Mor*_*sen 29 java json flickr jackson
我正在使用Flickr API.调用flickr.test.login方法时,默认的JSON结果是:
{
"user": {
"id": "21207597@N07",
"username": {
"_content": "jamalfanaian"
}
},
"stat": "ok"
}
Run Code Online (Sandbox Code Playgroud)
我想将此响应解析为Java对象:
public class FlickrAccount {
private String id;
private String username;
// ... getter & setter ...
}
Run Code Online (Sandbox Code Playgroud)
应该像这样映射JSON属性:
"user" -> "id" ==> FlickrAccount.id
"user" -> "username" -> "_content" ==> FlickrAccount.username
Run Code Online (Sandbox Code Playgroud)
不幸的是,我无法使用Annotations找到一个漂亮,优雅的方法.到目前为止,我的方法是将JSON字符串读入a Map<String, Object>并从那里获取值.
Map<String, Object> value = new ObjectMapper().readValue(response.getStream(),
new TypeReference<HashMap<String, Object>>() {
});
@SuppressWarnings( "unchecked" )
Map<String, Object> user = (Map<String, Object>) value.get("user");
String id = (String) user.get("id");
@SuppressWarnings( "unchecked" )
String username = (String) ((Map<String, Object>) user.get("username")).get("_content");
FlickrAccount account = new FlickrAccount();
account.setId(id);
account.setUsername(username);
Run Code Online (Sandbox Code Playgroud)
但我认为,这是迄今为止最不优雅的方式.有没有简单的方法,使用注释还是自定义反序列化器?
这对我来说非常明显,但当然它不起作用:
public class FlickrAccount {
@JsonProperty( "user.id" ) private String id;
@JsonProperty( "user.username._content" ) private String username;
// ... getter and setter ...
}
Run Code Online (Sandbox Code Playgroud)
Mic*_*ber 35
您可以为此类编写自定义反序列化程序.它可能看起来像这样:
class FlickrAccountJsonDeserializer extends JsonDeserializer<FlickrAccount> {
@Override
public FlickrAccount deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Root root = jp.readValueAs(Root.class);
FlickrAccount account = new FlickrAccount();
if (root != null && root.user != null) {
account.setId(root.user.id);
if (root.user.username != null) {
account.setUsername(root.user.username.content);
}
}
return account;
}
private static class Root {
public User user;
public String stat;
}
private static class User {
public String id;
public UserName username;
}
private static class UserName {
@JsonProperty("_content")
public String content;
}
}
Run Code Online (Sandbox Code Playgroud)
之后,您必须为您的类定义反序列化器.你可以这样做:
@JsonDeserialize(using = FlickrAccountJsonDeserializer.class)
class FlickrAccount {
...
}
Run Code Online (Sandbox Code Playgroud)
因为我不想实现自定义类(Username)只是为了映射用户名,所以我更优雅一点,但仍然是非常丑陋的方法:
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(in);
JsonNode user = node.get("user");
FlickrAccount account = new FlickrAccount();
account.setId(user.get("id").asText());
account.setUsername(user.get("username").get("_content").asText());
Run Code Online (Sandbox Code Playgroud)
它仍然没有我希望的那么优雅,但至少我摆脱了所有丑陋的演员.此解决方案的另一个优点是,我的域类(FlickrAccount)不会被任何Jackson注释污染.
基于@MichałZiober的回答,我决定使用 - 在我看来 - 最直接的解决方案.@JsonDeserialize在自定义反序列化器中使用注释:
@JsonDeserialize( using = FlickrAccountDeserializer.class )
public class FlickrAccount {
...
}
Run Code Online (Sandbox Code Playgroud)
但是反序列化器不使用任何内部类,只是JsonNode如上所述:
class FlickrAccountDeserializer extends JsonDeserializer<FlickrAccount> {
@Override
public FlickrAccount deserialize(JsonParser jp, DeserializationContext ctxt) throws
IOException, JsonProcessingException {
FlickrAccount account = new FlickrAccount();
JsonNode node = jp.readValueAsTree();
JsonNode user = node.get("user");
account.setId(user.get("id").asText());
account.setUsername(user.get("username").get("_content").asText());
return account;
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以使用 SimpleModule。
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
@Override public JsonDeserializer<?> modifyDeserializer(
DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (beanDesc.getBeanClass() == YourClass.class) {
return new YourClassDeserializer(deserializer);
}
return deserializer;
}});
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
objectMapper.readValue(json, classType);
Run Code Online (Sandbox Code Playgroud)
小智 5
我是这样做的:
public class FlickrAccount {
private String id;
@JsonDeserialize(converter = ContentConverter.class)
private String username;
private static class ContentConverter extends StdConverter<Map<String, String>, String> {
@Override
public String convert(Map<String, String> content) {
return content.get("_content"));
}
}
}
Run Code Online (Sandbox Code Playgroud)