How to convert arbitrary JSON into a usable structure in Java - java

I'm trying to use gson to convert this returned JSON into some kind of
data structure such that I can extract useful data.
For Example:
http://search.twitter.com/search.json?q=test&rpp=1
Returns:
{
"completed_in":0.028,
"max_id":196386333906837504,
"max_id_str":"196386333906837504",
"next_page":"?page=2&max_id=196386333906837504&q=test&rpp=1",
"page":1,
"query":"test",
"refresh_url":"?since_id=196386333906837504&q=test",
"results":[
{
"created_at":"Sat, 28 Apr 2012 23:52:05 +0000",
"from_user":"della_ky",
"from_user_id":525641596,
"from_user_id_str":"525641596",
"from_user_name":"kydella modeste",
"geo":null,
"id":196386333906837504,
"id_str":"196386333906837504",
"iso_language_code":"en",
"metadata":{
"result_type":"recent"
},
"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2159990525\/webcam-toy-photo3_20_2__normal.jpg",
"profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2159990525\/webcam-toy-photo3_20_2__normal.jpg",
"source":"<a href="http:\/\/mobile.twitter.com" rel="nofollow">Mobile Web<\/a>",
"text":"RT #Y__U__NOOO: #SongsIKnowOffByHeart ALL SONGS I LISTEN TO. BRAIN, Y U NO REMEMBER TEST ANSWERS LIKE THAT?!?",
"to_user":null,
"to_user_id":null,
"to_user_id_str":null,
"to_user_name":null
}
],
"results_per_page":1,
"since_id":0,
"since_id_str":"0"
}
Ultimately, I would like to be able to output a list of tweets with the
name of the sender and the date/time of the tweet.
I have read through the gson documentation but it's going over my head
to be honest - lots of new concepts there for me.
Do I need to define a class which maps exactly to the structure of the
JSON in order to then populate an instance of that class? If so this
seems very inflexible/laborious. Ideally I'm looking for something
which will handle JSON in any form and give me a structure I can use
automatically...
Is anyone able to give me some pointers? Being new to this - the more
detailed and in words of the fewest syllables the better!
Update - Thanks to the responses I've already had on this I've had a go at putting a class together to capture the twitter JSON. However, since the JSON has an embedded ArrayList of Objects I'm struggling a bit... So far I have
public class tweetData {
private double completed_in;
private long max_id;
private long max_id_str;
private String next_page;
private int page;
private String query;
private String refresh_url;
private List<tweetDetails> tweets = new ArrayList<tweetDetails>();
}
and
public class tweetDetails {
private String created_at;
private String from_user;
private long from_user_id;
private long from_user_id_str;
private String from_user_name;
private String geo;
private long id;
private long id_str;
private String iso_language_code;
// "metadata":
// {
// "result_type":"recent"
// },
private String profile_image_url;
private String profile_image_url_https;
private String source;
private String text;
private String to_user;
private String to_user_id;
private String to_user_id_str;
private String to_user_name;
}
Which I'm instantiating with
URI uri = new URI("http", "search.twitter.com", "/search.json", "q="+ searchTerms + "&rrp=" + RRP, null);
URL twitterSearch = uri.toURL();
URLConnection yc = twitterSearch.openConnection();
JsonReader reader = new JsonReader(new InputStreamReader(yc.getInputStream()));
Gson gson = new Gson();
tweetData data = gson.fromJson(reader, tweetData.class);
System.out.println(data);
The basic name:values are being populated correctly but the ArrayList is not.
tweetData : 0.17196614959919140865196614959919140865?page=2&max_id=196614959919140865&q=test1test?since_id=196614959919140865&q=testSIZE 0[]
So, I'm still struggling a bit - any more tips hugely appreciated!
Tia,
Tom

Do I need to define a class which maps exactly to the structure of the JSON in order to then populate an instance of that class? If so this seems very inflexible/laborious.
Yes. GSON is a library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. This is really powerful because you can automagically instantiate your Java objects from the JSON representation. Assuming your JSON doesn't change its structure, you only have to define the appropriate Java object representation once.
Ideally I'm looking for something which will handle JSON in any form and give me a structure I can use automatically...
However, if you don't want automagical serialisation/deserialisation, then try looking at a simpler library such as java.net/projects/jsonp.
You can extract stuff from it just by querying the keys:
final JSONObject json = new JSONObject(theJsonString);
final String id = json.getString("max_id");
final JSONArray results = json.getJSONArray("results");
final String user = results.getJSONObject(2).getString("from_user");

Gson actually does all the serialization for you. So yes, you would have to write the classes yourself. To you, this seams inflexible and laborious, but that's only because that library isn't made for what you're asking for (it doesn't parse 'arbitrary' JSON).
I would suggest at least considering writing the classes and using gson. The reason I say that is because either way your application's logic will have to expect a very specific format, and writing out that format in a Java class will make things tidier. Here's a nice guide that will help you get started that way.
If you want to simply decode the JSON without serializing it into a Java class (IMHO the only way to use 'arbitrary' JSON), you'll want to use another library. Try this one. It allows you to decode the JSON, and use it by getting values from it (as described in this question: Convert a JSON string to object in Java ME?).

