특정 필드에 대한 Jackson JSON 사용자 정의 직렬화


97

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은 숫자로 정렬 합니다. 이 경우 favoriteNumber를 문자열로 인코딩하고 싶습니다.


1
일부 사용자 에게 도움이 될 수있는 Jackson과 함께 Custom Serializer를 작성하는 방법에 대한 게시물을 썼습니다 .
Sam Berry

답변:


110

다음과 같이 사용자 지정 serializer를 구현할 수 있습니다.

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합니다.


4
Jackson-databind (최소 2.1.3)에는 이미 특수 ToStringSerializer가 포함되어 있습니다.
werupokz 2013

@KevinBowersox 제 역 직렬화 문제 를 도와 주 시겠습니까?
JJD 2014


이 작업을 수행하는 덜 끔찍한 방법이 있습니까? 처럼 Person implements ToJson?
jameshfisher

1
내 경우에는 as=String.class내가 사용한 유형 때문에 부품에서 실패했습니다 . @ kevin-bowersox, @GarethLatty가 말한 내용에 따라 귀하의 의견을 업데이트하는 것이 좋습니다.
Bert

56

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:
}

3
String을 int로 변환해야하는 반대의 경우는 어떻습니까? ToIntSerializer.class가 표시되지 않습니다.
jEremyB

당신은 쓸 필요가 있습니다 @jEremyB 사용자 정의 디시리얼라이저
드류 스티븐스

ToStringSerializer가 작동하지만 FloatSerializer가 다음 메시지를 표시합니다. 컨텐츠를 쓸 수 없습니다. java.lang.Integer를 java.lang.Float로 캐스트 할 수 없습니다.
Arnie Schwarzvogel

13

jackson-annotations는 @JsonFormat사용자 지정 serializer를 작성할 필요없이 많은 사용자 지정을 처리 할 수있는 기능 을 제공합니다 .

예를 들어 STRING숫자 유형이있는 필드 의 모양을 요청 하면 숫자 값이 문자열로 출력됩니다.

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

원하는 결과를 얻을 수 있습니다.

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

11

필드에 대해 @JsonProperty를 반환 하는 주석이 달린 getter를 추가 합니다.StringfavoriteNumber

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"}
    }
}

8

주석으로 모델을 오염시키고 싶지 않고 일부 사용자 지정 작업을 수행하려는 경우 믹스 인을 사용할 수 있습니다.

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");
    }
}

3

@JsonView 의 도움으로 최소 기준 (기준을 정의해야 함)을 충족하는 직렬화 할 모델 클래스의 필드를 결정할 수 있습니다. 뿐

다음 클래스를 생성하여 뷰를 정의하십시오.

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);
        }
    }

}

이제 dispatcher-servlet.xml에 이것을 넣어 봄 에이 커스텀 json 변환을 사용하도록 지시해야합니다.

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

이것이 직렬화 할 필드를 결정할 수있는 방법입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.