如何使用Jackson的自定义序列化器?

时间:2022-07-14 07:15:21

I have two Java classes that I want to serialize to JSON using Jackson:

我有两个Java类,我想使用Jackson将它们序列化为JSON:

public class User {
    public final int id;
    public final String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

public class Item {
    public final int id;
    public final String itemNr;
    public final User createdBy;

    public Item(int id, String itemNr, User createdBy) {
        this.id = id;
        this.itemNr = itemNr;
        this.createdBy = createdBy;
    }
}

I want to serialize an Item to this JSON:

我想将一个项目序列化为这个JSON:

{"id":7, "itemNr":"TEST", "createdBy":3}

with User serialized to only include the id. I will also be able to serilize all user objects to JSON like:

将用户序列化为只包含id,我还可以将所有用户对象serilize为JSON:

{"id":3, "name": "Jonas", "email": "jonas@example.com"}

So I guess that I need to write a custom serializer for Item and tried with this:

所以我想我需要为项目编写一个自定义序列化器,并尝试:

public class ItemSerializer extends JsonSerializer<Item> {

@Override
public void serialize(Item value, JsonGenerator jgen,
        SerializerProvider provider) throws IOException,
        JsonProcessingException {
    jgen.writeStartObject();
    jgen.writeNumberField("id", value.id);
    jgen.writeNumberField("itemNr", value.itemNr);
    jgen.writeNumberField("createdBy", value.user.id);
    jgen.writeEndObject();
}

}

I serialize the JSON with this code from Jackson How-to: Custom Serializers:

我用Jackson How-to:自定义序列化器中的代码序列化JSON:

ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule", 
                                              new Version(1,0,0,null));
simpleModule.addSerializer(new ItemSerializer());
mapper.registerModule(simpleModule);
StringWriter writer = new StringWriter();
try {
    mapper.writeValue(writer, myItem);
} catch (JsonGenerationException e) {
    e.printStackTrace();
} catch (JsonMappingException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

But I get this error:

但是我得到了这个错误:

Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.ItemSerializer does not define valid handledType() (use alternative registration method?)
    at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62)
    at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54)
    at com.example.JsonTest.main(JsonTest.java:54)

How can I use a custom Serializer with Jackson?

如何使用Jackson的自定义序列化器?


This is how I would do it with Gson:

这就是我对Gson所做的:

public class UserAdapter implements JsonSerializer<User> {

    @Override 
    public JsonElement serialize(User src, java.lang.reflect.Type typeOfSrc,
            JsonSerializationContext context) {
        return new JsonPrimitive(src.id);
    }
}

    GsonBuilder builder = new GsonBuilder();
    builder.registerTypeAdapter(User.class, new UserAdapter());
    Gson gson = builder.create();
    String json = gson.toJson(myItem);
    System.out.println("JSON: "+json);

But I need to do it with Jackson now, since Gson doesn't have support for interfaces.

但是我现在需要用Jackson来做,因为Gson不支持接口。

10 个解决方案

#1


36  

As mentioned, @JsonValue is a good way. But if you don't mind a custom serializer, there's no need to write one for Item but rather one for User -- if so, it'd be as simple as:

如前所述,@JsonValue是一种很好的方式。但是,如果您不介意一个自定义序列化器,那么就不需要为条目编写一个,而是为用户编写一个,如果是这样,那么就很简单:

public void serialize(Item value, JsonGenerator jgen,
    SerializerProvider provider) throws IOException,
    JsonProcessingException {
  jgen.writeNumber(id);
}

Yet another possibility is to implement JsonSerializable, in which case no registration is needed.

另一种可能是实现JsonSerializable,在这种情况下,不需要注册。

As to error; that is weird -- you probably want to upgrade to a later version. But it is also safer to extend org.codehaus.jackson.map.ser.SerializerBase as it will have standard implementations of non-essential methods (i.e. everything but actual serialization call).

