Jackson JSON反序列化MongoDB ObjectId

Mat*_*t M 4 json jackson mongo-jackson-mapper

好的,首先,这是从我的Web服务返回的JSON.我试图在Android ContentProvider中的ResponseHandler中进行异步查询后将其反序列化为pojos.

{"exampleList" : [{
"locationId" : "00001" , 
"owners" : [ 
  { 
    "paidID" : { "$oid" : "50a9c951300493f64fbffdb6"} , 
    "userID" : { "$oid" : "50a9c951300493f64fbffdb6"}
  } , 
  { 
    "paidID" : { "$oid" : "50a9c951300493f64fbffdb7"} , 
    "userID" : { "$oid" : "50a9c951300493f64fbffdb7"}
  } 
]
}]}
Run Code Online (Sandbox Code Playgroud)

起初,我对我看到的问题感到困惑,因为我在我的Android应用程序中使用与我的Web服务相同的Jackson注释bean - 但后来我意识到该owners对象永远不会在示例JSON中发送到我的Web服务(它跳过我的Web服务上的POJO并通过DAO的原子更新添加到mongoDB中的文档中).

那么好吧.到目前为止,杰克逊不必处理这个owners对象,现在它正在窒息,即:

JsonMappingException:无法反序列化的情况下java.lang.String进行的 START_OBJECT,在[字符位置,你可以找到令牌"userID",并"paidID"通过参考链] [路径到我的杰克逊豆含有车主类]

我的Jackson bean有一个包装器,这就是"exampleList"的全部内容:

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

}
Run Code Online (Sandbox Code Playgroud)

然后是实际的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;
    }

}

}
Run Code Online (Sandbox Code Playgroud)

最后,ResponseHandler中的代码全部失败(第二行产生JsonMappingException):

objectMapper = MongoJacksonMapperModule.configure(objectMapper);    
mExamples = objectMapper.readValue(jsonParser, Examples.class);
Run Code Online (Sandbox Code Playgroud)

我有一种感觉,问题是杰克逊仍然不知道如何映射那些$oid,即mongoDB ObjectIds.MongoJacksonMapper库应该通过提供@ObjectId注释和配置ObjectMapper以使用该库的方式来帮助它,但它仍然无法正常工作.出于某种原因,它仍然在寻找userID或paidID作为String,而不是ObjectId.有任何想法吗?

wbi*_*ler 15

另一种选择是 com.fasterxml.jackson.databind.ser.std.ToStringSerializer.

@Id
@JsonSerialize(using = ToStringSerializer.class)
private final ObjectId id;
Run Code Online (Sandbox Code Playgroud)

这将导致:

{
  "id": "5489f420c8306b6ac8d33897"
}
Run Code Online (Sandbox Code Playgroud)

  • 问题是关于反序列化,而不是序列化。这个答案应该被否决。 (3认同)

Arn*_*rny 6

对于未来的用户:使用自定义的 jackson 反序列化器将 $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());
    }

}
Run Code Online (Sandbox Code Playgroud)

如何使用:

ObjectMapper mapper = new ObjectMapper();
SimpleModule mod = new SimpleModule("ObjectId", new Version(1, 0, 0, null, null, null));
        
mod.addDeserializer(ObjectId.class, new ObjectIdDeserializer());
mapper.registerModule(mod);

YourClass obj = mapper.readValue("{your json with $oid}", YourClass.class);
Run Code Online (Sandbox Code Playgroud)


Mat*_*t M 2

我的代码至少有两个问题很难在网上找到答案,所以我会确保链接到这里。基本上,子类需要父类中的构造函数来调用 Jackson 的 readValue() 来映射子类。就 mongoDB $oid 而言,您应该创建一个单独的 MongoId 类来表示这些 mongo 对象,并遵循与子类类似的模式来在数据进行反序列化时映射数据。这是我发现的一篇博客文章,很好地描述了这一点并提供了一些示例。