我使用Jackson 1.8.3将以下域对象序列化和反序列化为JSON
public class Node {
private String key;
private Object value;
private List<Node> children = new ArrayList<Node>();
/* getters and setters omitted for brevity */
}
然后使用以下代码序列化和反序列化对象
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(destination, rootNode);
然后用
反序列化mapper.readValue(destination, Node.class);
对象的原始值是Strings,Doubles,Longs或Booleans。但是,在序列化和反序列化期间,Jackson将Long值(例如4)转换为Integers。
如何“强制”杰克逊将数字非十进制值反序列化为Long而不是Integer?
答案 0 :(得分:23)
杰克逊2.6中有一个专门用于此案例的新功能:
将ObjectMapper配置为使用DeserializationFeature.USE_LONG_FOR_INTS
请参阅https://github.com/FasterXML/jackson-databind/issues/504
cowtowncoder在2015年5月19日推出了一个关闭此问题的提交 修复#504和#797
答案 1 :(得分:9)
如果将type声明为java.lang.Object,则Jackson使用“自然”映射,如果值适合32位,则使用Integer。除了自定义处理程序之外,您还必须强制包含类型信息(通过在field / getter旁边添加@JsonTypeInfo;或者通过启用所谓的“默认类型”)。
答案 2 :(得分:4)
我最终创建了一个自定义反序列化程序,因为在我的应用程序逻辑中,值只有四种不同的类型(Double
,Long
,Integer
和String
)。
我不确定这是否是最好的解决方案,但现在可行。
public class MyDeserializer extends JsonDeserializer<Object> {
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
try {
Long l = Long.valueOf(p.getText());
return l;
} catch (NumberFormatException nfe) {
// Not a Long
}
try {
Double d = Double.valueOf(p.getText());
return d;
} catch (NumberFormatException nfe) {
// Not a Double
}
if ("TRUE".equalsIgnoreCase(p.getText())
|| "FALSE".equalsIgnoreCase(p.getText())) {
// Looks like a boolean
return Boolean.valueOf(p.getText());
}
return String.valueOf(p.getText());
}
}
答案 3 :(得分:1)
我使用了类似下面的内容来解决这个问题。
@JsonIgnoreProperties(ignoreUnknown = true)
public class Message {
public Long ID;
@JsonCreator
private Message(Map<String,Object> properties) {
try {
this.ID = (Long) properties.get("id");
} catch (ClassCastException e) {
this.ID = ((Integer) properties.get("id")).longValue();
}
}
}
答案 4 :(得分:0)
如果要将原语包装到特定的类中,则可以执行以下操作(例如Kotlin中的示例):
data class Age(
@JsonValue
val value: Int
)
现在,您的Int
基元将被解析为Age类,反之亦然-Age类为Int基元。
答案 5 :(得分:0)
在杰克逊2中,我们可以使用TypeReference详细指定通用类型。 readValue()
有一个重载的方法,该方法将 TypeReference 作为第二个参数:
readValue([File | String | etc],com.fasterxml.jackson.core.type.TypeReference))
如果要获取Long
而不是Integer
的列表,则可以执行以下操作。
ObjectMapper mapper = new ObjectMapper();
TypeReference ref = new TypeReference<List<Integer>>() { };
List<Integer> list = mapper.readValue(<jsonString>, ref);
这也适用于地图:
TypeReference ref = new TypeReference<Map<String,Long>>() { };
Map<String, Long> map = mapper.readValue(<jsonString>, ref);
根据您的情况,您可以将您的类转换为通用类。即Node<T>
。创建节点时,请执行Node<String/Integer/etc>
并使用类型引用读取值。