2016-07-31 29 views
1

Ich habe ein JSON-Format, das ich konvertieren in Java-Objektmodell mit Jackson API. Ich verwende Jaxsonxml 2.1.5 Parser. Die Antwort von json ist wie unten gezeigt.Injizieren JSON-Eigenschaft basierend auf Bedingung mit Jackson

{ 
    "response": { 
    "name": "states", 
    "total-records": "1", 
    "content": { 
    "data": { 
     "name": "OK", 
     "details": { 
     "id": "1234", 
     "name": "Oklahoma" 
     } 
    } 
    } 
} 
} 

Das JSON-Antwortformat hat sich geändert. Wenn die total-records1 ist, wird die details ein Objekt mit id und name Attribute sein. Aber wenn die total-records mehr als 1 ist dann die details wird wie unten ein Array von Objekt sein:

{ 
     "response": { 
     "name": "states", 
     "total-records": "4", 
     "content": { 
      "data": { 
      "name": "OK", 
      "details": [ 
       { 
       "id": "1234", 
       "name": "Oklahoma" 
       }, 
       { 
       "id": "1235", 
       "name": "Utah" 
       }, 
       { 
       "id": "1236", 
       "name": "Texas" 
       }, 
       { 
       "id": "1237", 
       "name": "Arizona" 
       } 
      ] 
      } 
     } 
     } 
    } 

Meine Java-Mapper-Klasse sieht aus wie unten mit früheren json Antwort.

@JsonIgnoreProperties(ignoreUnknown = true) 
    public class MapModelResponseList { 

     @JsonProperty("name") 
     private String name; 

     @JsonProperty("total-records") 
     private String records; 

     @JsonProperty(content") 
     private Model model; 

     public Model getModelResponse() { 
     return model; 
     } 

     public void setModel(Model model) { 
     this.model = model; 
     } 
    } 

-Client-Code

package com.test.deserializer; 

    import com.fasterxml.jackson.databind.DeserializationFeature; 
    import com.fasterxml.jackson.databind.ObjectMapper; 
    import com..schema.model.Person; 

    public class TestClient { 

     public static void main(String[] args) { 
      String response1="{\"id\":1234,\"name\":\"Pradeep\"}"; 
      TestClient client = new TestClient(); 
      try { 
       Person response = client.readJSONResponse(response1, Person.class); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 

     public <T extends Object> T readJSONResponse(String response, Class<T> type) { 
      ObjectMapper mapper = new ObjectMapper(); 
      mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); 
      T result = null; 
      try { 
       result = mapper.readValue(response, type); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      return (T) result; 
     } 

    } 

auf den total-records nun basierend, wie man Mapping entweder auf eine Model oder eine Liste von Model Objekt zu behandeln. Lass es mich wissen, bitte.

Antwort

1

Sie benötigen einen benutzerdefinierten Deserializer. Die Idee besteht darin, die Objektverarbeitung mit der Baumverarbeitung zu mischen und abzugleichen. Analysieren Sie Objekte wo möglich, verwenden Sie jedoch die Struktur (JSONNode) für die benutzerdefinierte Behandlung.

Auf der MapModelResponseList, entfernen Sie die records Eigenschaft und fügen Sie eine List<Data> Array, in dem Data für die id/name Paare nur ein Halter Klasse. Sie können die Gesamtdatensätze abrufen, indem Sie die Größe dieser Liste zurückgeben.

Im Deserializer, gehen Sie wie folgt vor:

public final class MapModelDeserializer extends BeanDeserializer { 
    public MapModelDeserializer(BeanDeserializerBase src) { 
    super(src); 
    } 

    protected void handleUnknownProperty(JsonParser jp, DeserializationContext ctxt, Object beanOrClass, String propName) throws IOException, JsonProcessingException { 
    if ("content".equals(propName)) { 
     MapModelResponseList response = (MapModelResponseList) beanOrClass; 

     // this probably needs null checks! 
     JsonNode details = (JsonNode) jp.getCodec().readTree(jp).get("data").get("details"); 

     // read as array and create a Data object for each element 
     if (details.isArray()) { 
     List<Data> data = new java.util.ArrayList<Data>(details.size()); 

     for (int i = 0; i < details.size(); i++) { 
      Data d = jp.getCodec().treeToValue(details.get(i), Data.class); 
      data.add(d); 
     } 

     response.setData(data); 
     } 
     // read a single object 
     else { 
     Data d = jp.getCodec().treeToValue(details, Data.class); 
     response.setData(java.util.Collections.singletonList(d)); 
     } 

    super.handleUnknownProperty(jp, ctxt, beanOrClass, propName); 
} 

Beachten Sie, dass Sie nicht deserialize() implementieren - die Standardimplementierung verwendet wird, um die MapModelResponseList als normal zu erstellen. handleUknownProperty() wird verwendet, um mit dem content Element umzugehen. Andere Daten, die Sie nicht interessieren, werden wegen @JsonIgnoreProperties(ignoreUnknown = true) im Superanruf ignoriert.

+0

Ich bekomme einen Fehler mit der Angabe 'com.fasterxml.jackson.databind.JsonMappingException: Klasse com.test.deserializer.CustomDeserializer hat keine Standard (kein arg) -Konstruktor' bei der Verwendung der oben genannten Ansatz. – zilcuanu

+0

Dem veröffentlichten Code wurde ein Konstruktor hinzugefügt. – AngerClown

+0

Ich habe versucht mit Ihrem Ansatz. Aber immer noch kein Glück. Lassen Sie mich wissen, ob ich meinen Client-Code richtig eingegeben habe. Ich bekomme immer noch die gleiche Ausnahme 'com.fasterxml.jackson.databind.JsonMappingException: Class com.test.deserializer.CustomDeserializer hat keinen Standard (kein Arg) -Konstruktor' – zilcuanu