为错误;这很奇怪——您可能想要升级到以后的版本。但是扩展org.codehaus.jackson.map.ser也更安全。SerializerBase因为它将具有非必需方法的标准实现(即除了实际的序列化调用之外的所有方法)。

#2


52  

You can put @JsonSerialize(using = CustomDateSerializer.class) over any date field of object to be serialized.

可以将@JsonSerialize(使用= CustomDateSerializer.class)放在要序列化的对象的任何日期字段上。

public class CustomDateSerializer extends SerializerBase<Date> {

    public CustomDateSerializer() {
        super(Date.class, true);
    }

    @Override
    public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider)
        throws IOException, JsonProcessingException {
        SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'ZZZ (z)");
        String format = formatter.format(value);
        jgen.writeString(format);
    }

}

#3


28  

I tried doing this too, and there is a mistake in the example code on the Jackson web page that fails to include the type (.class) in the call to addSerializer method, which should read like this:

我也尝试过这样做,Jackson web页面上的示例代码中有一个错误,没有将类型(.class)包含在对addSerializer方法的调用中,它应该如下所示:

simpleModule.addSerializer(Item.class, new ItemSerializer());

In other words, these are the lines that instantiate the simpleModule and add the serializer (with the prior incorrect line commented out):

换句话说,这些行实例化simpleModule并添加serializer(前面的不正确的行注释掉了):

ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule", 
                                          new Version(1,0,0,null));
// simpleModule.addSerializer(new ItemSerializer());
simpleModule.addSerializer(Item.class, new ItemSerializer());
mapper.registerModule(simpleModule);

FYI: Here is the reference for the correct example code: http://wiki.fasterxml.com/JacksonFeatureModules

这里是正确示例代码的引用:http://wiki.fasterxml.com/JacksonFeatureModules

Hope this helps!

希望这可以帮助!

#4


7  

Use @JsonValue:

使用@JsonValue:

public class User {
    int id;
    String name;

    @JsonValue
    public int getId() {
        return id;
    }
}

@JsonValue only works on methods so you must add the getId method. You should be able to skip your custom serializer altogether.

@JsonValue只对方法有效,所以必须添加getId方法。您应该能够完全跳过自定义序列化器。

#5


6  

These are behavior patterns I have noticed while trying to understand Jackson serialization.

这些是我在尝试理解Jackson序列化时注意到的行为模式。

1) Assume there is an object Classroom and a class Student. I've made everything public and final for ease.

1)假设有一个实物教室和一个班级学生。我把一切都公布于众,让大家放心。

public class Classroom {
    public final double double1 = 1234.5678;
    public final Double Double1 = 91011.1213;
    public final Student student1 = new Student();
}

public class Student {
    public final double double2 = 1920.2122;
    public final Double Double2 = 2324.2526;
}

2) Assume that these are the serializers we use for serializing the objects into JSON. The writeObjectField uses the object's own serializer if it is registered with the object mapper; if not, then it serializes it as a POJO. The writeNumberField exclusively only accepts primitives as arguments.

假设这些是我们用于将对象序列化为JSON的序列化器。如果向对象映射器注册,则writeObjectField使用对象自己的序列化器;如果不是,则将其序列化为POJO。writeNumberField只接受原语作为参数。

public class ClassroomSerializer extends StdSerializer<Classroom> {
    public ClassroomSerializer(Class<Classroom> t) {
        super(t);
    }

    @Override
    public void serialize(Classroom value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        jgen.writeStartObject();
        jgen.writeObjectField("double1-Object", value.double1);
        jgen.writeNumberField("double1-Number", value.double1);
        jgen.writeObjectField("Double1-Object", value.Double1);
        jgen.writeNumberField("Double1-Number", value.Double1);
        jgen.writeObjectField("student1", value.student1);
        jgen.writeEndObject();
    }
}

public class StudentSerializer extends StdSerializer<Student> {
    public StudentSerializer(Class<Student> t) {
        super(t);
    }

