[英]Jackson JSON custom serialization for certain fields
Is there a way using Jackson JSON Processor to do custom field level serialization?有没有办法使用 Jackson JSON Processor 进行自定义字段级序列化? For example, I'd like to have the class
例如,我想上课
public class Person {
public String name;
public int age;
public int favoriteNumber;
}
serialized to the follow JSON:序列化为以下 JSON:
{ "name": "Joe", "age": 25, "favoriteNumber": "123" }
Note that age=25 is encoded as a number while favoriteNumber=123 is encoded as a string .请注意,age=25 被编码为数字,而 favoriteNumber=123 被编码为字符串。 Out of the box Jackson marshalls
int
to a number.开箱即用的杰克逊将
int
编组为一个数字。 In this case I want favoriteNumber to be encoded as a string.在这种情况下,我希望将 favoriteNumber 编码为字符串。
You can implement a custom serializer as follows:您可以按如下方式实现自定义序列化程序:
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 should handle the autoboxing from int
to Integer
for you. Java 应该为您处理从
int
到Integer
的自动装箱。
Jackson-databind (at least 2.1.3) provides special ToStringSerializer
( com.fasterxml.jackson.databind.ser.std.ToStringSerializer
) Jackson-databind (至少 2.1.3) 提供了特殊的
ToStringSerializer
( com.fasterxml.jackson.databind.ser.std.ToStringSerializer
)
Example:例子:
public class Person {
public String name;
public int age;
@JsonSerialize(using = ToStringSerializer.class)
public int favoriteNumber:
}
jackson-annotations provides @JsonFormat
which can handle a lot of customizations without the need to write the custom serializer. jackson-annotations 提供了
@JsonFormat
,它可以处理大量的自定义,而无需编写自定义序列化程序。
For example, requesting a STRING
shape for a field with numeric type will output the numeric value as string例如,为数字类型的字段请求
STRING
形状将输出数字值作为字符串
public class Person {
public String name;
public int age;
@JsonFormat(shape = JsonFormat.Shape.STRING)
public int favoriteNumber;
}
will result in the desired output将导致所需的输出
{"name":"Joe","age":25,"favoriteNumber":"123"}
Add a @JsonProperty
annotated getter, which returns a String
, for the favoriteNumber
field:添加
@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"}
}
}
In case you don't want to pollute your model with annotations and want to perform some custom operations, you could use mixins.如果您不想使用注释污染模型并希望执行一些自定义操作,则可以使用 mixins。
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.setMixInAnnotation(Person.class, PersonMixin.class);
mapper.registerModule(simpleModule);
Override age:覆盖年龄:
public abstract class PersonMixin {
@JsonSerialize(using = PersonAgeSerializer.class)
public String age;
}
Do whatever you need with the 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");
}
}
with the help of @JsonView we can decide fields of model classes to serialize which satisfy the minimal criteria ( we have to define the criteria) like we can have one core class with 10 properties but only 5 properties can be serialize which are needful for client only在@JsonView的帮助下,我们可以决定要序列化的模型类的字段满足最低标准(我们必须定义标准),就像我们可以有一个具有 10 个属性的核心类,但只能序列化 5 个属性是客户端需要的只要
Define our Views by simply creating following class:通过简单地创建以下类来定义我们的视图:
public class Views
{
static class Android{};
static class IOS{};
static class Web{};
}
Annotated model class with views:带视图的带注释的模型类:
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
...
..
}
Now we have to write custom json converter by simply extending HttpMessageConverter class from spring as:现在我们必须通过简单地从 spring 扩展 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);
}
}
}
Now there is need to tell spring to use this custom json convert by simply putting this in dispatcher-servlet.xml现在需要告诉 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>
That's how you will able to decide which fields to get serialize.这就是您将能够决定要序列化哪些字段的方式。
You can create a custom serializer inline in the mixin.您可以在 mixin 中内联创建自定义序列化程序。 Then annotate a field with it.
然后用它注释一个字段。 See example below that appends " - something else " to lang field.
请参见下面的示例,该示例将“ - 其他”附加到 lang 字段。 This is kind of hackish - if your serializer requires something like a repository or anything injected by spring, this is going to be a problem.
这有点骇人听闻- 如果您的序列化程序需要诸如存储库或 spring 注入的任何内容,这将是一个问题。 Probably best to use a custom deserializer/serializer instead of a mixin.
可能最好使用自定义解串器/串行器而不是 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");
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.