2017-04-26 159 views
1

RESTTemplate APIを使用してJSON形式のPOJOクラスを作成しようとしていますが、Mapを使用して必要なJSON形式を解析できませんでした。 json形式より下になるにはどのようなプロパティタイプを使用しますか?私に助言してください。Jackson JSON動的キー値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; 

生成されたJSON形式:

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

予想されるフォーマット:

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

はここhttp://stackoverflow.com/questions/18002132/deserializing-into-a-hashmap-of-custom-objects-with他の回答を見てください-jacksonとここにhttp://stackoverflow.com/questions/12155800/how-to-convert-hashmap-to-json-object-in-java –

答えて

2

あなたはとにかくシリアライザを記述する必要が、これは一般的なシリアライザある地図このフォーム"HOBBIES[0]に提出されたすべてをシリアライズします。

@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

あなたは豆をたくさん持っている場合は、このシリアライザを書くことができ、シリアライザ注釈は迷惑です追加し、この機能を必要とするので、修飾子。

@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。働いてくれてありがとう。どのようにプライベートマップ hobbies = null; CustomJsonSerializerクラスにリンクしています。特定のフィールド趣味ではなく、クラスレベルでJsonSerializeが必要な理由 – DEADEND

+0

私は、その特定の趣味のためにserializeする必要がありますそのbeanの他のマップではない。 – DEADEND

+1

フィールドのシリアライザは、フィールド値のシリアル化を制御することしかできません。 '{..." HOBBIES ":<これだけを制御できます>}'、フィールドをマークする簡単な注釈を追加することができます。 – wener

関連する問題