gpt4 book ai didi

json - ContextualDeserializer,用于使用 Jackson 将 JSON 映射到不同类型的映射

转载 作者:行者123 更新时间:2023-12-02 01:30:44 35 4
gpt4 key购买 nike

此 JSON 片段应映射到包含 cars 的 Java 对象类型字段Map<String, Car>和一个 bikes类型字段Map<String, Bike> 。由于自行车和汽车在 JSON 文件中可能是空字符串,因此我需要一个自定义反序列化器 ( See this question )。

{
"id" : "1234",
"name" : "John Doe",
"cars" : {
"Tesla Model S" : {
"color" : "silver",
"buying_date" : "2012-06-01"
},
"Toyota Yaris" : {
"color" : "blue",
"buying_date" : "2005-01-01"
}
},
"bikes" : {
"Bike 1" : {
"color" : "black"
},
"Bike 2" : {
"color" : "red"
}
}
}

我考虑过拥有一个可以由createContextual(DeserializationConfig cfg, BeanProperty property)返回的通用自定义反序列化器的实例。方法ContextualDeserializer基于 BeanProperty 参数。通用的自定义反序列化器如下所示:

public class MapsGenericDeserializer<T> extends
JsonDeserializer<Map<String, T>> {

private ObjectMapper mapper; // ObjectMapper without special map deserializer

public MapsGenericDeserializer(ObjectMapper mapper) {
this.mapper = mapper;
}

@Override
public Map<String, T> deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectCodec codec = jp.getCodec();
JsonNode node = codec.readTree(jp);
if (!"".equals(node.getTextValue())) {
return mapper.readValue(node,
new TypeReference<Map<String, T>>() {});
}
return null; // Node was an empty string
}
}

下面的上下文序列化器不起作用,因为从 MapsGenericDeserializer<Car> 进行转换至JsonDeserializer<Map<String,?>>不可能。也许这在较新版本的 Java 中是可能的,但它不适用于我正在编码的 Android 版本。那么我怎样才能实现所需的行为呢?

public class MapsDeserializer extends JsonDeserializer<Map<String, ?>>
implements ContextualDeserializer<Map<String, ?>> {

private ObjectMapper mapper;

MapsGenericDeserializer<Car> carDeserializer = new MapsGenericDeserializer<Car>(mapper);
MapsGenericDeserializer<Bike> bikeDeserializer = new MapsGenericDeserializer<Bike>(mapper);

public MapsDeserializer(ObjectMapper mapper) {
this.mapper = mapper;
}

@Override
public JsonDeserializer<Map<String, ?>> createContextual(DeserializationConfig cfg,
BeanProperty property) throws JsonMappingException {

Class<?> targetClass = property.getType().containedType(1).getRawClass();

if(targetClass.equals(Car.class) {
return carDeserializer; // Type mismatch!
} else if (targetClass.equals(Bike.class)) {
return bikeDeserializer; // Type mismatch!
} else {
return this;
}
}

// ...
}

最佳答案

这是我可能采取的方法。

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.Version;
import org.codehaus.jackson.map.BeanProperty;
import org.codehaus.jackson.map.ContextualDeserializer;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.module.SimpleModule;

public class Foo
{
public static void main(String[] args) throws Exception
{
EmptyStringAsMapDeserializer<Map<String, ?>> emptyStringAsMapDeserializer =
new EmptyStringAsMapDeserializer<Map<String, ?>>(null, new ObjectMapper());

SimpleModule module = new SimpleModule("ThingsDeserializer", Version.unknownVersion());
module.addDeserializer(Map.class, emptyStringAsMapDeserializer);

ObjectMapper mapper = new ObjectMapper().withModule(module);

Person person = mapper.readValue(new File("input.json"), Person.class);
System.out.println(mapper.writeValueAsString(person));
}
}

class Person
{
public int id;
public String name;
public Map<String, Car> cars;
public Map<String, Bike> bikes;
}

class Car
{
public String color;
public String buying_date;
}

class Bike
{
public String color;
}

class EmptyStringAsMapDeserializer<T>
extends JsonDeserializer<Map<String, ?>>
implements ContextualDeserializer<Map<String, ?>>
{
private Class<?> targetType;
private ObjectMapper mapper;

EmptyStringAsMapDeserializer(Class<?> targetType, ObjectMapper mapper)
{
this.targetType = targetType;
this.mapper = mapper;
}

@Override
public JsonDeserializer<Map<String, ?>> createContextual(DeserializationConfig config, BeanProperty property)
throws JsonMappingException
{
return new EmptyStringAsMapDeserializer<Object>(property.getType().containedType(1).getRawClass(), mapper);
}

@Override
public Map<String, ?> deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
JsonNode node = jp.readValueAsTree();
if ("".equals(node.getTextValue()))
return new HashMap<String, Object>();
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(node, mapper.getTypeFactory().constructMapType(Map.class, String.class, targetType));
}
}

泛型类型参数可能有点乱。我做了一些快速复制粘贴。

关于json - ContextualDeserializer,用于使用 Jackson 将 JSON 映射到不同类型的映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6704992/

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