我正在尝试使用 Jersey 对 Facebook 运行批量请求。问题是 Facebook 返回了最奇怪的结构 - JSONObject 和 JSONString 的混合:
[
{
"code": 200,
"headers": [
{
"name": "Access-Control-Allow-Origin",
"value": "*"
},
<!-- some more headers... -->
],
"body": "{\n \"message\": \"Hello World!\",\n \"id\": \"...\",\n \"created_time\": \"2012-10-17T07:18:02+0000\"\n
<!-- ... -->
}"
}
]
现在,当我尝试使用 Jackson ObjectMapper
反序列化这个困惑的情况时,我得到了
JsonMappingException: Can not instantiate value of type [simple type, class package.to.Post] from JSON String; no single-String constructor/factory method (through reference chain: package.to.BatchResult["body"])
这是我正在使用的 POJO 结构:
public class BatchResult<T> {
private T body;
private int code;
private List<BatchResultHeader> headers;
// ...
}
public class BatchResultHeader {
private String name;
private String value;
// ...
}
public class Post {
private String message;
// ...
}
我像这样发送批量请求。 Params 包含文档中定义的批处理参数和批处理请求。还需要对批量请求进行 POST 调用。就像我说的那样,调用应该没问题,因为生成的 JSON 符合预期(见上文):
Client client = Client.create();
WebResource webResource = client.resource("https://graph.facebook.com");
ClientResponse response = webResource.type("application/x-www-form-urlencoded")
.post(ClientResponse.class, params);
String json = response.getEntity(String.class);
现在我只需使用ObjectMapper
来反序列化:
TypeReference<List<BatchResult<Post>>> ref = new TypeReference<List<BatchResult<Post>>>(){});
ObjectMapper mapper = new ObjectMapper();
List<BatchResult<Post>> batchResults = mapper.readValue(json, ref);
使用@JsonCreator?
因此,当搜索此异常时,我发现建议将 @JsonCreator
注释与我的 Post
构造函数一起使用。然而,这会导致
java.lang.IllegalArgumentException: Argument #0 of constructor [constructor for package.to.Post, annotations: {interface org.codehaus.jackson.annotate.JsonCreator=@org.codehaus.jackson.annotate.JsonCreator()}] has no property name annotation; must have name when multiple-paramater constructor annotated as Creator
这个问题的解决方案似乎是单独注释 POJO 的每个属性,这就是我说的要点:不,谢谢,当然不是!
所以问题仍然存在:有没有办法通过 ObjectMapper 设置来反序列化这种混合?
或者我可以告诉 Jersey 过滤传入的格式化字符串并剪切所有空格,然后再将其发送给 Jackson 进行反序列化?
我不满意的解决方法:
当我告诉我的 BatchResult
类 body
是一个 String
时,它起作用了,我得到了一个带有 String< 的 BatchResult/
正文
。现在,在该 String
body
上再次使用 ObjectMapper
以及正确反序列化的 Post.class
类型。这是我当前的解决方案,但它看起来很困惑,迭代反序列化结果以反序列化其元素不应该是我的工作......为什么 jackson 不能自己解决这个问题?
最佳答案
只是将正文作为帖子
如果您不想反序列化正文,那么您只需为 Post 对象提供一个采用字符串类型的构造函数即可:
public class Post {
public Post( String message ) {
this.message = message;
}
private String message;
// ...
}
将正文解码为帖子
如果您想使用字符串中包含的 JSON 填充 Post 对象,则可以使用 JsonDeserializer。首先,您需要定义一个反序列化器来读取字符串值,然后对其进行解码。这是一个示例实现:
import java.io.IOException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.ObjectCodec;
import org.codehaus.jackson.map.BeanProperty;
import org.codehaus.jackson.map.ContextualDeserializer;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectReader;
public class EmbeddedJsonDeserializer
extends JsonDeserializer<Object>
implements ContextualDeserializer<Object>
{
Class<?> type = null;
public EmbeddedJsonDeserializer() {
}
public EmbeddedJsonDeserializer( Class<?> type ) {
this.type = type;
}
@Override
public Object deserialize(JsonParser parser, DeserializationContext context)
throws IOException, JsonProcessingException {
JsonToken curr = parser.getCurrentToken();
if (curr == JsonToken.VALUE_STRING) {
if( type == null ) return parser.getText();
ObjectCodec codec = parser.getCodec();
if( codec == null ) {
return new ObjectMapper().readValue(parser.getText(), type);
}
else if( codec instanceof ObjectMapper ) {
return ((ObjectMapper)codec).readValue(parser.getText(), type);
}
else if( codec instanceof ObjectReader ) {
return ((ObjectReader)codec).withType(type).readValue(parser.getText());
}
else {
return new ObjectMapper().readValue(parser.getText(), type);
}
}
throw context.mappingException(type);
}
public JsonDeserializer<Object> createContextual(DeserializationConfig config, BeanProperty property) throws JsonMappingException {
return new EmbeddedJsonDeserializer(property.getType().getRawClass());
}
}
然后需要在body字段中添加@JsonDeserialize注解,指定要使用的反序列化器:
public class BatchResult<T> {
@JsonDeserialize(using=EmbeddedJsonDeserializer.class)
private T body;
...
您现在应该能够将嵌入的 JSON 嵌入到您的 Post 对象中。
关于java - 转换包含嵌套 JSONString 的 JSONObject 时出现 JsonMappingException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13108053/