V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
JasonLaw
V2EX  ›  Java

Jackson 如何保存 Map 中 key 的类型信息

  •  
  •   JasonLaw · 2020-07-13 12:11:52 +08:00 · 1916 次点击
    这是一个创建于 1631 天前的主题,其中的信息可能已经有所发展或是发生改变。

    首先看以下代码了解问题。

    PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder().build();
    ObjectMapper objectMapper = JsonMapper.builder()
            .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.EVERYTHING)
            .build();
    
    // content 为`["Gender","FEMALE"]`,保存了类型信息
    String content = objectMapper.writeValueAsString(Gender.FEMALE);
    
    PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder().build();
    ObjectMapper objectMapper = JsonMapper.builder()
            .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.EVERYTHING)
            .build();
    
    
    Map<Gender, String> map = new HashMap<>();
    map.put(Gender.FEMALE, "v1");
    
    // content 为`["java.util.HashMap",{"FEMALE":"v1"}]`,并没有保存 Map 中 key 的类型信息
    String content = objectMapper.writeValueAsString(map);
    

    我的问题:Jackson 可以做到保存 Map 中 key 的类型信息吗?如果可以,应该怎么做呢?

    我所做的尝试:

    1. 我尝试过配置 SerializationFeature,但是没有一个相关的 SerializationFeature 是可以实现这个功能的。
    2. 我发现objectMapper.writeValueAsString(Gender.FEMALE)使用的是TypeWrappedSerializer,最后调用StdScalarSerializer.serializeWithType(T value, JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer),因此保存了类型信息。但是objectMapper.writeValueAsString(map)不一样,在序列化 Map 中 key 的时候,最后会调用EnumKeySerializer.serialize(Object value, JsonGenerator g, SerializerProvider serializers),只是简单地调用了toString(),因此没有保存类型信息。
    7 条回复    2020-07-13 13:56:30 +08:00
    6IbA2bj5ip3tK49j
        1
    6IbA2bj5ip3tK49j  
       2020-07-13 12:55:53 +08:00
    你这是要干啥啊,感觉你压根不需要 json 啊。
    只是要一个类型安全的序列化 /反序列化的工具的话,没必要跟 json 死磕。
    wysnylc
        2
    wysnylc  
       2020-07-13 13:06:07 +08:00
    json 中结构只有 map 和数组,数据类型只有字符串和数值
    所有的反序列化都是收到 json 字符串然后反推结构和数据类型
    标准的序列化中是没有泛型的,甚至一些扩展实现的数据都会被抹掉比如实现 list 接口加个属性在里面的情况
    JasonLaw
        3
    JasonLaw  
    OP
       2020-07-13 13:09:44 +08:00 via iPhone
    @xgfan 我现在是使用 String 替代枚举作为替代应急措施,但是我更希望 Jackson 自身能够实现"保存 Map 中 key 的类型信息",因为不能改用其他的序列化 /反序列化机制。
    iyaozhen
        4
    iyaozhen  
       2020-07-13 13:17:49 +08:00
    你要是自己系统内部传输数据可以不用 json 呀,直接序列化就行

    或者你需要 pb
    iseki
        5
    iseki  
       2020-07-13 13:28:10 +08:00
    自己编写序列化器吧,你需要自己考虑把类型信息放在哪和安全问题
    passerbytiny
        6
    passerbytiny  
       2020-07-13 13:37:21 +08:00 via Android
    json 的 key,只能是值不能是对象;

    java 对象转成 json 是不保真的,不光 key,所有类型信息都会丢;

    json 转会 java 对象,需要额外指定 java 对象的类型;
    passerbytiny
        7
    passerbytiny  
       2020-07-13 13:56:30 +08:00 via Android
    仔细一看,楼主用了多态类型检测器。这玩意不是 json 标准(至少现在不是),我觉得一般人用试验性内容是在给自己挖坑。参考当前 javascript 、php 与 java 、.NET 在前端的流行度,这种强类型的 json 试验,很难成为正式标准。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5384 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 08:39 · PVG 16:39 · LAX 00:39 · JFK 03:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.