2012-12-23 141 views
3

好的,首先這裏是從我的web服務返回的JSON。我試圖在我的Android ContentProvider中的ResponseHandler中進行異步查詢後將其反序列化爲pojos。傑克遜JSON反序列化MongoDB ObjectId

{"exampleList" : [{ 
"locationId" : "00001" , 
"owners" : [ 
    { 
    "paidID" : { "$oid" : "50a9c951300493f64fbffdb6"} , 
    "userID" : { "$oid" : "50a9c951300493f64fbffdb6"} 
    } , 
    { 
    "paidID" : { "$oid" : "50a9c951300493f64fbffdb7"} , 
    "userID" : { "$oid" : "50a9c951300493f64fbffdb7"} 
    } 
] 
}]} 

起初,我很困惑,我所看到的問題,因爲我用的是相同的傑克遜標註豆我的web服務,我在我的Android應用程序做的 - 但後來我意識到owners對象從來沒有發送過樣本JSON到我的Web服務(它跳過我的Web服務中的POJO,並通過DAO中的原子更新添加到mongoDB中的文檔中)。

好吧。截至目前,傑克遜不必處理owners對象,而現在它是被窒息在其上,即:

JsonMappingException:在[字符無法反序列化的實例java.lang.StringSTART_OBJECT令牌位置,你可以找到"userID""paidID"] 通過參考鏈[路徑到我的傑克遜豆含有業主類]

我的傑克遜Bean有一個包裝,這是「exampleList」是怎麼一回事:

public class Examples extends HashMap<String, ArrayList<Example>> { 

} 

然後實際Example類:

@JsonIgnoreProperties(ignoreUnknown = true) 
public class Example implements Comparable<Example> { 

@ObjectId @Id 
private String id; 

@JsonProperty(Constants.Example.location) 
private String location; 

@JsonProperty(Constants.Example.OWNERS) 
private List<Owners> owners; 

public int compareTo(Example _o) { 
    return getId().compareTo(_o.getId()); 
} 

public String getId() { 
    return id; 
} 

public void setId(String id) { 
    this.id = id; 
} 

public String getLocation() { 
    return location; 
} 

public void setLocation(String location) { 
    this.location = location; 
} 
public List<Example.Owners> getOwners() { 
    return owners; 
} 

public void setOwners(List<Example.Owners> owners) { 
    this.owners = owners; 
} 

public Example() { 
} 

@JsonCreator 
public Example(@Id @ObjectId String id) { 
    this.id = id; 
} 

@JsonIgnoreProperties(ignoreUnknown = true) 
public static class Owners implements Comparable<Owners> { 

    @JsonProperty(Constants.Example.USERID) 
    private String userID; 

    @JsonProperty(Constants.Example.PAIDID) 
    private String paidID; 

    public Owners() { 
    } 

    public int compareTo(Owners _o) { 
     return getUserID().compareTo(_o.getUserID()); 
    } 

    @ObjectId 
    public String getUserID() { 
     return userID; 
    } 

    @ObjectId 
    public void setUserID(String userID) { 
     this.userID = userID; 
    } 

    @ObjectId 
    public String getPaidID() { 
     return paidID; 
    } 

    @ObjectId 
    public void setPaidID(String paidID) { 
     this.paidID = paidID; 
    } 

} 

} 

最後,在對ResponseHandler的代碼中,這是所有失敗(2號線生產的JsonMappingException):

objectMapper = MongoJacksonMapperModule.configure(objectMapper);  
mExamples = objectMapper.readValue(jsonParser, Examples.class); 

我有一種感覺,問題是傑克遜仍然不知道如何映射那些是mongoDB ObjectIds的$oid。 MongoJacksonMapper庫應該可以通過提供@ObjectId註釋和一種配置ObjectMapper來使用該庫的方法來提供幫助,但它仍然不起作用。出於某種原因,它仍然在尋找userID或paidID作爲字符串,而不是ObjectId。有任何想法嗎?