    @Override
    public void serialize(Student value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        jgen.writeStartObject();
        jgen.writeObjectField("double2-Object", value.double2);
        jgen.writeNumberField("double2-Number", value.double2);
        jgen.writeObjectField("Double2-Object", value.Double2);
        jgen.writeNumberField("Double2-Number", value.Double2);
        jgen.writeEndObject();
    }
}

3) Register only a DoubleSerializer with DecimalFormat output pattern ###,##0.000, in SimpleModule and the output is:

3)在SimpleModule中,仅注册一个具有DecimalFormat输出模式### #、#0.000的双线程化器,输出如下:

{
  "double1" : 1234.5678,
  "Double1" : {
    "value" : "91,011.121"
  },
  "student1" : {
    "double2" : 1920.2122,
    "Double2" : {
      "value" : "2,324.253"
    }
  }
}

You can see that the POJO serialization differentiates between double and Double, using the DoubleSerialzer for Doubles and using a regular String format for doubles.

您可以看到,POJO序列化区分了double和double,使用DoubleSerialzer进行double,使用常规字符串格式进行double。

4) Register DoubleSerializer and ClassroomSerializer, without the StudentSerializer. We expect that the output is such that if we write a double as an object, it behaves like a Double, and if we write a Double as a number, it behaves like a double. The Student instance variable should be written as a POJO and follow the pattern above since it does not register.

4)注册DoubleSerializer和ClassroomSerializer,但不包括StudentSerializer。我们期望输出是这样的,如果我们把double作为对象来写,它的行为就像double,如果我们把double作为数字来写,它的行为就像double。学生实例变量应该写成POJO,并遵循上面的模式,因为它不注册。

{
  "double1-Object" : {
    "value" : "1,234.568"
  },
  "double1-Number" : 1234.5678,
  "Double1-Object" : {
    "value" : "91,011.121"
  },
  "Double1-Number" : 91011.1213,
  "student1" : {
    "double2" : 1920.2122,
    "Double2" : {
      "value" : "2,324.253"
    }
  }
}

5) Register all serializers. The output is:

5)登记所有的序列化器。的输出是:

{
  "double1-Object" : {
    "value" : "1,234.568"
  },
  "double1-Number" : 1234.5678,
  "Double1-Object" : {
    "value" : "91,011.121"
  },
  "Double1-Number" : 91011.1213,
  "student1" : {
    "double2-Object" : {
      "value" : "1,920.212"
    },
    "double2-Number" : 1920.2122,
    "Double2-Object" : {
      "value" : "2,324.253"
    },
    "Double2-Number" : 2324.2526
  }
}

exactly as expected.

与预期完全一致。

Another important note: If you have multiple serializers for the same class registered with the same Module, then the Module will select the serializer for that class that is most recently added to the list. This should not be used - it's confusing and I am not sure how consistent this is

另一个重要注意事项:如果同一类的多个序列化器注册到同一模块,那么该模块将为最近添加到列表的类选择序列化器。这是不应该使用的-这是令人困惑的,我不确定这有多一致

Moral: if you want to customize serialization of primitives in your object, you must write your own serializer for the object. You cannot rely on the POJO Jackson serialization.

寓意:如果您想在对象中定制原语的序列化,您必须为对象编写自己的序列化器。你不能依赖POJO Jackson序列化。

#6


5  

Jackson's JSON Views might be a simpler way of achieving your requirements, especially if you have some flexibility in your JSON format.

Jackson的JSON视图可能是实现您的需求的一种更简单的方法,特别是如果您的JSON格式具有一定的灵活性。

If {"id":7, "itemNr":"TEST", "createdBy":{id:3}} is an acceptable representation then this will be very easy to achieve with very little code.

