2012-01-31 18 views
13

मेरे समस्या त्रुटि काफी सरल है: मैं निम्नलिखित सरल वर्ग है:जैक्सन अक्रमांकन निपटने

public class Foo { 
    private int id = -1; 
    public void setId(int _id){ this.id = _id; } 
    public int getId(){ return this.id; } 
} 

और मैं निम्नलिखित JSON कार्रवाई करने के लिए कोशिश कर रहा हूँ:

{ 
    "id": "blah" 
} 

जाहिर है, वहाँ एक समस्या यहाँ है ("blah" को int में पार्स नहीं किया जा सकता है)

पूर्व में, जैक्सन ने org.codehaus.jackson.map.JsonMappingException की तरह कुछ फेंकता है: स्ट्रिंग से java.lang.Integer का उदाहरण नहीं बना सकता मान 'blah': मान्य इंटीजर मान

मैं इसके साथ सहमत हूं, लेकिन मैं इस प्रकार की मैपिंग त्रुटियों को अनदेखा करने की अनुमति देने के लिए कहीं कुछ पंजीकरण करना चाहता हूं। मैंने एक DeserializationProblemHandler के साथ प्रयास किया (here देखें) लेकिन ऐसा लगता है कि यह केवल अज्ञात गुणों पर काम करता है और deserialization समस्याओं नहीं।

क्या आपको इस मुद्दे पर कोई संकेत है?

+0

क्यों आप इस त्रुटि को अनदेखा करना चाहते हैं? मैं प्रत्येक ग्राहक को '400' का एक HTTP कोड वापस कर दूंगा जो मुझे इस तरह संसाधन संसाधन प्रस्तुत करने की कोशिश करता है :) –

+1

मैं जैक्सन का उपयोग स्प्रिंग एमवीसी और बीन सत्यापन के साथ कर रहा हूं। समस्या यह है कि जैक्सन वसंत एमवीसी परत तक पहुंचने से पहले, deserialization समस्याओं के बारे में शिकायत कर रहा है .. इसलिए मैं अपने ग्राहक को लगातार तरीके से त्रुटियों को नहीं भेज सकता। –

+0

इसके अलावा मैं (एक के लिए) जैक्सन को अक्सर किसी ऑब्जेक्ट के एक पठनीय डंप को लॉग में करने के लिए उपयोग करता हूं। क्रमबद्धता मुद्दों को ध्यान में रखकर और आगे बढ़ना बहुत उपयोगी है –

उत्तर

9

मैं Tatu from Jackson ML के लिए धन्यवाद, मेरी समस्या को हल करने में सफल रहा।

मुझे जैक्सन में संभाले गए हर प्राचीन प्रकार के लिए कस्टम गैर अवरोधक deserializers का उपयोग करना पड़ा। कुछ इस कारखाने की तरह:

public class JacksonNonBlockingObjectMapperFactory { 

    /** 
    * Deserializer that won't block if value parsing doesn't match with target type 
    * @param <T> Handled type 
    */ 
    private static class NonBlockingDeserializer<T> extends JsonDeserializer<T> { 
     private StdDeserializer<T> delegate; 

     public NonBlockingDeserializer(StdDeserializer<T> _delegate){ 
      this.delegate = _delegate; 
     } 

     @Override 
     public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
      try { 
       return delegate.deserialize(jp, ctxt); 
      }catch (JsonMappingException e){ 
       // If a JSON Mapping occurs, simply returning null instead of blocking things 
       return null; 
      } 
     } 
    } 

    private List<StdDeserializer> jsonDeserializers = new ArrayList<StdDeserializer>(); 

    public ObjectMapper createObjectMapper(){ 
     ObjectMapper objectMapper = new ObjectMapper(); 

     SimpleModule customJacksonModule = new SimpleModule("customJacksonModule", new Version(1, 0, 0, null)); 
     for(StdDeserializer jsonDeserializer : jsonDeserializers){ 
      // Wrapping given deserializers with NonBlockingDeserializer 
      customJacksonModule.addDeserializer(jsonDeserializer.getValueClass(), new NonBlockingDeserializer(jsonDeserializer)); 
     } 

     objectMapper.registerModule(customJacksonModule); 
     return objectMapper; 
    } 

    public JacksonNonBlockingObjectMapperFactory setJsonDeserializers(List<StdDeserializer> _jsonDeserializers){ 
     this.jsonDeserializers = _jsonDeserializers; 
     return this; 
    } 
} 

तो इस तरह से है जैसे कि यह बुला (के रूप में केवल उन्हीं आप गैर अवरुद्ध होना चाहता हूँ deserializers पारित):

