2017-02-03 7 views
5

में उपलब्ध जानकारी के आधार पर कितना deserialize मैं Product इंटरफ़ेस के कई अलग-अलग कार्यान्वयन deserialize करने के लिए जैक्सन का उपयोग कर रहा हूँ। इन उत्पाद कार्यान्वयन में अलग-अलग फ़ील्ड हैं, लेकिन सभी में InsuredAmount फ़ील्ड है। यह InsuredAmount वर्ग का मूल्य फ़ील्ड और IAType फ़ील्ड है। IAType कार्यान्वयन के रूप में विभिन्न enums के साथ एक मार्कर इंटरफ़ेस है।अभिभावक वर्ग

अब यहां समस्या है: IAType इंटरफ़ेस के enum कार्यान्वयन Product इंटरफ़ेस के एक निश्चित कार्यान्वयन से मेल खाते हैं। मैं सामान्य कार्यान्वयन कैसे कर सकता हूं और जैक्सन को आपके IAType के सही कार्यान्वयन को खोजने के लिए कह सकता हूं? क्या मुझे उत्पाद कार्यान्वयन की पहचान करने वाले उत्पाद और आईएटीपी इंटरफेस पर एक सामान्य पैरामीटर का उपयोग करना चाहिए? क्या मुझे उत्पाद कार्यान्वयन की पहचान करने वाले वर्गों पर Productable कार्यात्मक इंटरफ़ेस का उपयोग करना चाहिए? मैं जैक्सन को उस कार्यान्वयन का उपयोग करने के लिए कैसे कह सकता हूं?

मुझे आशा है कि नीचे दिया गया कोड समस्या को स्पष्ट करता है, मैंने Productable इंटरफ़ेस को कार्यान्वित करना चुना है, लेकिन इस समस्या को संभालने के लिए एक बेट्टेयर संरचना का भी स्वागत किया जाएगा।

@JsonPropertyOrder({"type", "someInfo"}) 
public class InsuredAmount implements Productable, Serializable { 

    private static final long serialVersionUID = 1L; 

    private IAType type; 

    private String someInfo; 

    public InsuredAmount() { 
    } 

    public InsuredAmount(IAType typeA, String someInfo) { 
     this.type = typeA; 
     this.someInfo = someInfo; 
    } 


    /* This should be on the product level, but if I can solve this problem, 
    the next level will just be more of the same. 
    */ 
    @JsonIgnore 
    @Override 
    public Product getProduct() { 
     return Product.PROD_A; 
    } 

    // Getters, setters, equals, etc. omitted. 
} 

-

public interface Productable { 

    public Product getProduct(); 

} 

-

public enum Product { 

    PROD_A, PROD_B; 

} 

-

@JsonDeserialize(using = IATypeDeserializer.class) 
public interface IAType extends Productable { 

} 

-

public enum IATypeA implements IAType { 

    FOO, BAR; 

    @Override 
    public Product getProduct() { 
     return Product.PROD_A; 
    } 

} 

-

public class IATypeDeserializer extends StdDeserializer<IAType> { 

    private static final long serialVersionUID = 1L; 

    public IATypeDeserializer() { 
     this(null); 
    } 

    public IATypeDeserializer(Class<?> vc) { 
     super(vc); 
    } 

    @Override 
    public IAType deserialize(JsonParser parser, DeserializationContext context) 
      throws IOException, JsonProcessingException { 
     JsonNode node = parser.getCodec().readTree(parser); 
     /* How to find out that the class calling the deserialization is InsuredAmountA, which 
     has getProduct() method that returns PROD_A, and matches the IATypeA that also returns 
     PROD_A, so I know to deserialize IATypeA, instead of other implementations of the IAType 
     interface? 
     */ 
     return IATypeA.valueOf(node.asText()); 
    } 

} 

-

public class InsuredAmountTest { 

    private final ObjectMapper mapper = new ObjectMapper(); 

    @Test 
    public void test01() throws IOException { 
     InsuredAmount iaA = new InsuredAmount(IATypeA.FOO, "test it"); 
     String json = mapper.writeValueAsString(iaA); 
     assertThat(json, is("{\"type\":\"FOO\",\"someInfo\":\"test it\"}")); 
     InsuredAmount iaA2 = mapper.readValue(json, InsuredAmount.class); 
     IAType type = iaA2.getType(); 
     assertThat(type, is(IATypeA.FOO)); 
     assertThat(type.getProduct(), is(Product.PROD_A)); 
     assertThat(iaA, is(iaA2)); 
    } 

    @Test 
    public void test02() throws IOException { 
     InsuredAmount iaA = new InsuredAmount(IATypeA.BAR, "test it"); 
     String json = mapper.writeValueAsString(iaA); 
     assertThat(json, is("{\"type\":\"BAR\",\"someInfo\":\"test it\"}")); 
     InsuredAmount iaA2 = mapper.readValue(json, InsuredAmount.class); 
     assertThat(iaA, is(iaA2)); 
    } 

} 

उत्तर

2

मैं एक विशेष निर्माता पर JsonCreator एनोटेशन का उपयोग करने के साथ समाप्त हुआ।

