Jackson:仅为主/容器类型开启默认类型的配置方法咨询
仅为指定容器类开启Jackson默认类型的解决方案
要实现仅对标记的「容器类」(如你的Document类)自动添加类型信息(@class字段),同时不对其内部类、集合或包装类型启用默认类型,且无需手动给每个容器类添加@JsonTypeInfo注解,可通过以下步骤实现:
1. 自定义容器类标记注解
先定义一个注解,用来标记哪些类是需要开启默认类型的容器类:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ContainerType { }
2. 自定义TypeResolverBuilder实现规则
继承Jackson的StdTypeResolverBuilder,重写useForType方法,仅对标记了@ContainerType的类启用类型信息:
import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder; public class ContainerOnlyTypeResolverBuilder extends StdTypeResolverBuilder { @Override public boolean useForType(JavaType type) { // 仅对标记了@ContainerType的类启用类型信息 return type.getRawClass().isAnnotationPresent(ContainerType.class); } }
3. 配置ObjectMapper使用自定义Builder
在配置ObjectMapper时,指定使用我们自定义的类型解析器,并设置类型信息的存储方式(如作为属性@class):
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; public class ObjectMapperConfig { public static ObjectMapper createCustomObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // 初始化自定义类型解析器 TypeResolverBuilder<?> typeResolverBuilder = new ContainerOnlyTypeResolverBuilder() .init(com.fasterxml.jackson.annotation.JsonTypeInfo.Id.CLASS, null) .inclusion(com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY) .typeProperty("@class"); // 指定类型字段名 // 为ObjectMapper设置自定义默认类型规则 objectMapper.setDefaultTyping(typeResolverBuilder); return objectMapper; } }
4. 标记容器类
给需要开启默认类型的容器类添加@ContainerType注解,比如你的Document类:
@ContainerType public class Document { private String id; private Long testingLong; private Long accountId; private Internal internal; private List<String> list; // 省略getter、setter、构造方法 } // 内部类无需标记,不会生成类型信息 public class Internal { private String id; // 省略getter、setter、构造方法 }
5. 测试效果
序列化Document实例时,只有Document会生成@class字段,内部的Internal、Long、List都不会添加额外类型信息:
public class TestSerialization { public static void main(String[] args) throws Exception { ObjectMapper objectMapper = ObjectMapperConfig.createCustomObjectMapper(); Internal internal = new Internal(); internal.setId("1"); Document document = new Document(); document.setId(null); document.setTestingLong(5L); document.setAccountId(10L); document.setInternal(internal); document.setList(List.of("1", "2", "3")); String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(document); System.out.println(json); } }
输出的JSON如下,符合需求:
{ "@class" : "com.example.demo.test.Document", "id" : null, "testingLong" : 5, "accountId" : 10, "internal" : { "id" : "1" }, "list" : [ "1", "2", "3" ] }
扩展说明
- 如果需要批量标记容器类(比如某个包下的所有类),可以修改
useForType方法的判断逻辑,比如检查类的包名是否符合规则,无需逐个添加注解。 - 若反序列化时根对象类型为
Object,Jackson会通过@class字段自动解析为对应的容器类实例,内部字段则按类定义的类型正常反序列化。
内容的提问来源于stack exchange,提问作者F1zz4
相关产品推荐
相关产品推荐

