I'm using the Flickr API. When calling the flickr.test.login
method, the default JSON result is:
{
"user": {
"id": "21207597@N07",
"username": {
"_content": "jamalfanaian"
}
},
"stat": "ok"
}
I'd like to parse this response into a Java object:
public class FlickrAccount {
private String id;
private String username;
// ... getter & setter ...
}
The JSON properties should be mapped like this:
"user" -> "id" ==> FlickrAccount.id
"user" -> "username" -> "_content" ==> FlickrAccount.username
Unfortunately, I'm not able to find a nice, elegant way to do this using Annotations. My approach so far is, to read the JSON String into a Map<String, Object>
and get the values from there.
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);
But I think, this is the most non-elegant way, ever. Is there any simple way, either using Annotations or a custom Deserializer?
This would be very obvious for me, but of course it doesn't work:
public class FlickrAccount {
@JsonProperty( "user.id" ) private String id;
@JsonProperty( "user.username._content" ) private String username;
// ... getter and setter ...
}
How to deserialize Date from JSON using Jackson. In order to correct deserialize a Date field, you need to do two things: 1) Create a custom deserializer by extending StdDeserializer<T> class and override its deserialize(JsonParser jsonparser, DeserializationContext context) method.
Jackson is a powerful and efficient Java library that handles the serialization and deserialization of Java objects and their JSON representations. It's one of the most widely used libraries for this task, and runs under the hood of many other frameworks.
You can write custom deserializer for this class. It could look like this:
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;
}
}
After that, you have to define a deserializer for your class. You can do this as follows:
@JsonDeserialize(using = FlickrAccountJsonDeserializer.class)
class FlickrAccount {
...
}
Since I don't want to implement a custom class (Username
) just to map the username, I went with a little bit more elegant, but still quite ugly approach:
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());
It's still not as elegant as I hoped, but at least I got rid of all the ugly casting.
Another advantage of this solution is, that my domain class (FlickrAccount
) is not polluted with any Jackson annotations.
Based on @Michał Ziober's answer, I decided to use the - in my opinion - most straight forward solution. Using a @JsonDeserialize
annotation with a custom deserializer:
@JsonDeserialize( using = FlickrAccountDeserializer.class )
public class FlickrAccount {
...
}
But the deserializer does not use any internal classes, just the JsonNode
as above:
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With