2011-09-06 59 views
10

我序列化和反序列化使用以下杰克逊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); 

的对象A的原始值反序列化无论是弦乐,双打,长裤还是布尔人。但是,在序列化和反序列化过程中,Jackson将Long值(例如4)转换为Integers。

如何“强制”杰克逊将数字非十进制值反序列化为Long而不是Integer?

+0

相关:http://stackoverflow.com/questions/3140760/how-to-deserialize-and-cast-to-long-all-numbers – Bozho

+0

当心,你可能不反序列化的Javascript大长值完全相同,因为Javascript数字总是64位浮点(仅)52位尾数。 –

回答

7

如果类型被声明为java.lang.Object中,杰克逊使用其使用整数。如果值在32位配合“自然”映射。除了自定义处理程序之外,您还必须强制包含类型信息(通过在字段/ getter旁边添加@JsonTypeInfo;或者启用所谓的“default typing”)。

+0

这不是很令人满意的行为。这意味着,无论何时你反序列化一个无类型的数字,你都将不得不投它并调用longValue()或intValue()。如果杰克逊有办法强制所有的数字变长,那将是非常好的;至少行为是可以预测的。 – stickfigure

+0

@stickfigure这不会更好 - 请记住,JSON允许比64位更大的值,所以你仍然可以得到'BigInteger'(顺便说一句,有'DeserializationFeature.USE_BIG_INTEGER_FOR_INTS'来强制所有整数被转换为BigInteger)。但是,如果您想要任何特定的强制规则,您可能需要为'java.lang.Object'编写自定义反序列化器,并按您希望的方式100%获得规则 - 每个人都有自己的偏好。 – StaxMan

+4

虽然这在理论上可能是正确的,但在实践中并不常见。大多数Java应用程序不使用BigInteger,大多数Java应用程序对数字ID使用Long。这意味着,无论何时你经历一个无类型的情况(比如一个Map),你都需要编写像'((Number)map.get(“key”))。longValue()'的代码。如果您担心空值检查,代码会更乏味。我在杰克逊数据绑定git仓库中打开了一个功能请求。 – stickfigure

4

我结束了创建自定义解串器,因为在我的应用程序逻辑只有四种不同类型的值(DoubleLongIntegerString)。

我不确定这是否是最好的解决方案,但现在可行。

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()); 
    } 
} 
2

我已经使用类似下面的东西来解决这个问题。

@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(); 
     } 
    } 
}