gpt4 book ai didi

java - 向 Jackson Object Mapper 提供长对象池

转载 作者:行者123 更新时间:2023-12-03 23:17:06 25 4
gpt4 key购买 nike

我有一个可以转换为 POJO 的 JSON。从 GZIPInputStream gis 读取 JSON .

ObjectMapper mapper = new ObjectMapper();

TypeReference<Map<Long, ConfigMasterAirportData>> typeRef =
new TypeReference<Map<Long, ConfigMasterAirportData>>() {};

Map<Long, ConfigMasterAirportData> configMasterAirportMap =
mapper.readValue(gis, typeRef);

我不要新的 Long为每个条目创建的对象。我想让它得到 Long来自自定义的对象 LongPool我创造了。有没有办法通过这样的 LongPool到映射器?

如果没有,我可以使用另一个 JSON 库来做到这一点吗?

最佳答案

如果您确定在您的情况下需要对象池,有很多方法可以实现这一点。

首先,Java 已经做了 Long对象池在 -128 和 127 之间的小范围内(含)。查看 Long.valueOf 的源代码.

让我们有 2 个要反序列化的 JSON 对象:map1map2 :

    final String map1 = "{\"1\": \"Hello\", \"10000000\": \"world!\"}";
final String map2 = "{\"1\": \"You\", \"10000000\": \"rock!\"}";

标准反序列化

如果我们使用标准反序列化:
    final ObjectMapper mapper = new ObjectMapper();
final TypeReference<Map<Long, String>> typeRef = new TypeReference<Map<Long, String>>() {};
final Map<Long, String> deserializedMap1 = mapper.readValue(map1, typeRef);
final Map<Long, String> deserializedMap2 = mapper.readValue(map2, typeRef);

printMap(deserializedMap1);
printMap(deserializedMap2);

哪里 printMap被定义为
private static void printMap(Map<Long, String> longStringMap) {
longStringMap.forEach((Long k, String v) -> {
System.out.printf("key object id %d \t %s -> %s %n", System.identityHashCode(k), k, v);
});
}

我们得到以下输出:

key object id 1635756693     1 -> Hello 
key object id 504527234 10000000 -> world!
key object id 1635756693 1 -> You
key object id 101478235 10000000 -> rock!


注意键 1同一个对象带有哈希码 1635756693在两张 map 中。这是由于 [-128,127] 范围的内置池。

解决方案 1:@JsonAnySetter 反序列化

我们可以为 map 定义一个包装对象并使用 @JsonAnySetter拦截所有被反序列化的键值对的注释。然后我们可以实习每个 Long对象使用 Guava StrongInterner :
static class CustomLongPoolingMap {
private static final Interner<Long> LONG_POOL = Interners.newStrongInterner();
private final Map<Long, String> map = new HashMap<>();

@JsonAnySetter
public void addEntry(String key, String value) {
map.put(LONG_POOL.intern(Long.parseLong(key)), value);
}

public Map<Long, String> getMap() {
return map;
}
}

我们将像这样使用它:
    final ObjectMapper mapper = new ObjectMapper();
final Map<Long, String> deserializedMap1 = mapper.readValue(map1, CustomLongPoolingMap.class).getMap();
final Map<Long, String> deserializedMap2 = mapper.readValue(map2, CustomLongPoolingMap.class).getMap();

输出:

key object id 1635756693     1 -> Hello 
key object id 1596467899 10000000 -> world!
key object id 1635756693 1 -> You
key object id 1596467899 10000000 -> rock!


现在您可以看到该键 10000000在哈希码为 1596467899 的两个映射中也是同一个对象

方案二:注册自定义KeyDeserializer

定义自定义 KeySerializer :
public static class MyCustomKeyDeserializer extends KeyDeserializer {
private static final Interner<Long> LONG_POOL = Interners.newStrongInterner();
@Override
public Long deserializeKey(String key, DeserializationContext ctxt) {
return LONG_POOL.intern(Long.parseLong(key));
}
}

并使用 ObjectMapper 注册它:
    final SimpleModule module = new SimpleModule();
module.addKeyDeserializer(Long.class, new MyCustomKeyDeserializer());
final ObjectMapper mapper = new ObjectMapper().registerModule(module);
final TypeReference<Map<Long, String>> typeRef = new TypeReference<Map<Long, String>>() {};
final Map<Long, String> deserializedMap1 = mapper.readValue(map1, typeRef);
final Map<Long, String> deserializedMap2 = mapper.readValue(map2, typeRef);

解决方案 3:通过 @JsonDeserialize 使用自定义 KeyDeserializer注解

定义一个包装对象
static class MapWrapper {
@JsonDeserialize(keyUsing = MyCustomKeyDeserializer.class)
private Map<Long, String> map1;
@JsonDeserialize(keyUsing = MyCustomKeyDeserializer.class)
private Map<Long, String> map2;
}

并反序列化它:
    final ObjectMapper mapper = new ObjectMapper();
final String json = "{\"map1\": " + map1 + ", \"map2\": " + map2 + "}";
final MapWrapper wrapper = mapper.readValue(json, MapWrapper.class);
final Map<Long, String> deserializedMap1 = wrapper.map1;
final Map<Long, String> deserializedMap2 = wrapper.map2;

解决方案 4:使用 Trove library TLongObjectMap避免使用 Long完全对象

Trove 库实现了使用原始类型作为键的映射,以完全消除装箱对象的开销。然而,它处于某种 hibernate 状态。

您的情况需要 TLongObjectHashMap .

有一个库为 TIntObjectMap 定义了一个解串器。 :
https://bitbucket.org/marshallpierce/jackson-datatype-trove/src/d7386afab0eece6f34a0af69b76b478f417f0bd4/src/main/java/com/palominolabs/jackson/datatype/trove/deser/TIntObjectMapDeserializer.java?at=master&fileviewer=file-view-default

我认为它很容易适应 TLongObjectMap .

可以在此处找到此答案的完整代码: https://gist.github.com/shtratos/f0a81515d19b858dafb71e86b62cb474

我已经将这个问题的答案用于解决方案 2 和 3:
Deserializing non-string map keys with Jackson

关于java - 向 Jackson Object Mapper 提供长对象池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48882899/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com