3

J'ai une API REST qui retourne une réponse JSON comme:Deserializing attributs du même nom mais différents types dans Jackson?

{ 
    "channel" : "JHBHS" 
} 

et parfois il retourne:

{ 
    "channel": { 
        "id": 12321, 
        "name": "Some channel" 
       } 
} 

J'ai un POJO comme:

public class Event { 
    private String channel; 
    @JsonProperty("channel") 
    private Channel channelObj; 
} 

public class Channel { 
    private int id; 
    private String name; 
} 

Alors, est-il un moyen (autre que d'écrire votre propre désérialiseur personnalisé) en Jackson2 qui m'aidera à mapper channel dans JSON au type String lorsqu'il s'agit d'un type String et Channel lorsqu'il s'agit d'un objet JSON?

Ou en d'autres termes, y a-t-il un moyen dans Jackson qui mappe par type de la variable et pas seulement par name?

+0

Je trouve une autre question similaire http://stackoverflow.com/questions/21790727/providing-jackson-mapper-multiple- façons-de-désérialiser-le-même-objet –

Répondre

5

Je vous suggère d'utiliser JsonNode comme ceci:

class Event { 

    @JsonProperty("channel") 
    private JsonNode channelInternal; 

    private Channel channel; 

    private String channelStr; 

    /** 
    * Custom getter with channel parsing 
    * @return channel 
    */ 
    public Channel getChannel() { 
     if (channel == null && channelInternal != null) { 
      if (channelInternal.isObject()) { 
       int id = channelInternal.get("id").intValue(); 
       String name = channelInternal.get("name").asText(); 
       channel = new Channel(id, name); 
      } 
     } 
     return channel; 
    } 

    /** 
    * Custom getter with channel string parsing 
    * @return channel string 
    */ 
    public String getChannelStr() { 
     if (channelStr == null && channelInternal != null) { 
      if (channelInternal.isTextual()) { 
       channelStr = channelInternal.asText(); 
      } 
     } 
     return channelStr; 
    } 
} 

ou comme celui-ci:

class Event { 

    private Channel channel; 

    private String channelStr; 

    @JsonSetter("channel") 
    public void setChannelInternal(JsonNode channelInternal) { 
     if (channelInternal != null) { 
      if (channelInternal.isTextual()) { 
       channelStr = channelInternal.asText(); 
      } else if (channelInternal.isObject()) { 
       int id = channelInternal.get("id").intValue(); 
       String name = channelInternal.get("name").asText(); 
       channel = new Channel(id, name); 
      } 
     } 
    } 

    public Channel getChannel() { 
     return channel; 
    } 

    public String getChannelStr() { 
     return channelStr; 
    } 
} 

Mais je pense que l'utilisation désérialiseur personnalisée est plus fréquente.

est ici le code de test

public static void main(String[] args) throws IOException { 
    ObjectMapper objectMapper = new ObjectMapper(); 
    String source1 = "{\n" + 
      " \"channel\" : \"JHBHS\"\n" + 
      "}"; 
    String source2 = "{\n" + 
      " \"channel\": {\n" + 
      "     \"id\": 12321,\n" + 
      "     \"name\": \"Some channel\"\n" + 
      "    }\n" + 
      "}"; 

    //Test object parsing 
    Event result = objectMapper.readValue(source2, Event.class); 
    System.out.println(String.format("%s : %s", result.getChannel().getId(), result.getChannel().getName())); 

    //Test string parsing 
    result = objectMapper.readValue(source1, Event.class); 
    System.out.println(result.getChannelStr()); 
} 

Et la sortie:

12321 : Some channel 
JHBHS 
+0

Réponse très détaillée. Mais une méthode de setter personnalisée ne ferait-elle pas le travail ici comme dans ce http://stackoverflow.com/a/27068928/1385441? –

+0

@Ramswaroop, juste une réponse mise à jour avec la deuxième variante comme décrit dans http://stackoverflow.com/questions/21790727/providing-jackson-mapper-multiple-ways-to-deserialize-the-same-object/27068928#27068928 – Vadeg