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

Java @JsonSerialize-如何在运行时创建包装器并对对象字段使用默认序列化?,java,json,jackson,wrapper,jsonserializer,Java,Json,Jackson,Wrapper,Jsonserializer,我想添加一个名为的包装器,它是在运行时确定的,因为它取决于类名(我可以使用@JsonRootName,但我不想,因为我必须在每个子类上使用它,这是没有效率的) 我想我应该使用@JsonSerialize覆盖默认的序列化程序,但我只想创建包装器;我不想自己序列化对象字段(而且我在一个抽象类中,所以我甚至不知道子类的字段!)。我不在乎他们,我只在乎包装纸!因此,我希望默认序列化程序为我处理这些字段,或者类似的内容 @JsonSerialize(使用=CustomSerializer.class) 公

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

我想我应该使用
@JsonSerialize
覆盖默认的序列化程序,但我只想创建包装器;我不想自己序列化对象字段(而且我在一个抽象类中,所以我甚至不知道子类的字段!)。我不在乎他们,我只在乎包装纸!因此,我希望默认序列化程序为我处理这些字段,或者类似的内容

@JsonSerialize(使用=CustomSerializer.class)
公共抽象类请求{
公共静态类CustomSerializer扩展了JsonSerializer{
@凌驾
public void serialize(请求、JsonGenerator jgen、SerializerProvider提供程序)引发IOException{
//根据request.class.getSimpleName()确定包装器名称
//那么我应该如何序列化字段呢?
//基本上,我只需要一个函数来生成与默认序列化程序生成的json相同的json!
//我尝试了以下方法,但显然它给出了com.fasterxml.jackson.databind.JsonMappingException:无限递归
jgen.writeObject(值);
//下面的函数也有相同的错误
provider.defaultSerializeValue(值,jgen);
}
}

要创建包装序列化程序,您需要使用
com.fasterxml.jackson.databind.ser.BeanSerializerModifier
类。您可以使用
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
}

相反,您可以使用
序列化
方法并删除额外的包装调用。

即使我接受的解决方案是正确的,我还是提出了从a获得的另一个解决方案,它依赖于一个技巧:使该类自定义序列化另一个类的字段(纯粹用于包装)并在此字段上使用
@JsonSerialize
。代码更简单,但您必须创建和操作包装类。请参见以下内容:

公共类RequestWrapper{
@JsonUnwrapped//防止字段用名称“request”包装
@JsonSerialize(使用=RequestSerializer.class)
私人最终请求;
私有请求包装器(请求){
this.request=请求;
}
公共请求getRequest(){
返回请求;
}
公共静态类RequestSerializer扩展JsonSerializer{
@凌驾
公共布尔isUnwrappingSerializer(){
return true;//表示我们正在创建一个“unwrapping”序列化程序,因为我们添加了@JsonUnwrapped
}
@凌驾
public void serialize(请求、JsonGenerator jgen、SerializerProvider提供程序)引发IOException{
writeObject字段(request.getClass().getSimpleName(),value);
}
}
}
我在上看到了这个解决方案。这正是我想要的,尽管不幸的是,对于一个简单的需求来说,它有点复杂。谢谢。
{
  "Request1Wrapper" : {
    "id" : 1,
    "body" : "POST"
  }
}
{
  "Request2Wrapper" : {
    "id" : 2,
    "uuid" : "dd4cccb5-1cf5-4dd4-8bc7-97cb101e5d7d"
  }
}