Reputation: 3391
This is the json response returned by MediaWiki API. I want to create a class to be able to deserialize it to it use Jackson library. The problem is that this json contains a key which is different from each request (here is 290).
{
"query-continue": {
"revisions": {
"rvcontinue": 633308090
}
},
"query": {
"pages": {
"290": {
"pageid": 290,
"ns": 0,
"title": "A",
"revisions": [
{
"user": "Mr. Guye",
"timestamp": "2014-12-07T17:45:55Z",
"comment": "comment",
"contentformat": "text/x-wiki",
"contentmodel": "wikitext",
"*": "content"
}
]
}
}
}
}
How could create a class (or configure the mapper) to be able to deserialize this json?
Upvotes: 1
Views: 493
Reputation: 1911
This works for me:
For content:
...
"gameName": {
"*": "Rabbit Rabbit Rabbit"
}
...
I can deserialise it with:
public class Foo {
...
@JsonProperty("*")
private String gameName;
// getters and setters
}
and an ObjectMapper like so:
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
...
Foo foo = objectMapper.readValue(json, Foo.class);
Upvotes: 0
Reputation: 67
This looks like key value pair. You can use map in order to deserialize key value pairs:
public class Query {
private Map<Integer, Page> pages;
public Map<Integer, Page> getPages() {
return pages;
}
public void setPages(Map<Integer, Page> pages) {
this.pages = pages;
}
}
Jackson handles such deserialization by default.
Upvotes: -1
Reputation: 19221
You can deserialize JSON to multiple formats using Jackson. One way that you mentioned is to convert the JSON to a POJO which may be difficult when the keys are dynamic. Another approach is to deserialize the JSON to the Jackson Tree Model which is called JsonNode
. The following illustrates how you can parse the provided JSON to a JsonNode
and then retrieve the various attributes.
final ObjectMapper mapper = new ObjectMapper();
// Parse the JSON, deserialize to the Tree Model
final JsonNode jsonNode = mapper.readTree(jsonString);
// Get hold of the "query -> pages" node.
final JsonNode pages = jsonNode.path("query").path("pages");
// Iterate the pages
for (final JsonNode page : pages) {
// Work with the page object here...
System.out.println(page.get("pageid")); // -> 290
}
The JsonNode
object is very flexible and contains various convenience functions for accessing the data. As shown in the example above the path()
and get()
methods are two ways of accessing the data. If you use get()
the property MUST exist, if you use path
the property MAY exist. Furthermore, there are multiple ways of iterating the sub-elements and the loop shown above is one way.
Take a look at the Jackson docs for more info.
Upvotes: 2
Reputation: 416
The short answer is you can't, at least not in the current format with that abominable asterisk being present. Therefore, we will have to employ a bit of hackery here to get the job done, and I warn you upfront, it's not going to be pretty.
Firstly, copy that response, then go to http://www.jsonschema2pojo.org/ and paste it into the JSON textbox. After pasting it, change the asterisk to something more civilized, like "content". Select JSON (default is JSON Schema) for the Source Type, input your package and root class name respectively, and click JAR to generate the package with all the POJO's that map to this JSON. You could also click "Preview" and copy paste the code into your source files -- it's really up to you.
Now that we have a valid version of this JSON structure, we use Jackson to read it in. If your JSON String is called jsonResponse and the corresponding POJO class is MediaWiki, then you convert it with Jackson like this:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MediaWiki mw = objectMapper.readValue(profileJson, MediaWiki.class);
The key here is the FAIL_ON_UNKNOWN_PROPERTIES being set to false, which means it will ignore that asterisk, and create everything else for you.
Now, to actually grab whatever value was present for that asterisk and store it into our "content" attribute (or whatever else you wanted replace the asterisk with), you are going to have to parse this sucker out client-side and pass it as a separate input parameter, and to do that, you will have to yank it out by calling something like this:
var content = query.pages.290.revisions["*"];
This content parameter is passed and stored it into your POJO's content attribute.
I know it's a lot of work, and if anyone else has a more elegant solution, please share. As I said, mine was not going to be pretty. :-)
Upvotes: 0