2017-04-26 3 views
1

Ich versuche, POJO-Klasse für unter JSON-Format mit RESTTemplate API zu schreiben, aber ich fehlgeschlagen Parsen erforderlichen Json-Format mit Map. Welchen Eigenschaftstyp sollte ich verwenden, um unter das json-Format zu gelangen? Bitte berate mich.Jackson JSON Dynamischer Schlüssel Wert Bindung an Java Bean

@JsonProperty("ID") 
private String id = null; 
@JsonProperty("NAME") 
private String name = null; 
@JsonProperty("AGE") 
private int age = 0; 
@JsonProperty("HOBBIES") 
private Map<String, String> hobbies = null; 

generierte JSON Format:

{"NAME":"Shas","ID":"1","AGE":29,"HOBBIES":{"HOBBIES[1]":"Chess","HOBBIES[0]":"Cricket"}} 

Erwartete Format:

{"NAME":"Shas","ID":"1","AGE":29,"HOBBIES[0]":"Cricket", "HOBBIES[1]":"Chess"} 
+1

Werfen Sie einen Blick auf andere Antworten hier http://stackoverflow.com/questions/18002132/deserializing-into-a-hashmap-of-custom-objects-with -jackson und hier http://stackoverflow.com/questions/12155800/how-to-convert-hashmap-to-json-object-in-java –

Antwort

2

Sie müssen auf jeden Fall einen Serializer schreiben, dies ist ein generischer Serializer all Kartenansicht Formular "HOBBIES[0] eingereicht werden serialisiert .

@Test 
public void test() throws JsonProcessingException { 
    ObjectMapper mapper = new ObjectMapper(); 
    String json = mapper.writeValueAsString(new POJO().setHobbies(ImmutableMap.of("0", "Cricket", "1", "Chess"))); 
    System.out.println(json); 
} 

@Target({ElementType.FIELD}) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface MapAsField { 

} 

@Data 
@Accessors(chain = true) 
@JsonSerialize(using = CustomJsonSerializer.class) 
public static class POJO { 

    @JsonProperty("ID") 
    private String id = "abc"; 
    @JsonProperty("NAME") 
    private String name = "wener"; 
    @JsonProperty("AGE") 
    private int age = 0; 
    @JsonProperty("HOBBIES") 
    @MapAsField 
    private Map<String, String> hobbies = null; 
    private Map<String, String> fav = ImmutableMap.of("A", "Yes", "B", "No"); 
} 

static class CustomJsonSerializer extends JsonSerializer<Object> { 

    @Override 
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException { 
     gen.writeStartObject(); 
     JavaType javaType = provider.constructType(Object.class); 
     BeanDescription beanDesc = provider.getConfig().introspect(javaType); 
     ListIterator<BeanPropertyDefinition> itor = beanDesc.findProperties() 
      .listIterator(); 

     // Remove map field 
     ArrayList<BeanPropertyDefinition> list = new ArrayList<>(); 
     while (itor.hasNext()) { 
      BeanPropertyDefinition n = itor.next(); 

      if (n.getField().getAnnotated().getAnnotation(MapAsField.class) != null && // Only handle this 
       Map.class.isAssignableFrom(n.getField().getRawType())) { 
       itor.remove(); 
       list.add(n); 
      } 
     } 

     JsonSerializer<Object> serializer = BeanSerializerFactory 
      .instance 
      .findBeanSerializer(provider, javaType, beanDesc); 
     serializer.unwrappingSerializer(null).serialize(value, gen, provider); 

     // Handle all map field 
     for (BeanPropertyDefinition d : list) { 
      try { 
       Field field = d.getField().getAnnotated(); 
       field.setAccessible(true); 
       Map<?, ?> v = (Map<?, ?>) field.get(value); 
       if (v != null && !v.isEmpty()) { 
        for (Map.Entry o : v.entrySet()) { 
         gen.writeStringField(
          String.format("%s[%s]", d.getName(), o.getKey().toString()), 
          o.getValue().toString() 
         ); 
        } 
       } 
      } catch (IllegalAccessException e) { 
       throw new RuntimeException(e); 
      } 
     } 

     gen.writeEndObject(); 
    } 
} 