@JsonCreator 
    public InsuredAmountA(
      @JsonProperty("type") String type, 
      @JsonProperty("someInfo") String someInfo) throws IOException { 
     switch (getProduct()) { 
      case PROD_A: 
       try { 
        this.type = IATypeA.valueOf(type); 
        break; 
       } catch (IllegalArgumentException ex) { 
        // Throw IOException in the default. 
       } 
//   case PROD_B: 
//    this.type = (IATypeB) typeA; 
//    break; 
      default: 
       throw new IOException(String.format("Cannot parse value %s as type.", type)); 
     } 
     this.someInfo = someInfo; 
    } 
0

आप बहुरूपी deserialisation की दिशा पर गौर कर सकते हैं:

http://wiki.fasterxml.com/JacksonPolymorphicDeserialization

unsing कस्टम प्रकार समाधानकर्ता

+0

हाँ, मैंने पहले ही उसमें देखा है। यह पता नहीं लगा सका कि मेरे मामले में इसका उपयोग कैसे किया जाए। –

+0

@JsonTypeResolver आपको आवश्यक एनोटेशन लगता है, मैं स्रोतों (जैक्सन कोड का एक अच्छा टुकड़ा है और समझने में आसान है) देखता हूं और तातो सलोरांटा को परेशान करता है, वह लेखक है - वह आमतौर पर ज़िम्मेदार है और पश्चिमी तट में कहीं रहता है –

3

जैक्सन कम से कम उपद्रव के साथ enums की क्रमबद्धता संभालती है, तो तुम सब करने की जरूरत है @JsonTypeInfo साथ IAType क्षेत्र व्याख्या है:

@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS) 
private IAType type; 

एक परीक्षण तब: उत्पादन में

public static void main(String[] args) throws IOException { 
    ObjectMapper mapper = new ObjectMapper(); 
    String json = mapper.writeValueAsString(new InsuredAmount(IATypeA.FOO, "info")); 
    System.out.println(json); 
    InsuredAmount ia = mapper.readValue(json, InsuredAmount.class); 
    System.out.println("Type is: " + ia.getType()); 
} 

परिणाम:

{"type":[".IATypeA","FOO"],"someInfo":"info"} 
Type is: FOO 

अधिक कॉम्पैक्ट प्रतिनिधित्व प्राप्त करने के लिए आपको कस्टम क्रमिकरण का उपयोग करना होगा। यह मानते हुए कि आपके एनम नेमस्पेस में कोई ओवरलैप नहीं है, आप टाइप फ़ील्ड को एनम नाम के रूप में क्रमबद्ध कर सकते हैं।

deserializer पता करने के लिए जो प्रकार निर्माण के लिए उपलब्ध हैं, या निम्न उदाहरण में, बस संदर्भ हार्ड-कोड की आवश्यकता होगी या तो वर्ग पथ खोज से,:

public class IATest { 

    public static class IATypeSerializer extends JsonSerializer<IAType> { 
     @Override 
     public void serialize(IAType value, JsonGenerator gen, SerializerProvider serializers) throws IOException { 
      gen.writeString(((Enum) value).name()); 
     } 
    } 

    public static class IATypeDeserializer extends JsonDeserializer<IAType> { 
     @Override 
     public IAType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { 
      String value = p.readValueAs(String.class); 
      try { 
       return IATypeA.valueOf(value); 
      } catch (IllegalArgumentException e) { 
       // fall through 
      } 
      try { 
       return IATypeB.valueOf(value); 
      } catch (IllegalArgumentException e) { 
       // fall through 
      } 
      throw new JsonMappingException(p, "Unknown type '" + value + "'"); 
     } 
    } 

    public static void main(String[] args) throws IOException { 
     ObjectMapper mapper = new ObjectMapper(); 

     // Register a module to handle serialization of IAType implementations 
     SimpleModule module = new SimpleModule(); 
     module.addSerializer(IAType.class, new IATypeSerializer()); 
     module.addDeserializer(IAType.class, new IATypeDeserializer()); 
     mapper.registerModule(module); 

     // Test 
     String json = mapper.writeValueAsString(new InsuredAmount(IATypeA.FOO, "info")); 
     System.out.println(json); 
     InsuredAmount ia = mapper.readValue(json, InsuredAmount.class); 
     System.out.println("Type is: " + ia.getType()); 
    } 

} 

कौन सा आउटपुट:

{"type":"FOO","someInfo":"info"} 
Type is: FOO 
+0

मुद्दा यह है कि मैं जिस वर्ग का उपयोग कर रहा हूं वह बीमाकृत है जिसमें से IAType एक फ़ील्ड है। इसलिए मुझे लगता है कि धारावाहिक वर्ग के लिए "आईएटीपीए" अतिरिक्त मेरे मामले में आवश्यक नहीं है। लेकिन मैं जैक्सन को यह कैसे बता सकता हूं? –

+0

तो आपका लक्ष्य एक स्वच्छ जेसन प्रतिनिधित्व है? क्या आप अपने प्रश्न में कुछ स्वीकार्य उदाहरण जोड़ सकते हैं? – teppic

+0

उदाहरण दिए गए टेस्टकेस में हैं: 'assertThat (json, है ("{\" प्रकार \ ": \" FOO \ ", \" someInfo \ ": \" इसे परीक्षण करें \ "}")। आप कुछ विशेष तालाश कर रहे हैं? –

संबंधित मुद्दे