I receive from server a response in this form
{"error":null,"id":1,"result":
{"admin":false,
"firstname":"Jason",
"id":346,"idHotel":109,
"idVendor":null,
"lastname":"Butcher",
"sessionkey":"3c8a17ae47a6d131b1a14b44a1d8f9a9",
"urlAvatar":"avatar_316_mjm.jpg",
"urlThumb":"thumb_316_mjm.jpg"}
}
And want to get the various singles attributes,
for example
Boolean error=..;
String admin=....;
String idHotel=...;
and also the images
You should create a wrapper class like this:
public class Response {
public boolean error;
public int id;
public Result result;
}
public class Result {
...
}
then is simple for you to deserialize the json via gson to you classes:
Response response = new Response();
Gson gson = new Gson();
response = gson.fromJson(response, Response.class);
And there's a lot of other nifty things you can do: https://sites.google.com/site/gson/gson-user-guide
Oh forgot one important thing!
Remember to change the namespace on the Gson library, I had problems get it running on htc telephones. You can do this with jar jar links: http://code.google.com/p/jarjar/downloads/list
docs: http://code.google.com/p/jarjar/wiki/CommandLineDocs
Related
I've got a Scenario Entity in my Spring boot app
private Long id;
private String scenarioName;
private HashMap<Integer, Object> scenarioAttributes;
Let's say we create a Scenario entity with following Json:
{
"scenarioName":"scenario1",
"scenarioAttributes":{
"1" : {
"goToURL":"https://google.com/"
},
"2" : {
"assertCurrentUrl":"https://google.com/"
}
}
}
In my ExecutorService, I've got following code:
public List<Object> getStepsFromScenarioAttributesValues(Long scenarioId){
List<Object> response = new ArrayList<>();
Scenario scenario = scenarioService.getScenario(scenarioId);
HashMap<Integer, Object> steps = scenario.getScenarioAttributes();
for (Map.Entry<Integer, Object> set : steps.entrySet()){
response.add(set.getValue());
System.out.println(response);
// prints out
//[{goToURL=https://google.com/}, {assertCurrentUrl=https://google.com/}]
}
return response;
}
public void executeSteps(List<Object> response){
for (Object obj : response){
JsonObject jsonObj = (JsonObject) obj;
if (jsonObj.has("goToUrl")) {
//goes to url
driverService.goToUrl(String.valueOf(jsonObj.get("goToUrl")));
return;
} else if (jsonObj.has("assertCurrentUrl")) {
//asserts cur url with value
driverService.assertCurrentUrl(String.valueOf(jsonObj.get("assertCurrentUrl")));
return;
}
}
}
public String executeScenario(Long scenarioId){
executeSteps(getStepsFromScenarioAttributesValues(scenarioId));
return "Scenario" + scenarioId + " has been executed successfully";
}
I've got a GetMapping for single scenario as follows:
#GetMapping("/scenarios/{id}/execute")
public List<Object> executeScenario(#PathVariable Long id){
return executorService.getStepsFromScenarioAttributesValues(id);
}
Which, upon sending one sample scenario and entering a site, provides us with, you guessed it, a List containing an Object, which is a Json.
Unfortunately, if I want to call executeSteps() function which has a list of Objects, I cannot do it since an Object is not a JsonObject.
I thought simple JsonObject jsonObj = (JsonObject) obj; would do a trick, but I'm greeted with
class java.util.LinkedHashMap cannot be cast to class com.google.gson.JsonObject (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.google.gson.JsonObject is in unnamed module of loader 'app')
How can I approach fetching values from scenarioAttributes Jsons to further interpret them?
Are there unnecessary lines of code that I could get rid of?
Feel free to point out my wrongdoings, just starting my journey with Spring
public class Scenario {
private String scenarioName;
private HashMap<Integer, Object> scenarioAttributes;
}
Use object mapper to print class object to JSON:
ObjectMapper objectMapper = new ObjectMapper();
Scenario scenario = objectMapper.readValue(response, Scenario.class);
When you say Object, which is a Json what do you mean by "Json"? Json is not a class. I assume that your Object is an instance of class String that contains text in Json format. Your exception though points out that it could be a Map. I would still assume that it is a String that holds Json. In your code you attempt to work with class JSONObject which is part of json-simple library. While it is a nice training library I would suggest that you don't use it. BTW great site about JSON with the list of most libraries for most languages is: https://www.json.org/json-en.html. Best options are (IMHO) are Jackson-Json (also known as Faster XML) or Gson (by Google) (Here is their user guide site). To parse your Json text to a class instance you can use ObjectMapper class which is part of Jackson-Json library. For example
public <T> T readValue(String content,
TypeReference valueTypeRef)
throws IOException,
JsonParseException,
JsonMappingException
See Javadoc. But I also may suggest a very simplified JsonUtils class which is a thin wrapper over Jackson-Json library. This class is part of Open-source library called MgntUtils written and maintained by me. Your code may be as simple as follows:
Scenario scenario;
try {
scenario = JsonUtils.readObjectFromJsonString(response, Scenario.class);
} catch(IOException ioe) {
....
}
Here is JsonUtils javadoc. MgntUtils library can be obtained as Maven artifact here or on Github (including source code and Javadoc)
I am working on an HTTP Rest query.
Wikipedia API returns a JSON. The problem is the JSON structure returned by Wikipedia.
https://en.wikipedia.org/w/api.php?action=parse§ion=0&prop=text&format=json&page=pizza
This is the JSON obtained via a rest request to the Wikipedia API. To view the full JSON, you can click on the above link.
{
"parse":
{
"title":"Pizza",
"pageid":24768,
"text":{"*":"<div class=\...>"}
}
}
I would parse this using a custom deserializer which I haven't got a chance to test. Trying to parse with simple Gson like the following return null;
Result res = new Gson(str,Result.class);
I have created the classes like the following:
public class Result
{
private Parse parse;
}
public class Parse
{
private String title;
private int pageid;
private Text text;
}
public class Text{
private String *;// what should I call this attribute.
}
My plan is to add a custom deserializer like the following:
public class TextBaseDeserializer implements JsonDeserializer<Text> {
#Override
public RespondentBase deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
return jsonDeserializationContext.deserialize(jsonElement.get("*"),Text.class);
}
}
I am using Gson to parse this, like the following:
Gson tmp = new GsonBuilder().registerTypeAdapter(Text.class, new TextBaseDeserializer());
// let's assume that str is the string obtained following Rest based request from Java.
Result res = tmp.parse(str,Result.class);
I have done all the above code to handle the symbolic JSON attribute.
My question is how to parse such a JSON. In the above example, the attribute is a *
As mentioned in a comment, you should annotated field with #SerializedName("*").
You can name the field whatever you want. We'll just name it star below, but maybe all is better, since * might be a wildchar? Doesn't really matter, just choose whatever name you like.
class Text
{
#SerializedName("*")
private String star;
}
Test
String str = "{\"parse\":{\"title\":\"Pizza\",\"pageid\":24768,\"text\":{\"*\":\"<div class=\\\"mw-parser-output\\\">...</div>\"}}}";
Gson tmp = new GsonBuilder().create();
Result res = tmp.fromJson(str, Result.class);
System.out.println(res.getParse().getText().getStar());
Output
<div class="mw-parser-output">...</div>
I have an API that returns some arguably useful metadata along with requested data itself. It looks something like this:
{
"success": true,
"messages": [],
/* other metadata */
"result": { /* fields with useful data */ }
}
So, basically I want to serialize only stuff that is nested inside of "result" field, preferably still being able to work with meta (checking "success" on true/false and reading messages might be useful).
I thought I could use JSONObject to separate "result" and other meta, but this pipeline feels like a bit of overhead. Is there a way to do it purely with GSON?
The other problem is that I use Retrofit, which has a very neat workflow with pure GSON. If the above is the only adequate way of dealing with such API, how should I approach integrating it into Retrofit workflow?
to your retrofit builder add:
.addConverterFactory(new GsonConverterFactory(new GsonBuilder()
.registerTypeAdapter(Result.class, new JsonDeserializer<Result>() {
#Override
public Result deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if(!(((JsonObject) json).getAsJsonPrimitive("success")).getAsBoolean()) {
return null;
}
JsonObject result = ((JsonObject) json).getAsJsonObject("result");
return new Gson().fromJson(result, Result.class);
}
}).create()))
there are npe and other checks to do of course :)
Create a POJO with #Expose annotation and use serialization = true/false. If you want to serialize only success, then your POJO would look something like this.
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class POJO {
#SerializedName("success")
#Expose(serialize = true, deserialize = false)
private Boolean success;
///Your getter / setter methods
}
I have used this above with Retrofit and it works fine.
Hope this helps!
EDIT:
Also you need to mention this while creating your Retrofit Service
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.excludeFieldsWithoutExposeAnnotation();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(YOUR_BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gsonBuilder.create()))
.build();
I'm using Jackson and RESTEasy to hook into an external API. The API mainly returns simple objects which I have managed to successfully populate into POJOs.
I'm hitting a problem where I get an array of objects back e.g.
[
{
"variable1": "someValue1",
"variable2": "someValue2",
"variable3": "someValue3"
}
{
"variable1": "someValue4",
"variable2": "someValue5",
"variable3": "someValue6"
}
{
"variable1": "someValue7",
"variable2": "someValue8",
"variable3": "someValue9"
}
]
I have 2 classes: one called VariableObject which looks like this:
public class VariableObject {
private String variable1;
private String variable2;
private String variable3;
}
and VariableResponse which looks like:
public class VariableResponse {
private List<VariableObject> variableObjects;
}
My client uses JAXRS Response class to read the entity into the class i.e
return response.readEntity(VariableResponse.class);
I get a stack trace which reads:
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of VariableResponse out of START_ARRAY token
I understand you can return these as a List of POJOs i.e List quite easily, but this is not what I want to do.
The question really is two parts:
a. Can I possibly populate the VariableResponse POJO using Jackson (some how) preferably without a customer deserialiser? Maybe some annotation exists (this would be ideal)?
b. Is there some way to detect if an Array is being retuned as the root JSON node in the response and then act accordingly?
Help greatly appreciated.
Your JSON is indeed an array of objects.
You can deserialize it with:
response.readEntity(new GenericType<List<VariableObject>>() {});
And then create a new instance of VariableResponse passing resulting List as a constructor parameter like this:
public class VariableResponse {
private final List<VariableObject> variableObjects;
public VariableResponse(List<VariableObject> variableObjects) {
this.variableObject = new ArrayList<>(variableObjects);
}
}
You might forget to add comma after each {..}. After correcting your JSON string, I converted it into ArrayList<VariableObject> using TypeReference and ObjectMapper.
sample code:
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
...
TypeReference<ArrayList<VariableObject>> typeRef = new TypeReference<ArrayList<VariableObject>>() {};
ObjectMapper mapper = new ObjectMapper();
try {
ArrayList<VariableObject> data = mapper.readValue(jsonString, typeRef);
for (VariableObject var: data) {
System.out.println(var.getVariable1()+","+var.getVariable2()+","+var.getVariable3());
}
} catch (Exception e) {
System.out.println("There might be some issue with the JSON string");
}
output:
someValue1,someValue2,someValue3
someValue4,someValue5,someValue6
someValue7,someValue8,someValue9
If you prefer your own response type direct.
Try just extending ArrayList?
public VariableResponse extends ArrayList<VariableObject> {
}
I've been fighting with JSON parsing using GSON today and a lot of things went well with a minimum amount of hassle.
Though, for the following JSON string I started running into some issues;
{"success":1,"response":{"dvds":{"IronMan":{"rating":"awesome"},"BatMan":{"rating":"awesome"},"Smurfs":{"rating":"childish"}}}}
In this JSON I have a collection "response" containing a collection of responsetypes. In the example the only responsetype included is dvds.
But my issue lies here; I wish to have every child of "dvds" to be parsed to a List response , each child being a single Dvd-class object (containing a String "title" and a String "rating")
Thus far parsing seperate values/objects and parsing arrays went with no real issues, but I can't wrap my head around how to solve parsing such collections.
googling today kept referencing me to "TypeTokens" but looking at the code in various topics regarding this issue, I still haven't understood how to implement it for my use-scenario at all.
So, to be concrete;
"How can I make GSON correctly recognize both my responsetype and dvd-collections?"
Currently my ResponseData.class looks like this:
public class ResponseData {
public int success;
public List<ResponseTypes> responsetypes;
public class ResponseType{
public List<Dvd> Dvds;
}
public class Dvd{
public String title;
public String rating;
}
}
That's how i'd look at this problem in an array-based form, but this time i need to apply it in the case i run into a collection of objects instead. in all scenarios i can think of the Class of the object should be able to be recognized by the name of it's parent.
Currently the parsing is initiated as follows;
try{
Gson gson = new Gson();
Reader reader = new InputStreamReader(stream);
ResponseData responsedata = gson.fromJson(reader, ResponseData.class);
return responsedata;
}
I really hope someone can help me out! Thanks!
you have here some problems:
the class ResponseData should hold List<ResponseType> and not List<ResponseTypes>
the json that you supplied isnt matching the classes above.
an accurate classes for this json are:
public class ResponseData
{
public int success;
public Map<String, Map<String, Dvd>> response;
public class Dvd
{
public String rating;
}
}
in order to describe a list in json you should use: "[ ]". for example: [1,2,3]. you can read more about json here
if you want the json to describe the class hierarchy you describe above. it should looks like:
{"success":1,"responseTypes":[{"Dvds":[{"title":"IronMan","rating":"awesome"},{"title": "BatMan", "rating":"awesome"},{"title":"Smurfs", "rating":"childish"}]}]}
notice that unless you declare a mapping between the variable names and the json varible names then you should use the same names. for example "Dvds" and "responseTypes"