programing

특정 필드에 대한 Jackson JSON 사용자 지정 일련화

procenter 2023. 1. 13. 20:13
반응형

특정 필드에 대한 Jackson JSON 사용자 지정 일련화

Jackson JSON 프로세서를 사용하여 커스텀 필드 레벨의 시리얼화를 실시하는 방법이 있습니까?예를 들어, 나는 수업을 하고 싶다.

public class Person {
    public String name;
    public int age;
    public int favoriteNumber;
}

다음 JSON으로 시리얼화 됩니다.

{ "name": "Joe", "age": 25, "favoriteNumber": "123" }

age=25는 숫자로 인코딩되고 favoriteNumber=123은 문자열로 인코딩됩니다.잭슨 마샬은 개봉 후int몇 개로 줄여서.이 경우 favorite Number를 문자열로 인코딩합니다.

다음과 같이 커스텀시리얼라이저를 실장할 수 있습니다.

public class Person {
    public String name;
    public int age;
    @JsonSerialize(using = IntToStringSerializer.class, as=String.class)
    public int favoriteNumber:
}


public class IntToStringSerializer extends JsonSerializer<Integer> {

    @Override
    public void serialize(Integer tmpInt, 
                          JsonGenerator jsonGenerator, 
                          SerializerProvider serializerProvider) 
                          throws IOException, JsonProcessingException {
        jsonGenerator.writeObject(tmpInt.toString());
    }
}

Java는 다음 위치에서 자동 박스를 처리합니다.int로.Integer널 위해서.

Jackson-databind(최소 2.1.3)는 특별한 기능을 제공합니다.ToStringSerializer(com.fasterxml.jackson.databind.ser.std.ToStringSerializer)

예를 들어:

public class Person {
    public String name;
    public int age;
    @JsonSerialize(using = ToStringSerializer.class)
    public int favoriteNumber:
}

를 추가합니다.@JsonProperty주석이 달린 getter를 반환한다.String,를 위해favoriteNumber필드:

public class Person {
    public String name;
    public int age;
    private int favoriteNumber;

    public Person(String name, int age, int favoriteNumber) {
        this.name = name;
        this.age = age;
        this.favoriteNumber = favoriteNumber;
    }

    @JsonProperty
    public String getFavoriteNumber() {
        return String.valueOf(favoriteNumber);
    }

    public static void main(String... args) throws Exception {
        Person p = new Person("Joe", 25, 123);
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writeValueAsString(p)); 
        // {"name":"Joe","age":25,"favoriteNumber":"123"}
    }
}

Jackson이 제공하는 정보@JsonFormat커스텀 시리얼라이저를 쓸 필요 없이 많은 커스터마이즈를 처리할 수 있습니다.

예를 들어, 요구는STRING숫자 유형이 있는 필드의 모양은 숫자 값을 문자열로 출력합니다.

public class Person {
    public String name;
    public int age;
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    public int favoriteNumber;
}

원하는 출력을 얻을 수 있습니다.

{"name":"Joe","age":25,"favoriteNumber":"123"}

주석을 사용하여 모형을 오염시키지 않고 사용자 지정 작업을 수행하려는 경우 혼합을 사용할 수 있습니다.

ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.setMixInAnnotation(Person.class, PersonMixin.class);
mapper.registerModule(simpleModule);

재지정 기간:

public abstract class PersonMixin {
    @JsonSerialize(using = PersonAgeSerializer.class)
    public String age;
}

연령에 따라 필요한 모든 것을 할 수 있습니다.

public class PersonAgeSerializer extends JsonSerializer<Integer> {
    @Override
    public void serialize(Integer integer, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString(String.valueOf(integer * 52) + " months");
    }
}

@JsonView의 도움을 받아 최소 기준을 충족하는 모델 클래스의 필드를 시리얼화할 수 있습니다.예를 들어 10개의 속성을 가진 코어 클래스는 1개이지만 클라이언트에 필요한 속성은 5개뿐입니다.

