2012-12-23 142 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()); 
} 

}