source

잭슨 동적 속성 이름

lovecheck 2023. 2. 13. 20:43
반응형

잭슨 동적 속성 이름

필드 유형에 따라 필드 중 하나의 이름이 다르게 지정되도록 개체를 직렬화하고 싶습니다.예를 들어 다음과 같습니다.

public class Response {
    private Status status;
    private String error;
    private Object data;
        [ getters, setters ]
    }

여기, 나는 그 필드를 원한다.data연재되다data.getClass.getName()항상 라는 분야를 가지고 있는 대신data상황에 따라 다른 타입이 포함되어 있습니다.

잭슨을 이용해서 어떻게 그런 묘기를 부릴 수 있을까요?

이 솔루션을 사용하여 보다 심플한 솔루션을 사용하였습니다.@JsonAnyGetter주석은 마법처럼 작동했어요

import java.util.Collections;
import java.util.Map;

public class Response {
    private Status status;
    private String error;

    @JsonIgnore
    private Object data;

    [getters, setters]

    @JsonAnyGetter
    public Map<String, Object> any() {
        //add the custom name here
        //use full HashMap if you need more than one property
        return Collections.singletonMap(data.getClass().getName(), data);
    }
}

래퍼도 커스텀시리얼라이저도 필요 없습니다.

커스텀 사용.

public class Response {
  private String status;
  private String error;

  @JsonProperty("p")
  @JsonSerialize(using = CustomSerializer.class)
  private Object data;

  // ...
}

public class CustomSerializer extends JsonSerializer<Object> {
  public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
    jgen.writeStartObject();
    jgen.writeObjectField(value.getClass().getName(), value);
    jgen.writeEndObject();
  }
}

그런 다음 다음 다음 두 개체를 직렬화한다고 가정합니다.

public static void main(String... args) throws Exception {
  ObjectMapper mapper = new ObjectMapper();
  Response r1 = new Response("Error", "Some error", 20);
  System.out.println(mapper.writeValueAsString(r1));
  Response r2 = new Response("Error", "Some error", "some string");
  System.out.println(mapper.writeValueAsString(r2));
}

첫 번째 인쇄물은 다음과 같습니다.

{"status":"Error","error":"Some error","p":{"java.lang.Integer":20}}

그리고 두 번째는:

{"status":"Error","error":"Some error","p":{"java.lang.String":"some string"}}

나는 그 이름을 사용했다.p그것은 단지 하나의 역할로서 기능할 것이기 때문에 포장된 오브젝트에 대해서p레이스 홀더삭제할 경우 전체 클래스에 대해 커스텀시리얼라이저를 작성해야 합니다(예:JsonSerializer<Response>.

나만의 해결책.

@Data
@EqualsAndHashCode
@ToString
@JsonSerialize(using = ElementsListBean.CustomSerializer.class)
public class ElementsListBean<T> {

    public ElementsListBean()
    {
    }

    public ElementsListBean(final String fieldName, final List<T> elements)
    {
        this.fieldName = fieldName;
        this.elements = elements;
    }

    private String fieldName;

    private List<T> elements;

    public int length()
    {
        return (this.elements != null) ? this.elements.size() : 0;
    }

    private static class CustomSerializer extends JsonSerializer<Object> {
        public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
                JsonProcessingException
        {
            if (value instanceof ElementsListBean) {
                final ElementsListBean<?> o = (ElementsListBean<?>) value;
                jgen.writeStartObject();
                jgen.writeArrayFieldStart(o.getFieldName());
                for (Object e : o.getElements()) {
                    jgen.writeObject(e);
                }
                jgen.writeEndArray();
                jgen.writeNumberField("length", o.length());
                jgen.writeEndObject();
            }
        }
    }
}

주석을 사용할 수 있습니다.JsonTypeInfo잭슨에게 정확하게 알려주고 커스텀 시리얼라이저를 쓸 필요가 없습니다.이 정보를 포함할 수 있는 방법은 다양합니다만, 구체적인 질문에는As.WRAPPER_OBJECT그리고.Id.CLASS. 예:

public static class Response {
    private Status status;
    private String error;
    @JsonTypeInfo(include = As.WRAPPER_OBJECT, use = Id.CLASS)
    private Object data;
}

그러나 String이나 Integer와 같은 원시 유형에서는 작동하지 않습니다.이 정보는 원래 JSON으로 표시되며 Jackson은 이 정보를 처리하는 방법을 알고 있기 때문에 원본을 위해 필요하지 않습니다.주석을 사용하면 필요할 때 무료로 역직렬화를 사용할 수 있습니다.다음은 예를 제시하겠습니다.

public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    Response r1 = new Response("Status", "An error", "some data");
    Response r2 = new Response("Status", "An error", 10);
    Response r3 = new Response("Status", "An error", new MyClass("data"));
    System.out.println(mapper.writeValueAsString(r1));
    System.out.println(mapper.writeValueAsString(r2));
    System.out.println(mapper.writeValueAsString(r3));
}

@JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class MyClass{
    private String data;
    public MyClass(String data) {
        this.data = data;
    }
}

그 결과:

{"status":"Status","error":"An error","data":"some data"}
{"status":"Status","error":"An error","data":10}
{"status":"Status","error":"An error","data":{"some.package.MyClass":{"data":"data"}}}

@tlogbon 응답을 바탕으로 특정/동적인 파일명으로 아이템 목록을 정리하는 솔루션을 소개합니다.

public class ListResource<T> {

    @JsonIgnore
    private List<T> items;

    @JsonIgnore
    private String fieldName;

    public ListResource(String fieldName, List<T> items) {
        this.items = items;
        this.fieldName = fieldName;
    }

    @JsonAnyGetter
    public Map<String, List<T>> getMap() {
        return Collections.singletonMap(fieldName, items);
    }

언급URL : https://stackoverflow.com/questions/12134231/jackson-dynamic-property-names

반응형