我有以下课程
public class BetWrapper {
private String description;
private Calendar startTime;
private HashMap<String, SimpleEntry<Integer, Double>> map;
public BetWrapper() {
map = new HashMap<>();
}
public Calendar getStartTime() {
return startTime;
}
public void setStartTime(Calendar startTime) {
this.startTime = startTime;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public HashMap<String, SimpleEntry<Integer, Double>> getMap() {
return map;
}
public void setMap(HashMap<String, SimpleEntry<Integer, Double>> map) {
this.map = map;
}
}
我正在使用JSONUtil类
public class JSONUtil {
private JSONUtil() {}
public static <T> T fromJSON(String content, Class<T> clazz) throws TechnicalException {
try {
return new ObjectMapper().readValue(content, clazz);
} catch (IOException e) {
throw new TechnicalException(e);
}
}
public static String toJSON(Object obj) throws TechnicalException {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (JsonProcessingException ex) {
throw new TechnicalException(ex);
}
}
}
我想将JSON反序列化为BetWrapper对象。但是下面的代码会产生一些例外。
BetWrapper betWrapper = new BetWrapper();
betWrapper.setDescription("Stoke City - Arsenal");
betWrapper.setStartTime(Calendar.getInstance());
HashMap<String, AbstractMap.SimpleEntry<Integer, Double>> map = new HashMap<>();
map.put("home_team", new AbstractMap.SimpleEntry<>(1, 2.85));
betWrapper.setMap(map);
String json = JSONUtil.toJSON(betWrapper);
JSONUtil.fromJSON(json, BetWrapper.class);
例外情况是:
Caused by: com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class java.util.AbstractMap$SimpleEntry<java.lang.Integer,java.lang.Double>]: can not instantiate from JSON object (need to add/enable type information?)
at [Source: {"description":"Stoke City - Arsenal","startTime":1417648132139,"map":{"home_team":"key":1,"value":2.85}}}; line: 1, column: 85] (through reference chain: by.bsu.kolodyuk.bettingapp.model.entity.BetWrapper["map"])
如何正确反序列化?似乎问题是SimpleEntry中的类型K,V应该以某种方式为Jackson指定。
任何想法?
答案 0 :(得分:1)
类型SimpleEntry
具有以下构造函数
public SimpleEntry(K key, V value) {
this.key = key;
this.value = value;
}
默认情况下,Jackson需要一个无参数构造函数。如果这样的构造函数不存在,它会查找带有@JsonProperty
注释的构造函数。 (我可能会倒退,但不要那么编码。)既然你正在使用JDK类型,它显然不会有这些注释。
你可以使用Mixins。 Jackson使用这些作为模板来反序列化您的目标类型。
abstract class Mixin<K, V> {
public Mixin(@JsonProperty("key") K key, @JsonProperty("value") V value) {}
}
...
public static <T> T fromJSON(String content, Class<T> clazz) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(SimpleEntry.class, Mixin.class);
return mapper.readValue(content, clazz);
}
杰克逊将使用元类型Mixin
来反序列化为SimpleEntry
个对象。
(注意,Mixin
的类型参数和构造函数参数类型并不重要。事实上有两个构造函数参数,构造函数参数是注释的。)
答案 1 :(得分:0)
在Jackson中,您可以定义自定义反序列化器。所以对于你的情况,它可能看起来像这样:
import java.io.IOException;
import java.util.AbstractMap;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
public class SomeDeserializer extends StdDeserializer<AbstractMap.SimpleEntry>
{
public SomeDeserializer()
{
super( AbstractMap.SimpleEntry.class );
}
@Override
public AbstractMap.SimpleEntry deserialize( JsonParser jp, DeserializationContext ctxt ) throws IOException, JsonProcessingException
{
Integer key = null;
Double value = null;
JsonToken token;
while ( ( token = jp.nextValue() ) != null )
{
if ( token.isNumeric() )
{
String propertyName = jp.getCurrentName();
if ( "key".equalsIgnoreCase( propertyName ) )
{
key = jp.getIntValue();
}
else if ( "value".equalsIgnoreCase( propertyName ) )
{
value = jp.getDoubleValue();
}
}
}
if ( key != null && value != null )
{
return new AbstractMap.SimpleEntry( key, value );
}
return null;
}
}
应使用ObjectMapper.registerModule(Module m)
注册反序列化程序。在您的情况下,您可以在JSONUtil
实用程序类中执行此操作:
SimpleModule module = new SimpleModule();
module.addDeserializer( AbstractMap.SimpleEntry.class, new SomeDeserializer() );
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule( module );
请注意,反序列化器已在ObjectMapper
实例中注册。因此,您最好将实例存储为实用程序类的字段。
上面的反序列化程序类并不全面!这只是为了展示手头的情况。可以根据需要应用进一步的优化和重构。