There are some tools that do gson to schema mapping. You give some sample JSON responses, and the java classes to access them are created for you.
http://www.jsonschema2pojo.org/

Gson is a slick beast!
Or at least it became so over the years that have passed since the question had been asked.
You can pass it an Object.class as a second parameter to the fromJson() method and it will parse your Json into a reasonable structure of LinkedTreeMaps and ArrayLists.
Object result = (new Gson()).fromJson(jsonString, Object.class)
More than that, you can really do partial parsing and leave loose ends at any level of your object structure by defining a certain field as Object!
Gson will then parse Json into your structure and your field of type Object will contain the above mentioned structure of LinkedTreeMaps and ArrayLists.
E.g., you may define a class
Person {
String name;
Object details;
}
(Imagine, you care mostly about the person's name but may want the details also somewhere. To log them, for instance.)
Then you can pass the following Json to the fromJson(input, Person.class) method as a first parameter
{
"name": "Carlsson",
"details": {
"address": "Stockholm",
"phones": [
"work": "233-322-233-322",
"home": "none"
]
}
}
The result will have the name field filled with "Carlsson" string and details field will contain a LinkedTreeMap with keys "address" and "phones", etc.

Related

How get just one value from json as string

I have following json as string:
{
"field1":"value1",
"field2":"value2",
"field3":{
"field31":"value31",
"field32":"value32"
},
"field4":{
"field41":"value41"
}
}
What is the best and the most modern way to get from this json just value from field41, so I would return "value41". I know that I can use JSONObject but I'm wondering weather we have any other better option?
Try JSONPath
String json = "...";
String field41 = JsonPath.read(json, "$.field4.field41");
You can test it here - https://jsonpath.herokuapp.com/
If you want to generate a real object out of it you can use Gson. You need to describe the class first. There are online json to Java objects converters out there. And then you can just call:
YourObject obj = new Gson().fromJson(json,YourObject.class);
System.out.println(obj.getField4().getField41());
And there you have it!

How extract the first element of a JsonArray that is an Integer and the other are JsonElements?

I'm on a Java Spring Boot project that makes API requests using RestTemplates.
Trying to implement pagination, makes the new JsonArray incoming has as first element an Integer and the rest are JsonElements.
Without pagination the value of the json incoming is:
[
{
"id":1234,
"name": null,
"...":...
},...
]
And these objects with their getter and setters correctly implented. p.d I don't need all the attributes of the incoming jsonelement.
public class WorkListBean extends WorkBean{
private List<WorkBean> lsWorkBean;
}
public class WorkBean implements Serializable {
private static final long serialVersionUID = -...L;
private long id;
private String name;
}
This returns WorkListBean[] to the client and works pretty well.
But with pagination implemented the incoming json is like this:
[
1,
{
"id":1234,
"name": null
},...
]
How could I extract this first Integer of the array?
I think maybe I could use a Deserializer with a Object Mapper to make a custom object that owns a Integer and a list or array of WorkBean. But I'm a little bit lost with this terms. Can anyone confirm am pointing in a good view?
Thanks in advance,
Grettings LaGallinaturuleta
That's a badly designed schema. Allthough it's technically allowed, putting elements of different types in the same array will make every client suffer.
If you can change the server side you're talking to, they should use a more user-friendly schema, like this:
{
"pageNumber":0,
"size":5,
"totalPages":4,
"content":[
{"studentId":"1","name":"Bryan","gender":"Male","age":20},
{"studentId":"2","name":"Ben","gender":"Male","age":22},
{"studentId":"3","name":"Lisa","gender":"Female","age":24},
{"studentId":"4","name":"Sarah","gender":"Female","age":26},
{"studentId":"5","name":"Jay","gender":"Male","age":20}
],
}
If not, you're going to need a custom deserializer indeed.

How to convert flat key-value file to a bean object dynamically?

I'd like to convert a flat file with many different keys to a java bean dto, as follows:
Flat file:
mykey=example
anotherkey=test
adress-street-1=downtown street
address-town-1=nyc
address-stree-2=some street
adrerss-town-2=los angeles
Target bean:
public class Content {
private String mykey;
private String anotherkey;
private List<Address> address;
}
public class Address {
private String street,
private String town;
}
Question: how could I achieve the mapping between the flat file and the target bean? Imagine a few hundred property keys. Some may occur multiple times, in whose cases they and with an index number, like address-town-1.
Content content = new Content();
while(true) {
String line = reader.readLine();
String key = line.split("=")[0];
String value = line.split("=")[1];
switch(key) {
case "mykey": content.setMykey(value);
case "anotherkey": content.setAnotherkey(value);
...
}
}
But I would have to code those mappings a few hundred times, which does not feel right.
Question: is there a better way, eg by using some kind of xml configuration/mapping file, and reflection?
BeanIO comes close to what I want to achieve. But it lacks the ability to just convert multiple different fields to the bean field name. And also it cannot group sets like the address-* example into a List.
Is there any known library or concept that I could use? Some framework that could do the formatting, using eg a xml configuration file?
Or would I have to write my own parser and use reflection to write the data to my java objects?

Parsing complex nested JSON data with Gson

I'm using Gson to parse a JSON string. I want to convert this to an object using a container class and embedded static classes. To some extent this has been possible, but I want to treat the content of stuff1 and stuff2 as arrays, for example, stuff1 is an array containing other_stuff1 and other_stuff2. This is so I can reference the object in a fashion like these: object.integer, object.stuff1.get("other_stuff1").name, or object.stuff2.get("other_stuff3").more. (for the last one, I could be interested in looping over more to get each item.
For example, in PHP, I would use this:
<?php
echo "<pre>";
$object = json_decode(file_get_contents("THE JSON FILENAME"));
foreach($object->stuff1 as $name=>$data) {
echo $name . ":\n"; // other_stuff1 or other_stuff2
echo $unlockable->description . "\n\n"; // Got lots of stuff or Got even more stuff.
}
?>
I want to be able to reference in a similar way, loading the JSON to an object to be used on the fly.
It is crucial that, while some degree of change can be made to the JSON, that the names of the elements remain and be referable and retrievable.
I've included JSON, very similar to the one I'm using, below.
{
"integer":"12345",
"stuff1":{
"other_stuff1":{
"name":"a_name",
"description":"Got lots of stuff.",
"boolean":false
},
"other_stuff2":{
"name":"another_name",
"description":"Got even more stuff",
"boolean":true
}
},
"stuff2":{
"other_stuff3":{
"name":"a_name",
"description":"Got even more stuff",
"boolean":false,
"more":{
"option1":{
"name":"hello"
},
"option2":{
"name":"goodbye"
}
}
},
}
}
I've gone through a number of reference guides and tutorials, and I can't find a way to interpret this the way I'm trying to.
I'd really appreciate it if someone could give me a pointer. I can't find any tutorials that take into account that a) I want multiple objects in an array-style list, referable by the IDs (like with other_stuff1 and other_stuff2), and b) I want to also be able to loop over the items without providing the IDs.
You should define a Java class with fields named after the keys you need. You can use Maps (not arrays) to get the .get("key") behavior you describe. For example:
class Container {
private final int integer;
private final HashMap<String, Stuff> stuff1;
private final HashMap<String, Stuff> stuff2;
}
class Stuff {
private final String name;
private final String description;
#SerializedName("boolean") private final boolean bool;
private final HashMap<String, Option> more;
}
class Option {
private final String name;
}
For the "boolean" field you need need to use a different variable name since boolean is a reserved keyword.
You can then do:
Container c = gson.fromJson(jsonString, Container.class);
for(Stuff s : c.getStuff1().values()) {
System.out.println(s.getName());
}