如果{“id”:7,“itemNr”:“TEST”,“createdBy”:{id:3}是一种可接受的表示,那么使用很少的代码就很容易实现这一点。

You would just annotate the name field of User as being part of a view, and specify a different view in your serialisation request (the un-annotated fields would be included by default)

您只需将用户的name字段注释为视图的一部分,并在序列化请求中指定一个不同的视图(默认情况下将包含未注释的字段)

For example: Define the views:

例如:定义视图:

public class Views {
    public static class BasicView{}
    public static class CompleteUserView{}
}

Annotate the User:

注释的用户:

public class User {
    public final int id;

    @JsonView(Views.CompleteUserView.class)
    public final String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

And serialise requesting a view which doesn't contain the field you want to hide (non-annotated fields are serialised by default):

并且序列化请求一个不包含您想要隐藏的字段的视图(非注释字段默认为序列化):

objectMapper.getSerializationConfig().withView(Views.BasicView.class);

#7


4  

In my case (Spring 3.2.4 and Jackson 2.3.1), XML configuration for custom serializer:

在我的例子中(Spring 3.2.4和Jackson 2.3.1),定制序列化器的XML配置:

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="false">
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="serializers">
                        <array>
                            <bean class="com.example.business.serializer.json.CustomObjectSerializer"/>
                        </array>
                    </property>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

was in unexplained way overwritten back to default by something.

以一种无法解释的方式重写为默认。

This worked for me:

这工作对我来说:

CustomObject.java

@JsonSerialize(using = CustomObjectSerializer.class)
public class CustomObject {

    private Long value;

    public Long getValue() {
        return value;
    }

    public void setValue(Long value) {
        this.value = value;
    }
}

CustomObjectSerializer.java

public class CustomObjectSerializer extends JsonSerializer<CustomObject> {

    @Override
    public void serialize(CustomObject value, JsonGenerator jgen,
        SerializerProvider provider) throws IOException,JsonProcessingException {
        jgen.writeStartObject();
        jgen.writeNumberField("y", value.getValue());
        jgen.writeEndObject();
    }

    @Override
    public Class<CustomObject> handledType() {
        return CustomObject.class;
    }
}

No XML configuration (<mvc:message-converters>(...)</mvc:message-converters>) is needed in my solution.

我的解决方案不需要XML配置( (…) 消息转换器>)。

#8


4  

I wrote an example for a custom Timestamp.class serialization/deserialization, but you could use it for what ever you want.

我为定制时间戳编写了一个示例。类序列化/反序列化,但是您可以将它用于任何您想要的。

When creating the object mapper do something like this:

在创建对象映射器时,请执行以下操作:

public class JsonUtils {

    public static ObjectMapper objectMapper = null;

    static {
        objectMapper = new ObjectMapper();
        SimpleModule s = new SimpleModule();
        s.addSerializer(Timestamp.class, new TimestampSerializerTypeHandler());
        s.addDeserializer(Timestamp.class, new TimestampDeserializerTypeHandler());
        objectMapper.registerModule(s);
    };
}

for example in java ee you could initialize it with this:

例如,在java ee中,您可以用以下方法初始化它:

import java.time.LocalDateTime;

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;

@Provider
public class JacksonConfig implements ContextResolver<ObjectMapper> {

    private final ObjectMapper objectMapper;

    public JacksonConfig() {
        objectMapper = new ObjectMapper();
        SimpleModule s = new SimpleModule();
        s.addSerializer(Timestamp.class, new TimestampSerializerTypeHandler());
        s.addDeserializer(Timestamp.class, new TimestampDeserializerTypeHandler());
        objectMapper.registerModule(s);
    };

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return objectMapper;
    }
}

where the serializer should be something like this:

序列化器应该是这样的:

import java.io.IOException;
import java.sql.Timestamp;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class TimestampSerializerTypeHandler extends JsonSerializer<Timestamp> {

    @Override
    public void serialize(Timestamp value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        String stringValue = value.toString();
        if(stringValue != null && !stringValue.isEmpty() && !stringValue.equals("null")) {
            jgen.writeString(stringValue);
        } else {
            jgen.writeNull();
        }
    }

    @Override
    public Class<Timestamp> handledType() {
        return Timestamp.class;
    }
}

and deserializer something like this:

反序列化器是这样的

import java.io.IOException;
import java.sql.Timestamp;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class TimestampDeserializerTypeHandler extends JsonDeserializer<Timestamp> {

    @Override
    public Timestamp deserialize(JsonParser jp, DeserializationContext ds) throws IOException, JsonProcessingException {
        SqlTimestampConverter s = new SqlTimestampConverter();
        String value = jp.getValueAsString();
        if(value != null && !value.isEmpty() && !value.equals("null"))
            return (Timestamp) s.convert(Timestamp.class, value);
        return null;
    }

    @Override
    public Class<Timestamp> handledType() {
        return Timestamp.class;
    }
}

#9


1  

You have to override method handledType and everything will work

您必须重写方法handledType,一切都会正常工作

@Override
public Class<Item> handledType()
{
  return Item.class;
}

#10


0  

If your only requirement in your custom serializer is to skip serializing the name field of User, mark it as transient. Jackson will not serialize or deserialize transient fields.

如果您在自定义序列化器中唯一的要求是跳过用户名字段的序列化,则将其标记为瞬态。Jackson不会序列化或反序列化瞬态字段。

[ see also: Why does Java have transient fields? ]

[另见:为什么Java有瞬态字段?]

#1


36  

As mentioned, @JsonValue is a good way. But if you don't mind a custom serializer, there's no need to write one for Item but rather one for User -- if so, it'd be as simple as:

如前所述,@JsonValue是一种很好的方式。但是,如果您不介意一个自定义序列化器,那么就不需要为条目编写一个,而是为用户编写一个,如果是这样,那么就很简单:

public void serialize(Item value, JsonGenerator jgen,
    SerializerProvider provider) throws IOException,
    JsonProcessingException {
  jgen.writeNumber(id);
}

Yet another possibility is to implement JsonSerializable, in which case no registration is needed.

另一种可能是实现JsonSerializable,在这种情况下,不需要注册。

As to error; that is weird -- you probably want to upgrade to a later version. But it is also safer to extend org.codehaus.jackson.map.ser.SerializerBase as it will have standard implementations of non-essential methods (i.e. everything but actual serialization call).

为错误;这很奇怪——您可能想要升级到以后的版本。但是扩展org.codehaus.jackson.map.ser也更安全。SerializerBase因为它将具有非必需方法的标准实现(即除了实际的序列化调用之外的所有方法)。

#2


52  

You can put @JsonSerialize(using = CustomDateSerializer.class) over any date field of object to be serialized.

可以将@JsonSerialize(使用= CustomDateSerializer.class)放在要序列化的对象的任何日期字段上。

public class CustomDateSerializer extends SerializerBase<Date> {

    public CustomDateSerializer() {
        super(Date.class, true);
    }

    @Override
    public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider)
        throws IOException, JsonProcessingException {
        SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'ZZZ (z)");
        String format = formatter.format(value);
        jgen.writeString(format);
    }

}

