2011-09-06 18 views
10

Tôi serializing và deserializing sau đối tượng miền để JSON sử dụng Jackson 1.8.3Buộc Jackson để deserialize để nguyên thủy loại hình cụ thể

public class Node { 
    private String key; 
    private Object value; 
    private List<Node> children = new ArrayList<Node>(); 
    /* getters and setters omitted for brevity */ 
} 

Object là sau đó serialized và deserialized sử dụng đoạn mã sau

ObjectMapper mapper = new ObjectMapper(); 
mapper.writeValue(destination, rootNode); 

Và sau đó được deserialized với

mapper.readValue(destination, Node.class); 

Giá trị ban đầu của đối tượng hoặc là Strings, Doubles, Longs hoặc Booleans. Tuy nhiên, trong quá trình tuần tự hóa và deserialization, Jackson biến đổi các giá trị Long (như 4) thành Số nguyên.

Làm cách nào để "buộc" Jackson bỏ qua các giá trị số thập phân sang Long thay vì Số nguyên?

+0

liên quan: http://stackoverflow.com/questions/3140760/how-to-deserialize-and-cast-to-long-all-numbers – Bozho

+0

Hãy coi chừng rằng bạn có thể không deserialize một giá trị lớn dài trong Javascript chính xác, bởi vì số Javascript luôn là điểm nổi 64bit với (chỉ) 52 bit mantissa. –

Trả lời

7

Nếu loại được khai báo là java.lang.Object, Jackson sử dụng ánh xạ 'tự nhiên' sử dụng số nguyên nếu giá trị khớp với 32 bit. Ngoài các trình xử lý tùy chỉnh, bạn sẽ phải ép buộc bao gồm thông tin kiểu (hoặc bằng cách thêm @JsonTypeInfo bên cạnh trường/getter; hoặc bằng cách bật cái gọi là "gõ mặc định").

+0

Đây không phải là hành vi rất thỏa mãn. Nó có nghĩa là bất cứ khi nào bạn deserialize một số untyped bạn sẽ luôn luôn phải đúc nó và gọi longValue() hoặc intValue(). Sẽ thật tuyệt nếu Jackson có cách để ép buộc mọi con số thành Long; ít nhất là hành vi sẽ có thể dự đoán được. – stickfigure

+0

@stickfigure Điều đó sẽ không tốt hơn nhiều - hãy nhớ rằng JSON cho phép các giá trị lớn hơn 64 bit giữ, vì vậy bạn vẫn có thể nhận được 'BigInteger' (ngẫu nhiên, có' DeserializationFeature.USE_BIG_INTEGER_FOR_INTS' để buộc tất cả các số nguyên được chuyển đổi thành 'BigInteger'). Nhưng nếu bạn muốn có bất kỳ quy tắc cưỡng chế cụ thể nào, bạn có thể muốn viết deserializer tùy chỉnh cho 'java.lang.Object' và nhận các quy tắc 100% theo cách bạn muốn - mọi người đều có sở thích riêng của họ. – StaxMan

+4

Trong khi đó có thể về mặt lý thuyết, nó là không phổ biến trong thực tế.Hầu hết các ứng dụng Java không sử dụng BigInteger và hầu hết các ứng dụng Java đều sử dụng Long cho các id số. Có nghĩa là bất cứ lúc nào bạn đi qua một tình huống không được phân loại (nói một Bản đồ) bạn cần viết mã như '((Số) map.get (" khóa ")). LongValue()'. Nếu bạn quan tâm đến việc kiểm tra null, mã này thậm chí còn tẻ nhạt hơn. Tôi đã mở một yêu cầu tính năng trong kho dữ liệu jackson git repo. – stickfigure

4

Tôi đã kết thúc tạo trình tùy chỉnh deserializer, vì trong logic ứng dụng của tôi chỉ có bốn loại giá trị khác nhau (Double, Long, IntegerString).

Tôi không chắc liệu đây có phải là giải pháp tốt nhất có thể hay không nhưng hiện tại nó vẫn hoạt động.

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

Tôi đã sử dụng một cái gì đó giống như bên dưới để khắc phục sự cố này.

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

Có một tính năng mới trong Jackson 2,6 đặc biệt cho trường hợp này:

cấu hình các ObjectMapper sử dụng DeserializationFeature.USE_LONG_FOR_INTS

thấy https://github.com/FasterXML/jackson-databind/issues/504

cowtowncoder đẩy một cam kết rằng đóng vấn đề này vào ngày 19 tháng 5 năm 2015 Khắc phụC# 504 và # 797

Các vấn đề liên quan