getting the values of array from javascript to java as list

var catids = new Array();
I have a catids array where i store the checked checkbox values like the below one.
cat = $("input[name=catChkBox]:checked").map(function () {
return $(this).data('name');
}).get().join(",");
the cat variable forms something like this 1,2,3..
I want to send this "cat" to a java method and print those values.
I pass the values to java through a dwr call like this
DataHandler.getTasks( categories, {callback:function(data){
}, errorHandler:function(){
},async:false
});
I have configured dwr for pojo. should I configure anything for parameters?
I tried the below code but I didn't get anything.
public List<Facade> getTasks(String myIds){
String[] ids = catids .split(",");
System.out.println("-------size of cat id------------" + myIds.length);
for (int i=0; i<myIds.length;i++)
System.out.println(myIds[i]);
//finally it will return a pojo which i l be receiving it in data of dwr call.
-------size of cat id------------ is 1
myIds[i] prints nothing
I need it as an integer back.
What mistake am I doing ?
I will do it in this way.
JavaScript creates json object like this {"categoryIds": [1,2,3,4,5]}
Java converter convert json to java POJO object using for example Gson or Jackson library.
After convert you can work with java POJO object which have list of categories.
If you use this solution your code will be more clear and you will be able to share more objects between JavaScript and Java using the same clear solution.
Example (pseudo code)
CategorList class
public class CategoryList {
private ArrayList<Category> categoryList;
// getters and setters
}
Converter
public class CategoryListConverter {
public CategoryList convert(String json) {
Gson g = new Gson();
CategoryList cl = g.fromJson(json, CategoryList.class);
return cl;
}
}
I tried the code it workd fine
getTasks("1,2,3");
check what the value of categoriesIds is sent to getTask
Send this as a form parameter from webpage. Then get this from HttpServletRequest request object in java.
request.getParameter('categoryId');

Categories