#3


28  

I tried doing this too, and there is a mistake in the example code on the Jackson web page that fails to include the type (.class) in the call to addSerializer method, which should read like this:

我也尝试过这样做,Jackson web页面上的示例代码中有一个错误,没有将类型(.class)包含在对addSerializer方法的调用中,它应该如下所示:

simpleModule.addSerializer(Item.class, new ItemSerializer());

In other words, these are the lines that instantiate the simpleModule and add the serializer (with the prior incorrect line commented out):

换句话说,这些行实例化simpleModule并添加serializer(前面的不正确的行注释掉了):

ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule", 
                                          new Version(1,0,0,null));
// simpleModule.addSerializer(new ItemSerializer());
simpleModule.addSerializer(Item.class, new ItemSerializer());
mapper.registerModule(simpleModule);

FYI: Here is the reference for the correct example code: http://wiki.fasterxml.com/JacksonFeatureModules

这里是正确示例代码的引用:http://wiki.fasterxml.com/JacksonFeatureModules

Hope this helps!

希望这可以帮助!

#4


7  

Use @JsonValue:

使用@JsonValue:

public class User {
    int id;
    String name;

    @JsonValue
    public int getId() {
        return id;
    }
}

@JsonValue only works on methods so you must add the getId method. You should be able to skip your custom serializer altogether.

