java - @JsonSerialize - 如何在运行时创建包装器并为对象字段使用默认序列化?

标签 java json jackson wrapper jsonserializer

我想添加一个包装器,其命名是在运行时确定的,因为它取决于类名(我可以使用@JsonRootName,但我不想这样做,因为我必须在每个子类上使用它,即效率不高)。

我想我应该使用 @JsonSerialize 来覆盖默认的序列化器,但我只想创建包装器;我不想自己序列化对象字段(而且我在一个抽象类中,所以我什至不知道子类的字段!)。我不关心它们,我只关心包装!所以我希望默认序列化器为我处理这些字段,或者类似的东西。

@JsonSerialize(using = CustomSerializer.class)
public abstract class Request {

    public static class CustomSerializer extends JsonSerializer<Request > {
        @Override
        public void serialize(Request request, JsonGenerator jgen, SerializerProvider provider) throws IOException {
            // Doing my stuff to determine the wrapper name based on request.class.getSimpleName()
            // Then what should I wright to serialize the fields?
            // Basically I just want a function to generate the same json that the default serializer would generate!

            // I tried the following, but obviously it gives a com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion
            jgen.writeObject(value);

            // Same error for the function below 
            provider.defaultSerializeValue(value, jgen);
        }
    }

最佳答案

要创建包装序列化程序,您需要使用 com.fasterxml.jackson.databind.ser.BeanSerializerModifier类(class)。您可以使用 com.fasterxml.jackson.databind.module.SimpleModule 注册它。下面的示例展示了如何做到这一点的端到端解决方案:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.util.NameTransformer;

import java.io.IOException;
import java.util.UUID;

public class JsonPathApp {

    public static void main(String[] args) throws Exception {
        SimpleModule wrappersModule = new SimpleModule("requestWrapper");
        wrappersModule.setSerializerModifier(new BeanSerializerModifier() {
            @Override
            public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
                if (Request.class.isAssignableFrom(beanDesc.getBeanClass())) {
                    return new RequestWrapperJsonSerializer(serializer);
                }
                return serializer;
            }
        });
        ObjectMapper mapper = JsonMapper.builder()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .addModule(wrappersModule)
                .build();

        System.out.println(mapper.writeValueAsString(new Request1(1, "POST")));
        System.out.println(mapper.writeValueAsString(new Request2(2, UUID.randomUUID())));
    }
}

class RequestWrapperJsonSerializer extends JsonSerializer<Request> {

    private final JsonSerializer baseSerializer;

    public RequestWrapperJsonSerializer(JsonSerializer baseSerializer) {
        this.baseSerializer = baseSerializer;
    }

    @Override
    public void serialize(Request value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        gen.writeFieldName(value.getClass().getSimpleName() + "Wrapper");
        gen.writeStartObject();
        baseSerializer.unwrappingSerializer(NameTransformer.NOP).serialize(value, gen, serializers);
        gen.writeEndObject();
        gen.writeEndObject();
    }
}

abstract class Request {
    private int id;

    //constructor, getters, setters, toString
}

class Request1 extends Request {
    private String body;

    //constructor, getters, setters, toString
}

class Request2 extends Request {

    private UUID uuid;

    //constructor, getters, setters, toString
}

上面的代码打印:

{
  "Request1Wrapper" : {
    "id" : 1,
    "body" : "POST"
  }
}
{
  "Request2Wrapper" : {
    "id" : 2,
    "uuid" : "dd4cccb5-1cf5-4dd4-8bc7-97cb101e5d7d"
  }
}

相反unwrappingSerializer您可以使用的方法 serialize方法并删除额外的包装调用。

关于java - @JsonSerialize - 如何在运行时创建包装器并为对象字段使用默认序列化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59411455/

相关文章:

java - 如何使用 Jackson 获取嵌套 JsonNode 内的集合

java - Jersey 2.17 中缺少 Response.readEntity() 吗?

java - NavigableMap 的subMap 会导致内存泄漏吗?

json - 我如何 Json.decode 联合类型?

java - 从命令提示符编译 J2ME

c# - 如何将对象序列化为 Json,在桌面 C# 应用程序中将对象类的名称作为根添加?

javascript - 如何将 JSON 数据存储在磁盘上?

jquery - Spring JSON 和 406 HTTP 错误

java - Jsoup, '&gt;' 的问题相关转换

java - 无法使用Java连接到HBase?