Джексон @JsonValue конфликтует с @JsonTypeInfo; Как заставить их работать вместе

#java #json #serialization #jackson #jackson2

Вопрос:

Я использую Jackson для сериализации a POJO . Этот POJO класс состоит из некоторых полей и a Map<String,Object> others . Я использую во Custom Serializer время написания JSON для этого MAP поля. Я хочу избежать получения Map field name "others"´ in my . Hence, I am using the карты JSON on the @ field but using the JsonValue@JsonValue is conflicting with @JsonTypeInfo’. Мне нужны обе аннотации в моем классе, как я могу этого достичь?

На данный момент я получаю JSON следующее: (С обоими @JsonValue и @JsonTypeInfo )

 [ "Customer", {
  "name" : "Rise Against",
  "google:sub" : "MyValue-1",
  "age" : "2000"
} ]

 

Я хотел бы получить JSON следующее с обоими @JsonValue и @JsonTypeInfo : (Как вы можете видеть others , ключ зафиксирован, но его значения добавляются непосредственно в JSON)

 {
  "isA" : "Customer",
  "name" : "Batman",
  "google:sub" : "MyValue-1",
  "age" : "2008"
}

 

Я могу получить вывод, но мне нужно удалить аннотацию из моего класса:

 @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
 

Но если я удалю это, то я не получу isA свойство в своем JSON. Я хочу знать, как заставить Jackson Json Serializer работать и с @JsonTypeInfo и @JsonValue .

Вывод без @JsonTypeInfo , но с @JsonValue :

 {
  "name" : "Rise Against",
  "google:sub" : "MyValue-1",
  "age" : "2000"
}
 

Вывод без @JsonValue , но с @JsonTypeInfo

 {
  "isA" : "Customer",
  "name" : "",
  "age" : "",
  "others" : {
    "name" : "Rise Against",
    "google:sub" : "MyValue-1",
    "age" : "2000"
  }
}
 

Following is my Customer class Pojo:

 @XmlRootElement(name = "Customer")
@XmlType(name = "Customer", propOrder = {"name", "age", "others"})
@XmlAccessorType(XmlAccessType.FIELD)
@NoArgsConstructor
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
@AllArgsConstructor
@JsonIgnoreType
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.PROPERTY, visible = true, property = "isA")
public class Customer {

  @XmlElement(name = "name", required = true)
  private String name;

  @XmlElement(name = "age", required = true)
  private String age;

  @JsonSerialize(using = CustomExtensionsSerializer.class)
  @XmlJavaTypeAdapter(TestAdapter.class)
  @XmlPath(".")
  @JsonValue
  private Map<String, Object> others = new HashMap<>();

  @JsonAnySetter
  public void setOthers(String key, Object value) {
    others.put(key, value);
  }

  public Map<String, Object> getOthers() {
    return others;
  }
}
 

Ниже приведен мой » Пользовательский сериализатор:

 public class CustomExtensionsSerializer extends JsonSerializer<Map<String, Object>> {

  private static final ObjectMapper mapper = new ObjectMapper();

  @Override
  public void serialize(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
    gen.writeStartObject();
    recusiveSerializer(value, gen, serializers);
    gen.writeEndObject();
  }

  public void recusiveSerializer(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
    for (Map.Entry<String, Object> extension : value.entrySet()) {
      if (extension.getValue() instanceof Map) {
        //If instance is MAP then call the recursive method
        recusiveSerializer((Map) extension.getValue(), gen, serializers);
      } else if (extension.getValue() instanceof String) {
        //If instance is String directly add it to the JSON
        gen.writeStringField(extension.getKey(), (String) extension.getValue());
      } else if (extension.getValue() instanceof ArrayList) {
        //If instance if ArrayList then loop over it and add it to the JSON after calling recursive method
        gen.writeFieldName(extension.getKey());
        gen.writeStartObject();
        for (Object dupItems : (ArrayList<String>) extension.getValue()) {
          if (dupItems instanceof Map) {
            recusiveSerializer((Map) dupItems, gen, serializers);
          } else {
            gen.writeStringField(extension.getKey(), (String) extension.getValue());
          }
        }
        gen.writeEndObject();
      }
    }
  }
}
 

Ответ №1:

Попробуйте установить @JsonTypeInfo.include в JsonTypeInfo.As.EXISTING_PROPERTY

 @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, visible = true, property = "isA")
 

Комментарии:

1. Привет, спасибо, что нашли время и ответили. Я действительно пробовал это. Добавление этого приведет к созданию того же JSON, что и в первом JSON, указанном в вопросе. Он добавляет в Array качестве оболочки в мой JSON, а также значения полностью перепутались примерно так: [ "Customer", { "google:main" : { "google:sub" : "MyValue-1" }, "name" : "BATMAN", "age" : "2008" } ]