JacksonJSON自定义序列化某些字段

o3imoua4  于 2023-11-19  发布在  其他
关注(0)|答案(8)|浏览(105)

有没有一种方法可以使用JacksonJSON处理器来进行自定义字段级别的序列化?例如,我想让类

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

字符串
序列化为以下JSON:

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


请注意,age=25被编码为number,而favoriteNumber=123被编码为string。开箱即用Jackson将int编组为一个数字。在本例中,我希望favoriteNumber被编码为字符串。

lb3vh1jj

lb3vh1jj1#

可以按如下方式实现自定义序列化程序:

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应该为您处理从intInteger的自动装箱。

odopli94

odopli942#

Jackson-databind(至少2.1.3)提供特殊的ToStringSerializercom.fasterxml.jackson.databind.ser.std.ToStringSerializer
范例:

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

字符串

2mbi3lxu

2mbi3lxu3#

如果你不想用注解污染你的模型,而想执行一些自定义操作,你可以使用mixin。

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

字符串
Package :

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

2q5ifsrm

2q5ifsrm4#

jackson-annotations提供了@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"}

c9x0cxw0

c9x0cxw05#

favoriteNumber字段添加一个@JsonProperty注解的getter,它返回一个String

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

字符串

7uhlpewt

7uhlpewt6#

在**@JsonView**的帮助下,我们可以决定要序列化的模型类的字段,这些字段满足最低标准(我们必须定义标准),比如我们可以有一个具有10个属性的核心类,但只有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
...
..
}


现在,我们必须编写自定义的json转换器,只需从spring扩展HttpMessageConverter类:

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

}


现在需要告诉spring使用这个自定义的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>


这就是你如何能够决定哪些字段得到序列化。

rekjcdws

rekjcdws7#

你可以在mixin中内联创建一个自定义的序列化器。然后用它注解一个字段。请参阅下面的例子,它将“- something else“附加到lang字段。这有点 * 黑客 * -如果你的序列化器需要像仓库或Spring注入的任何东西,这将是一个问题。可能最好使用自定义的序列化器/序列化器而不是mixin。

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

字符串

jdzmm42g

jdzmm42g8#

我最终将两个答案结合起来(并使用ToStringSerializer提供的实现)

POJO:

public class MyPojo{
  LocalDate date;

  @JsonSerialize(using = CurrencySerializer.class)
  double amount;
}

字符串
串行化器:

import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializerBase;

@JacksonStdImpl
public class CurrencySerializer extends ToStringSerializerBase
{
  public final static CurrencySerializer instance = new CurrencySerializer();

  public CurrencySerializer() { super(Object.class); }

  public CurrencySerializer(Class<?> handledType) {
    super(handledType);
  }

  @Override
  public final String valueToString(Object value) {
    return "$ " + value.toString();
  }
}

相关问题