다음 클래스를 만드는 것만으로 뷰를 정의할 수 있습니다.

public class Views
{
    static class Android{};
    static class IOS{};
    static class Web{};
}

뷰가 있는 주석 모델 클래스:

public class Demo 
{
    public Demo() 
    {
    }

@JsonView(Views.IOS.class)
private String iosField;

@JsonView(Views.Android.class)
private String androidField;

@JsonView(Views.Web.class)
private String webField;

 // getters/setters
...
..
}

이제 봄부터 HttpMessageConverter 클래스를 다음과 같이 확장하여 커스텀 json 컨버터를 작성해야 합니다.

    public class CustomJacksonConverter implements HttpMessageConverter<Object> 
    {
    public CustomJacksonConverter() 
        {
            super();
        //this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.ClientView.class));
        this.delegate.getObjectMapper().configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true);
        this.delegate.getObjectMapper().setSerializationInclusion(Include.NON_NULL);

    }

    // a real message converter that will respond to methods and do the actual work
    private MappingJackson2HttpMessageConverter delegate = new MappingJackson2HttpMessageConverter();

    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return delegate.canRead(clazz, mediaType);
    }

    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return delegate.canWrite(clazz, mediaType);
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return delegate.getSupportedMediaTypes();
    }

    @Override
    public Object read(Class<? extends Object> clazz,
            HttpInputMessage inputMessage) throws IOException,
            HttpMessageNotReadableException {
        return delegate.read(clazz, inputMessage);
    }

    @Override
    public void write(Object obj, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException 
    {
        synchronized(this) 
        {
            String userAgent = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("userAgent");
            if ( userAgent != null ) 
            {
                switch (userAgent) 
                {
                case "IOS" :
                    this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.IOS.class));
                    break;
                case "Android" :
                    this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.Android.class));
                    break;
                case "Web" :
                    this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( Views.Web.class));
                    break;
                default:
                    this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( null ));
                    break;
                }
            }
            else
            {
                // reset to default view
                this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( null ));
            }
            delegate.write(obj, contentType, outputMessage);
        }
    }

}

이 커스텀 json 변환을 사용하기 위해서는 단순히 dispatcher-servlet.xml에 넣기만 하면 됩니다.

<mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean id="jsonConverter" class="com.mactores.org.CustomJacksonConverter" >
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

그래야 시리얼화할 필드를 결정할 수 있습니다.

믹스인으로 커스텀시리얼라이저를 인라인으로 작성할 수 있습니다.그런 다음 필드에 주석을 추가합니다.lang 필드에 " - something other " 필드를 추가하는 예는 다음과 같습니다.이것은 좀 해커가 됩니다.시리얼라이저가 저장소나 봄까지 주입된 것을 필요로 한다면, 이것은 문제가 될 것입니다.믹스인 대신 커스텀 디시리얼라이저/시리얼라이저를 사용하는 것이 좋습니다.

package com.test;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.test.Argument;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//Serialize only fields explicitly mentioned by this mixin.
@JsonAutoDetect(
    fieldVisibility = Visibility.NONE,
    setterVisibility = Visibility.NONE,
    getterVisibility = Visibility.NONE,
    isGetterVisibility = Visibility.NONE,
    creatorVisibility = Visibility.NONE
)
@JsonPropertyOrder({"lang", "name", "value"})
public abstract class V2ArgumentMixin {

  @JsonProperty("name")
  private String name;

  @JsonSerialize(using = LangCustomSerializer.class, as=String.class)
  @JsonProperty("lang")
  private String lang;

  @JsonProperty("value")
  private Object value;


  
  public static class LangCustomSerializer extends JsonSerializer<String> {

    @Override
    public void serialize(String value,
                          JsonGenerator jsonGenerator,
                          SerializerProvider serializerProvider)
        throws IOException, JsonProcessingException {
      jsonGenerator.writeObject(value.toString() + "  - something else");
    }
  }
}

언급URL : https://stackoverflow.com/questions/12046786/jackson-json-custom-serialization-for-certain-fields

반응형