@JsonValue只对方法有效,所以必须添加getId方法。您应该能够完全跳过自定义序列化器。

#5


6  

These are behavior patterns I have noticed while trying to understand Jackson serialization.

这些是我在尝试理解Jackson序列化时注意到的行为模式。

1) Assume there is an object Classroom and a class Student. I've made everything public and final for ease.

1)假设有一个实物教室和一个班级学生。我把一切都公布于众,让大家放心。

public class Classroom {
    public final double double1 = 1234.5678;
    public final Double Double1 = 91011.1213;
    public final Student student1 = new Student();
}

public class Student {
    public final double double2 = 1920.2122;
    public final Double Double2 = 2324.2526;
}

2) Assume that these are the serializers we use for serializing the objects into JSON. The writeObjectField uses the object's own serializer if it is registered with the object mapper; if not, then it serializes it as a POJO. The writeNumberField exclusively only accepts primitives as arguments.

假设这些是我们用于将对象序列化为JSON的序列化器。如果向对象映射器注册,则writeObjectField使用对象自己的序列化器;如果不是,则将其序列化为POJO。writeNumberField只接受原语作为参数。

public class ClassroomSerializer extends StdSerializer<Classroom> {
    public ClassroomSerializer(Class<Classroom> t) {
        super(t);
    }

    @Override
    public void serialize(Classroom value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        jgen.writeStartObject();
        jgen.writeObjectField("double1-Object", value.double1);
        jgen.writeNumberField("double1-Number", value.double1);
        jgen.writeObjectField("Double1-Object", value.Double1);
        jgen.writeNumberField("Double1-Number", value.Double1);
        jgen.writeObjectField("student1", value.student1);
        jgen.writeEndObject();
    }
}

public class StudentSerializer extends StdSerializer<Student> {
    public StudentSerializer(Class<Student> t) {
        super(t);
    }

    @Override
    public void serialize(Student value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        jgen.writeStartObject();
        jgen.writeObjectField("double2-Object", value.double2);
        jgen.writeNumberField("double2-Number", value.double2);
        jgen.writeObjectField("Double2-Object", value.Double2);
        jgen.writeNumberField("Double2-Number", value.Double2);
        jgen.writeEndObject();
    }
}

3) Register only a DoubleSerializer with DecimalFormat output pattern ###,##0.000, in SimpleModule and the output is:

3)在SimpleModule中,仅注册一个具有DecimalFormat输出模式### #、#0.000的双线程化器,输出如下:

{
  "double1" : 1234.5678,
  "Double1" : {
    "value" : "91,011.121"
  },
  "student1" : {
    "double2" : 1920.2122,
    "Double2" : {
      "value" : "2,324.253"
    }
  }
}

You can see that the POJO serialization differentiates between double and Double, using the DoubleSerialzer for Doubles and using a regular String format for doubles.

您可以看到,POJO序列化区分了double和double,使用DoubleSerialzer进行double,使用常规字符串格式进行double。

4) Register DoubleSerializer and ClassroomSerializer, without the StudentSerializer. We expect that the output is such that if we write a double as an object, it behaves like a Double, and if we write a Double as a number, it behaves like a double. The Student instance variable should be written as a POJO and follow the pattern above since it does not register.