JacksonNonBlockingObjectMapperFactory factory = new JacksonNonBlockingObjectMapperFactory(); 
factory.setJsonDeserializers(Arrays.asList(new StdDeserializer[]{ 
    // StdDeserializer, here, comes from Jackson (org.codehaus.jackson.map.deser.StdDeserializer) 
    new StdDeserializer.ShortDeserializer(Short.class, null), 
    new StdDeserializer.IntegerDeserializer(Integer.class, null), 
    new StdDeserializer.CharacterDeserializer(Character.class, null), 
    new StdDeserializer.LongDeserializer(Long.class, null), 
    new StdDeserializer.FloatDeserializer(Float.class, null), 
    new StdDeserializer.DoubleDeserializer(Double.class, null), 
    new StdDeserializer.NumberDeserializer(), 
    new StdDeserializer.BigDecimalDeserializer(), 
    new StdDeserializer.BigIntegerDeserializer(), 
    new StdDeserializer.CalendarDeserializer() 
})); 
ObjectMapper om = factory.createObjectMapper(); 
6

आप अपने नियंत्रक समस्या संभाल जाने के लिए चाहते हो सकता है एक विधि है कि इस विशिष्ट अपवाद

@ExceptionHandler(HttpMessageNotReadableException.class) 
@ResponseBody 
public String handleHttpMessageNotReadableException(HttpMessageNotReadableException ex) 
{ 
    JsonMappingException jme = (JsonMappingException) ex.getCause(); 
    return jme.getPath().get(0).getFieldName() + " invalid"; 
} 
बेशक

संभालती है, लाइन

जोड़कर
JsonMappingException jme = (JsonMappingException) ex.getCause(); 

कुछ मामलों के लिए क्लास कास्ट अपवाद फेंक सकता है लेकिन मुझे अभी तक उनका सामना नहीं हुआ है।

+1

आप सही हैं, यह एक वैध समाधान हो सकता है। फिर भी, इसमें कुछ कमियां हैं: - आपको एक-एक करके त्रुटियों की सूचना दी जाएगी (आपको 3 बुरी तरह से स्वरूपित फ़ील्ड की पहचान करने के लिए 3 अनुरोधों की आवश्यकता होगी)। फ़ील्ड बुरी तरह से स्वरूपित होने पर शून्य मान डालकर मुझे 1 अनुरोध में त्रुटियों की विस्तृत सूची रखने के लिए फ़ील्ड पर \ @NotNull एनोटेशन डालने की अनुमति मिलती है - यह प्रत्येक फ़ील्ड पर केस-बाय-केस हैंडलिंग की अनुमति देता है।यदि कुछ फ़ील्ड बुरी तरह से स्वरूपित हैं * और * यह महत्वपूर्ण नहीं है, तो मैं इन फ़ील्ड पर \ @NotNull नहीं डालता => त्रुटि फ़िल्टर की जाएगी –

+0

हाँ, आप सही हैं, आपका दृष्टिकोण बेहतर है। मुझे दिलचस्पी है कि आप इसे एक आदिम मूल्य के लिए कैसे काम करते हैं, क्योंकि मैं चाहता हूं कि मेरा डोमेन मॉडल ** निजी इंटीजर आयु ** की बजाय ** निजी int आयु ** हो। मैंने ** नए StdDeserializer.IntegerDeserializer (int.class, 0), ** का उपयोग कर इसे हल करने में कामयाब रहे ** ** ** वापसी प्रतिनिधि के साथ deserialize विधि से ** वापसी शून्य ** की जगह ** वापसी प्रतिनिधि.getNullValue(); **। अगर आपको लगता है कि यह सही समाधान है, तो कृपया इसे शामिल करने के लिए अपना कोड अपडेट करें, अगर आपके पास कोई अन्य दृष्टिकोण है, तो कृपया साझा करें। –

+0

मुझे आश्चर्य है कि उस मामले में कच्चे प्रकारों पर विचार करना एक अच्छा विचार है। क्योंकि यह "अवैध" मान का प्रतिनिधित्व करने के लिए कुछ मानों का उपयोग करने के लिए अजीब लगता है (आपके मामले में, मान 0 लगता है)। मैं इसके बजाय एक कम इस्तेमाल किए गए मान का उपयोग करता हूं जैसे कि Integer.MAX_VALUE, लेकिन उस स्थिति में, मुझे यह व्यवहार थोड़ा मनमाना लगता है (यह एक व्यक्तिगत पीओवी है) –

0

एक सरल मैपर बनाएँ:

@Provider 
@Produces(MediaType.APPLICATION_JSON) 
public class JSONProcessingErroMapper implements ExceptionMapper<InvalidFormatException> { 

@Override 
public Response toResponse(InvalidFormatException ex) { 
    return Response.status(400) 
      .entity(new ClientError("[User friendly message]")) 
      .type(MediaType.APPLICATION_JSON) 
      .build(); 
} 

}