回答

2

我的代碼至少有兩個問題很難找到在線答案,所以我會確保鏈接到這裏。基本上,子類需要父類中的構造函數來調用Jackson的readValue()來映射孩子。至於mongoDB $ oid的去,你應該創建一個單獨的MongoId類來表示這些mongo對象,並遵循與子類類似的模式來映射數據進行反序列化時。 Here's a blog post我發現描述得很好,並提供了一些例子。

2

還有一個更簡單的方法documented here這對我來說是一個救生員。現在,您可以在Java中使用ObjectId,但是當您從/到JSON時,它將是一個String。

public class ObjectIdJsonSerializer extends JsonSerializer<ObjectId> { 
    @Override 
    public void serialize(ObjectId o, JsonGenerator j, SerializerProvider s) throws IOException, JsonProcessingException { 
     if(o == null) { 
      j.writeNull(); 
     } else { 
      j.writeString(o.toString()); 
     } 
    } 
} 

,然後在豆類:

@JsonSerialize(using=ObjectIdJsonSerializer.class) 
private ObjectId id; 
10

另一種選擇是 com.fasterxml.jackson.databind.ser.std.ToStringSerializer

@Id 
@JsonSerialize(using = ToStringSerializer.class) 
private final ObjectId id; 

這將導致:

{ 
    "id": "5489f420c8306b6ac8d33897" 
} 
+0

問題是關於反序列化,系列化沒有。這個答案應該被下調。 – Arny

1

對於未來的用戶:使用自定義傑克遜解串器轉換$ OID返回的ObjectId。

public class ObjectIdDeserializer extends JsonDeserializer<ObjectId> { 

    @Override 
    public ObjectId deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
     JsonNode oid = ((JsonNode)p.readValueAsTree()).get("$oid"); 
     return new ObjectId(oid.asText()); 
    } 

} 

如何使用:

ObjectMapper mapper = new ObjectMapper(); 
SimpleModule mod = new SimpleModule("ObjectId", new Version(1, 0, 0, null, null, null)); 

mod.addDeserializer(ObjectId.class, new ObjectIdDeserializer()); 
registerModule(mod); 

YourClass obj = mapper.readValue("{your json with $oid}", YourClass.class); 
+0

也可以用'@JsonDeserialize(using = ObjectIdDeserializer.class)'來註釋該字段' –

0

傑克遜不知道如何序列化的ObjectId。我阿尼扭捏的代碼序列化任何的ObjectId,並提供這方面的工作例如:

public class SerialiserTest { 

private ObjectMapper mapper = new ObjectMapper(); 

public static class T { 
    private ObjectId objectId; 

    public ObjectId getObjectId() { 
     return objectId; 
    } 

    public void setObjectId(ObjectId objectId) { 
     this.objectId = objectId; 
    } 
} 

@Test 
public final void serDeser() throws IOException { 
    T t = new T(); 
    t.setObjectId(new ObjectId()); 
    List<T> ls = Collections.singletonList(t); 
    String json = mapper.writeValueAsString(ls); 
    System.out.println(json); 
    SimpleModule mod = new SimpleModule("ObjectId", new Version(1, 0, 0, null, null, null)); 
    mod.addDeserializer(ObjectId.class, new ObjectIdDeserializer()); 
    mapper.registerModule(mod); 
    JavaType type = mapper.getTypeFactory(). 
      constructCollectionType(List.class, T.class); 
    List<?> l = mapper.readValue(json, type); 
    System.out.println(l); 
} 
} 

public class ObjectIdDeserializer extends JsonDeserializer<ObjectId> { 

@Override 
public ObjectId deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
    JsonNode n = (JsonNode)p.readValueAsTree(); 
    return new ObjectId(n.get("timestamp").asInt(), n.get("machineIdentifier").asInt(), (short) n.get("processIdentifier").asInt(), n.get("counter").asInt()); 
} 

}