I am using goggle's search api to get topics id which is used to get JSON response from topic api.The returned response looks like this
{
"id":"/m/01d5g",
"property":{
"/amusement_parks/ride_theme/rides":{...},
"/award/ranked_item/appears_in_ranked_lists":{...},
"/book/book_character/appears_in_book":{
"valuetype":"object",
"values":[
{
"text":"Inferno",
"lang":"en",
"id":"/m/0g5qs3",
"creator":"/user/duck1123",
"timestamp":"2010-02-11T04:00:59.000Z"
},
{
"text":"Batman: Year One",
"lang":"en",
"id":"/m/0hzz_1h",
"creator":"/user/anasay",
"timestamp":"2012-01-25T11:05:03.000Z"
},
{
"text":"Batman: The Dark Knight Returns",
"lang":"en",
"id":"/m/0hzz_sb",
"creator":"/user/anasay",
"timestamp":"2012-01-25T11:22:17.001Z"
},
{
"text":"Batman: Son of the Demon",
"lang":"en",
"id":"/m/071l77",
"creator":"/user/wikimapper",
"timestamp":"2013-07-11T15:20:32.000Z"
},
{
"text":"Joker",
"lang":"en",
"id":"/m/04zxvhs",
"creator":"/user/wikimapper",
"timestamp":"2013-07-11T16:58:37.000Z"
},
{
"text":"Arkham Asylum: A Serious House on Serious Earth",
"lang":"en",
"id":"/m/0b7hyw",
"creator":"/user/wikimapper",
"timestamp":"2013-07-11T19:26:54.000Z"
}
],
"count":6.0
},
"/book/book_subject/works":{...},
"/comic_books/comic_book_character/cover_appearances":{...},
...
}
}
I want to decipher this so that i can get relevant information such as, "/book/book_character/appears_in_book" itself is a property for response and only required value that i want from it is "text" and "id" e.g. "text":"Batman: Year One" and "id":"/m/0hzz_1h".
Since the response does not have fixed properties, and which may varying according to response id. how can i covert this JSON response in java Class where i can store "/book/book_character/appears_in_book" as one serialized class and containing Collection of values such has id and text and appears_in_book as name variables for class.
I considered GSON to do this. since name of property is not constant i can not use it to covert JSON to Java Object. currently i am iterating over each property by hard coding and filling them in java variables.
If some one can provide efficient way to do so i will appreciate help.
You could do this dynamically using reflection in Java but this is an advanced feature of Java and it may make your code more complicated than it needs to be.
See: Dynamically create an object in java from a class name and set class fields by using a List with data
A simpler alternative would be to just parse the JSON into a bunch of nested Maps and Lists exactly as they're given in the JSON data.
See: How to parse JSON in Java
Related
I have a request body like
{
"Data": {
"Permissions": [
"ReadOnly"
],
"CreationTime": "2099-09-14T10:28:33.722Z",
},
"standards": { },
"testing":{ }
}
I want to run a data driven testing using rest assured where I pass different values for permissions and creation time etc.. What is the best way to do that ? I want to have only one request model but need to write a helper method to change the values by passing the field key name and value .
Very much appreciate your help
Either you can create property file (something like inputdata.properties) or using excel sheet also you can call the data and iterate through all the rows of excel sheet. You can follow below link :-
https://www.callicoder.com/java-read-excel-file-apache-poi/
I'm looking for potentially some design pattern advice regarding object traversal to dynamically construct objects based on the data being presented.
Below, I am manually constructing this object. Initially, the root node is a BinaryLogicOpType but could be a different object based on the rootNodeType.
My question is.. I need to dynamically construct these objects of differing types based on the string data in my lists. What is the best route in doing so?
I'm willing to refine this questions if it's confusing.
String rootNodeType = fN.type;
BinaryLogicOpType _blop = new BinaryLogicOpType();
JAXBElement<BinaryLogicOpType> root = constructRootElement(_blop, factory, rootNodeType);
/** LETS CREATE THE FIRST CHILD ELEMENT */
BinaryComparisonOpType attrName1GTEFive = new BinaryComparisonOpType();
_blop.getOps().add(factory.createPropertyIsEqualTo(attrName1GTEFive));
JAXBElement<String> attr1Property = factory.createValueReference(fN.nodes.get(0).getProperty());
LiteralType attr1ValueLiteral = new LiteralType();
attr1ValueLiteral.getContent().add(fN.nodes.get(0).getValue());
JAXBElement<LiteralType> attr1Value = factory.createLiteral(attr1ValueLiteral);
attrName1GTEFive.getExpression().add(attr1Property);
attrName1GTEFive.getExpression().add(attr1Value);
Sample JSON
{
"type": "AND",
"filters": [
{
"type": "=",
"value": "exampleid",
"property": "id"
},
{
"type": "ILIKE",
"value": "*",
"property": "metacard-tags"
},
{
"type": "OR",
"filters": [
{
"type": ">=",
"value": null,
"property": "benumber"
},
{
"type": "ILIKE",
"value": "redshirts",
"property": "title",
"isCaseSensitive": true
}
]
}
]
}
Sample XML
<?xml version="1.0" encoding="UTF-8"?><fes:Filter xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:gml="http://www.opengis.net/gml/3.2">
<fes:Or>
<fes:PropertyIsLessThan matchAction="ANY" matchCase="false">
<fes:ValueReference>name</fes:ValueReference>
<fes:Function name="sub">
<fes:Literal>my-id</fes:Literal>
</fes:Function>
</fes:PropertyIsLessThan>
<fes:And>
<fes:PropertyIsGreaterThanOrEqualTo matchAction="ANY" matchCase="false">
<fes:ValueReference>attName</fes:ValueReference>
<fes:Literal>5</fes:Literal>
</fes:PropertyIsGreaterThanOrEqualTo>
<fes:PropertyIsLike escapeChar="\" matchCase="false" singleChar="?" wildCard="*">
<fes:ValueReference>title</fes:ValueReference>
<fes:Literal>greetings</fes:Literal>
</fes:PropertyIsLike>
<fes:PropertyIsEqual>
<fes:ValueReference>be_number</fes:ValueReference>
<fes:Function>
<fes:Parameter>null</fes:Parameter>
<fes:Parameter>null</fes:Parameter>
</fes:Function>
</fes:PropertyIsEqual>
</fes:And>
</fes:Or>
</fes:Filter>
I think there is really no easy solution, but I'm pretty sure it is possible to implement conversion in quite an elegant manner with OOP.
Essentially, you're dealing with ASTs in both cases. And the their structures are not so different at all. So if you'd manage to implement conversion routine for each of the possible node types, you should be able to convert the whole AST.
First of all, I'd start by implementing a good Java model for your JSON structure. Classes like AndExpression, ComparisonExpression, LikeExpression, OrExpression etc. For inspiration, check the generated classes of the Filter schema. Good modelling is essential here.
Use poliformic deserialization so that you get the proper object structure after parsing Jackson. Now you "only" need to convert this structure into your JAXB structure.
The simplest would be to add conversion methods to your JSON model classes directly. I'd make them all implement an interface with a method like:
public Object convertToJAXB(ObjectFactory objectFactory);
In the case of "leaf" AST nodes like ILIKE you can just construct the appropriate object directly.
In the case of "composite" AST nodes like AND or OR you will need to call convertToJAXB on each of the filters and then do some more work by wrapping results into JAXBElements. You might need some instanceof checks here; it should be possible to come up with a more intelligent solution.
I have JSON that needs to be converted to a Java Object. The JSONs I need to handle can look like this:
{
"documents": [
{
"title": "Jobs",
"is-saved": false,
"abstract": "<span class=\"hit\">Jobs</span> may refer to:\n\n* Steve <span class=\"hit\">Jobs</span> (1955–2011), co-founder and former CEO of consumer electronics company...<br />",
"id": "Jobs",
"url": "http://en.wikipedia.org/wiki/Jobs"
}
],
"keywords_local": [
{
"keyword": "Jobs",
"interest": 1,
"angle": 0
}
],
"sessionid": "6cd6402e-1f67-45a8-b0fa-e79a5d0d50f4",
"q": "Jobs",
}
This JSON is returned when entering a search keyword on a searchengine, in this case "Jobs". I have not named these variables-to-be-created, this JSON was just "given" to me from a similar earlier app. So I'm obviously having trouble with variables is-saved and abstract. Abstract is a reserved keyword and everywhere I read a reserved keyword CANNOT be used as a variable name.
I do not have access to the previous app that I am sort of updating and I guess the point to that is that I need to figure it out by myself ;) But I am a bit of a stand still now, have no idea of how to move forward.
I'm a newbie, so do not give me hell if I'm asking a stupid question, it's my first time coding any sort of app! ;)
Thanks for any help!
If you use GSON for parsing you can name your members as you want and annotate them for mapping.
#SerializedName("abstract")
private String abstractText;
Another option you've got is to use Jackson, and use the #JsonProperty annotation..
#JsonProperty("abstract")
private String abstractText;
In fact, it depends on the tool you are using. With tools mapping directly to your custom POJO (like GSON, Jackson), you need to map your JSON field name with your Java correct and valid field name.
If you use a mors basic library such as JSON.org's, there is no need to do so because you parse it to specific object allowing you to handle it.
JSONObject obj = new JSONObject(" .... ");
JSONArray arr = obj.getJSONArray("documents");
String abstractValue = arr.getJSONObject(0).getString("abstract");
First I know my title is bad as I didn't come up with better, I'm opened to suggestion.
I'm using retrofit to get data from an api of this kind : #GET("users/{userid}")
It works fine and I'm happy with it, the problem is when I call the same api with #POST("users/widget") with a list of ids. I have the following answer :
{
"long_hash_id": {
"_id": "long_hash_id"
.......
},
"long_hash_id": {
"_id": "long_hash_id",
.....
},
........
}
the "long_hash_id" is typicaly "525558cf8ecd651095af7954"
it correspond to the id of the user attached to it.
When I didn't use retrofit, I used Gson in stream mode to get each user one by one. But I don't know how to tell retrofit.
Hope I'm clear and
Thank you in advance.
----------- Solution :
I made my interface this way :
#FormUrlEncoded
#POST(AppConstants.ROUTE_USER_GROUP)
Call<Map<String,User>> getUsers( #Field("ids") List<String> param, #QueryMap Map<String,String> options);
and I simply gave my ArrayList of ids. Thank you very much
Gson is able to deal with JSON objects with variable keys like the one you posted. What you have to do, in this case, is to declare a Map<String, ModelClass>, where ModelClass is the content of the JSONObject you want to represent
data: [
{
type: "earnings"
info: {
earnings: 45.6
dividends: 4052.94
gains: 0
expenses: 3935.24
shares_bought: 0
shares_bought_user_count: 0
shares_sold: 0
shares_sold_user_count: 0
}
created: "2011-07-04 11:46:17"
}
{
type: "mentions"
info: [
{
type_id: "twitter"
mentioner_ticker: "LOANS"
mentioner_full_name: "ERICK STROBEL"
}
]
created: "2011-06-10 23:03:02"
}
]
Here's my problem : like you can see the "info" is different in each of one, one is a json object, and one is a json array, i usually choose Gson to take the data, but with Gson we can't do this kind of thing . How can i make it work ?
If you want to use Gson, then to handle the issue where the same JSON element value is sometimes an array and sometimes an object, custom deserialization processing is necessary. I posted an example of this in the Parsing JSON with GSON, object sometimes contains list sometimes contains object post.
If the "info" element object has different elements based on type, and so you want polymorphic deserialization behavior to deserialize to the correct type of object, with Gson you'll also need to implement custom deserialization processing. How to do that has been covered in other StackOverflow.com posts. I posted a link to four different such questions and answers (some with code examples) in the Can I instantiate a superclass and have a particular subclass be instantiated based on the parameters supplied thread. In this thread, the particular structure of the JSON objects to deserialize varies from the examples I just linked, because the element to indicate the type is external of the object to be deserialized, but if you can understand the other examples, then handling the problem here should be easy.
Both key and value have to be within quotes, and you need to separate definitions with commas:
{
"key0": "value0",
"key1": "value1",
"key2": [ "value2_0", "value2_1" ]
}
That should do the trick!
The info object should be of the same type with every type.
So check the type first. Pseudocode:
if (data.get('type').equals("mentions") {
json_arr = data.get('info');
}
else if (data.get('type').equals("earnings") {
json_obj = data.get('info');
}
I'm not sure that helps, cause I'm not sure I understand the question.
Use simply org.json classes that are available in android: http://developer.android.com/reference/org/json/package-summary.html
You will get a dynamic structure that you will be able to traverse, without the limitations of strong typing.....
This is not a "usual" way of doing things in Java (where strong typing is default) but IMHO in many situations even in Java it is ok to do some dynamic processing. Flexibility is better but price to pay is lack of compile-time type verification... Which in many cases is ok.
If changing libraries is an option you could have a look at Jackson, its Simple Data Binding mode should allow you to deserialize an object like you describe about. A part of the doc that is probably quite important is this, your example would already need JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES to work...
Clarification for Bruce: true, in Jackson's Full Data Binding mode, but not in Simple Data Binding mode. This is simple data binding:
public static void main(String[] args) throws IOException {
File src = new File("test.json");
ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonParser.Feature. ALLOW_UNQUOTED_FIELD_NAMES, true);
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS,true);
Object root = mapper.readValue(src, Object.class);
Map<?,?> rootAsMap = mapper.readValue(src, Map.class);
System.out.println(rootAsMap);
}
which with OP's sightly corrected sample JSON data gives:
{data=[{type=earnings, info={earnings=45.6, dividends=4052.94, gains=0,
expenses=3935.24, shares_bought=0, shares_bought_user_count=0, shares_sold=0,
shares_sold_user_count=0}, created=2011-07-04 11:46:17}, {type=mentions,
info=[{type_id=twitter, mentioner_ticker=LOANS, mentioner_full_name=ERICK STROBEL}],
created=2011-06-10 23:03:02}]}
OK, some hand-coding needed to wire up this Map to the original data, but quite often less is more and such mapping code, being dead simple has the advantage of being very easy to read/maintain later on.