4)注册DoubleSerializer和ClassroomSerializer,但不包括StudentSerializer。我们期望输出是这样的,如果我们把double作为对象来写,它的行为就像double,如果我们把double作为数字来写,它的行为就像double。学生实例变量应该写成POJO,并遵循上面的模式,因为它不注册。

{
  "double1-Object" : {
    "value" : "1,234.568"
  },
  "double1-Number" : 1234.5678,
  "Double1-Object" : {
    "value" : "91,011.121"
  },
  "Double1-Number" : 91011.1213,
  "student1" : {
    "double2" : 1920.2122,
    "Double2" : {
      "value" : "2,324.253"
    }
  }
}

5) Register all serializers. The output is:

5)登记所有的序列化器。的输出是:

{
  "double1-Object" : {
    "value" : "1,234.568"
  },
  "double1-Number" : 1234.5678,
  "Double1-Object" : {
    "value" : "91,011.121"
  },
  "Double1-Number" : 91011.1213,
  "student1" : {
    "double2-Object" : {
      "value" : "1,920.212"
    },
    "double2-Number" : 1920.2122,
    "Double2-Object" : {
      "value" : "2,324.253"
    },
    "Double2-Number" : 2324.2526
  }
}

exactly as expected.

与预期完全一致。

Another important note: If you have multiple serializers for the same class registered with the same Module, then the Module will select the serializer for that class that is most recently added to the list. This should not be used - it's confusing and I am not sure how consistent this is

另一个重要注意事项:如果同一类的多个序列化器注册到同一模块,那么该模块将为最近添加到列表的类选择序列化器。这是不应该使用的-这是令人困惑的,我不确定这有多一致

Moral: if you want to customize serialization of primitives in your object, you must write your own serializer for the object. You cannot rely on the POJO Jackson serialization.

寓意:如果您想在对象中定制原语的序列化,您必须为对象编写自己的序列化器。你不能依赖POJO Jackson序列化。

#6


5  

Jackson's JSON Views might be a simpler way of achieving your requirements, especially if you have some flexibility in your JSON format.

Jackson的JSON视图可能是实现您的需求的一种更简单的方法,特别是如果您的JSON格式具有一定的灵活性。

If {"id":7, "itemNr":"TEST", "createdBy":{id:3}} is an acceptable representation then this will be very easy to achieve with very little code.

