如何通过@JsonSerialize在运行时创建包装器并保留默认字段序列化?
解决Jackson动态根节点包装(无需每个子类加@JsonRootName)
嗨,这个需求我太熟了——想要给所有Request子类自动套一个以类名为名称的根节点,又不想在每个子类上重复加注解,同时还得复用Jackson的默认序列化逻辑对吧?
你之前遇到的无限递归问题,根源是直接调用writeObject或者defaultSerializeValue时,Jackson又会触发你这个自定义的CustomSerializer,陷入循环。解决的核心是获取对应子类的默认序列化器,绕过我们自己的这个。
直接上修改后的代码:
@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 { // 获取当前子类的默认序列化器,避开我们自定义的这个 JsonSerializer<Object> defaultSerializer = provider.findValueSerializer(request.getClass(), null); // 写入动态根节点:用子类的类名作为包装器名称 jgen.writeStartObject(); jgen.writeFieldName(request.getClass().getSimpleName()); // 用默认序列化器处理字段,完全复用Jackson原生逻辑,不会递归 defaultSerializer.serialize(request, jgen, provider); // 关闭根节点对象 jgen.writeEndObject(); } } }
关键逻辑解释:
provider.findValueSerializer(request.getClass(), null):这里会查找具体子类的默认序列化器(比如你的UserRequest、OrderRequest这些子类的BeanSerializer),而不是我们的CustomSerializer,所以不会触发递归。- 整个流程就是:先写外层的根节点对象,把子类类名作为字段名,然后用默认序列化器把子类的所有字段序列化到这个字段下面,最后关闭外层对象。
- 子类原来的所有Jackson注解(比如
@JsonProperty、@JsonIgnore、@JsonFormat)都会生效,因为我们完全复用了默认的序列化逻辑,只是加了一层包装。
举个例子,如果你的子类是:
public class UserRequest extends Request { private String username; private Integer age; // getters & setters }
序列化后会得到:
{ "UserRequest": { "username": "Alice", "age": 25 } }
完美符合你的需求——不用给每个子类加@JsonRootName,包装器名称自动用类名,字段序列化完全交给Jackson处理~
内容的提问来源于stack exchange,提问作者Flyout91
相关产品推荐
相关产品推荐