OUTPUT

{"fav":{"A":"Yes","B":"No"},"ID":"abc","NAME":"wener","AGE":0,"HOBBIES[0]":"Cricket","HOBBIES[1]":"Chess"} 

UPDATE

Wenn Sie eine Menge von Bohnen benötigen diese Funktion haben, fügen Sie ein Serializer Anmerkung ärgerlich ist, so können Sie diese Serializer schreiben als ein Modifikator

@Test 
public void test2() throws JsonProcessingException { 
    ObjectMapper mapper = new ObjectMapper(); 
    mapper.registerModule(new SimpleModule().setSerializerModifier(new MapAsFieldModifier())); 
    System.out.println(mapper.writeValueAsString(new POJO2())); 
} 
@Data 
@Accessors(chain = true) 
public static class POJO2 { 

    @JsonProperty("ID") 
    private String id = "abc"; 
    @JsonProperty("NAME") 
    private String name = "wener"; 
    @JsonProperty("AGE") 
    private int age = 0; 
    @JsonProperty("HOBBIES") 
    @MapAsField 
    private Map<String, String> hobbies = ImmutableMap.of("0", "Cricket", "1", "Chess"); 
    private Map<String, String> fav = ImmutableMap.of("A", "Yes", "B", "No"); 
} 

public class MapAsFieldModifier extends BeanSerializerModifier { 

    @Override 
    public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, 
     JsonSerializer<?> serializer) { 
     ListIterator<BeanPropertyDefinition> itor = beanDesc.findProperties().listIterator(); 
     // Remove map field 
     ArrayList<BeanPropertyDefinition> list = new ArrayList<>(); 
     while (itor.hasNext()) { 
      BeanPropertyDefinition n = itor.next(); 

      if (n.getField().getAnnotated().getAnnotation(MapAsField.class) != null && // Only handle this 
       Map.class.isAssignableFrom(n.getField().getRawType())) { 
       itor.remove(); 
       list.add(n); 
      } 
     } 

     // We should handle this 
     if (!list.isEmpty()) { 

      return new JsonSerializer<Object>() { 
       @Override 
       public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) 
        throws IOException, JsonProcessingException { 
        gen.writeStartObject(); 

        JavaType javaType = serializers.constructType(value.getClass()); 
        JsonSerializer<Object> ser = BeanSerializerFactory 
         .instance 
         .findBeanSerializer(serializers, javaType, beanDesc); 

        ser.unwrappingSerializer(null).serialize(value, gen, serializers); 

        // Handle all map field 
        for (BeanPropertyDefinition d : list) { 
         try { 
          Field field = d.getField().getAnnotated(); 
          field.setAccessible(true); 
          Map<?, ?> v = (Map<?, ?>) field.get(value); 
          if (v != null && !v.isEmpty()) { 
           for (Map.Entry o : v.entrySet()) { 
            gen.writeStringField(
             String.format("%s[%s]", d.getName(), o.getKey().toString()), 
             o.getValue().toString() 
            ); 
           } 
          } 
         } catch (IllegalAccessException e) { 
          throw new RuntimeException(e); 
         } 
        } 

        gen.writeEndObject(); 
       } 
      }; 
     } 

     return serializer; 
    } 
} 

OUTPUT

{"fav":{"A":"Yes","B":"No"},"ID":"abc","NAME":"wener","AGE":0,"HOBBIES[0]":"Cricket","HOBBIES[1]":"Chess"} 
+0

@ wener. Danke, dass es funktioniert. Wie private Map hobbies = null; verweist auf die CustomJsonSerializer-Klasse. Warum brauchen wir JsonSerialize auf Klassenebene statt bestimmter Feldhobbies? – DEADEND

+0

Ich muss für diese bestimmten Hobbys Karte nicht andere Karte in dieser Bohne serialisieren. – DEADEND

+1

Der Serializer für ein Feld kann nur die Feldwert-Serialisierung steuern, '{..." HOBBIES ": }', Sie können eine einfache Anmerkung hinzufügen, um das Feld zu markieren, der Serializer kann dies erkennen. – wener

Verwandte Themen