如果{“id”:7,“itemNr”:“TEST”,“createdBy”:{id:3}是一种可接受的表示,那么使用很少的代码就很容易实现这一点。

You would just annotate the name field of User as being part of a view, and specify a different view in your serialisation request (the un-annotated fields would be included by default)

您只需将用户的name字段注释为视图的一部分,并在序列化请求中指定一个不同的视图(默认情况下将包含未注释的字段)

For example: Define the views:

例如:定义视图:

public class Views {
    public static class BasicView{}
    public static class CompleteUserView{}
}

Annotate the User:

注释的用户:

public class User {
    public final int id;

    @JsonView(Views.CompleteUserView.class)
    public final String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

And serialise requesting a view which doesn't contain the field you want to hide (non-annotated fields are serialised by default):

并且序列化请求一个不包含您想要隐藏的字段的视图(非注释字段默认为序列化):

objectMapper.getSerializationConfig().withView(Views.BasicView.class);

#7


4  

In my case (Spring 3.2.4 and Jackson 2.3.1), XML configuration for custom serializer:

在我的例子中(Spring 3.2.4和Jackson 2.3.1),定制序列化器的XML配置:

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="false">
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="serializers">
                        <array>
                            <bean class="com.example.business.serializer.json.CustomObjectSerializer"/>
                        </array>
                    </property>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

was in unexplained way overwritten back to default by something.

以一种无法解释的方式重写为默认。

This worked for me:

这工作对我来说:

CustomObject.java

@JsonSerialize(using = CustomObjectSerializer.class)
public class CustomObject {

    private Long value;

    public Long getValue() {
        return value;
    }

    public void setValue(Long value) {
        this.value = value;
    }
}

CustomObjectSerializer.java

public class CustomObjectSerializer extends JsonSerializer<CustomObject> {

    @Override
    public void serialize(CustomObject value, JsonGenerator jgen,
        SerializerProvider provider) throws IOException,JsonProcessingException {
        jgen.writeStartObject();
        jgen.writeNumberField("y", value.getValue());
        jgen.writeEndObject();
    }

    @Override
    public Class<CustomObject> handledType() {
        return CustomObject.class;
    }
}

No XML configuration (<mvc:message-converters>(...)</mvc:message-converters>) is needed in my solution.

我的解决方案不需要XML配置( (…) 消息转换器>)。

#8


4  

I wrote an example for a custom Timestamp.class serialization/deserialization, but you could use it for what ever you want.

我为定制时间戳编写了一个示例。类序列化/反序列化,但是您可以将它用于任何您想要的。

When creating the object mapper do something like this:

在创建对象映射器时,请执行以下操作:

public class JsonUtils {

    public static ObjectMapper objectMapper = null;

    static {
        objectMapper = new ObjectMapper();
        SimpleModule s = new SimpleModule();
        s.addSerializer(Timestamp.class, new TimestampSerializerTypeHandler());
        s.addDeserializer(Timestamp.class, new TimestampDeserializerTypeHandler());
        objectMapper.registerModule(s);
    };
}

for example in java ee you could initialize it with this:

例如,在java ee中,您可以用以下方法初始化它:

import java.time.LocalDateTime;

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;

@Provider
public class JacksonConfig implements ContextResolver<ObjectMapper> {

    private final ObjectMapper objectMapper;

    public JacksonConfig() {
        objectMapper = new ObjectMapper();
        SimpleModule s = new SimpleModule();
        s.addSerializer(Timestamp.class, new TimestampSerializerTypeHandler());
        s.addDeserializer(Timestamp.class, new TimestampDeserializerTypeHandler());
        objectMapper.registerModule(s);
    };

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return objectMapper;
    }
}

where the serializer should be something like this:

序列化器应该是这样的:

import java.io.IOException;
import java.sql.Timestamp;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class TimestampSerializerTypeHandler extends JsonSerializer<Timestamp> {

    @Override
    public void serialize(Timestamp value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        String stringValue = value.toString();
        if(stringValue != null && !stringValue.isEmpty() && !stringValue.equals("null")) {
            jgen.writeString(stringValue);
        } else {
            jgen.writeNull();
        }
    }

    @Override
    public Class<Timestamp> handledType() {
        return Timestamp.class;
    }
}

and deserializer something like this:

反序列化器是这样的

import java.io.IOException;
import java.sql.Timestamp;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class TimestampDeserializerTypeHandler extends JsonDeserializer<Timestamp> {

    @Override
    public Timestamp deserialize(JsonParser jp, DeserializationContext ds) throws IOException, JsonProcessingException {
        SqlTimestampConverter s = new SqlTimestampConverter();
        String value = jp.getValueAsString();
        if(value != null && !value.isEmpty() && !value.equals("null"))
            return (Timestamp) s.convert(Timestamp.class, value);
        return null;
    }

    @Override
    public Class<Timestamp> handledType() {
        return Timestamp.class;
    }
}

#9


1  

You have to override method handledType and everything will work

您必须重写方法handledType,一切都会正常工作

@Override
public Class<Item> handledType()
{
  return Item.class;
}

#10


0  

If your only requirement in your custom serializer is to skip serializing the name field of User, mark it as transient. Jackson will not serialize or deserialize transient fields.

如果您在自定义序列化器中唯一的要求是跳过用户名字段的序列化,则将其标记为瞬态。Jackson不会序列化或反序列化瞬态字段。

[ see also: Why does Java have transient fields? ]

[另见:为什么Java有瞬态字段?]