I am making a query call to freebase and I receive a JSON response. The response has the following structure:
{
"code": "/api/status/ok",
"result": [
{
"/common/topic/image": [{
"guid": "#9202a8c04000641f8000000004b67f6d"
}],
"/people/person/profession": [{
"name": "Critic"
}],
"id": "/en/michael_jackson_1942",
"name": "Michael Jackson",
"type": "/people/person"
},
{
"/common/topic/image": [{
"guid": "#9202a8c04000641f800000001b90fdea"
}],
"/people/person/profession": [{
"name": "Actor"
}],
"id": "/en/michael_jackson_1970",
"name": "Michael Jackson",
"type": "/people/person"
}
],
"status": "200 OK",
"transaction_id": "cache;cache03.p01.sjc1:8101;2012-01-16T18:28:36Z;0055"
}
I need to parse this response in a ArrayList of java objects using GSON. To do this I need to create the class of the object with get/set and make it available to parse. Or is there another simpler way to do things ? I have used simple JSON strings by now, but in this case I can't remake the structure of the class I need. Basically in the end I need something like ArrayList<Person> where Person has all the attributes from the json string.
Any help is appreciated. Thank you.
The final solution, according with the answer below
public class FreebaseResponse {
#SerializedName("code")
public String code;
#SerializedName("result")
public ArrayList<Person> result;
#SerializedName("status")
public String status;
#SerializedName("transaction_id")
public String transaction_id;
}
public class Person {
#SerializedName("/common/topic/image")
public ArrayList<Person.Guid> imageGuid;
#SerializedName("/people/person/profession")
public ArrayList<Person.Profession> profession;
#SerializedName("id")
public String id;
#SerializedName("name")
public String name;
#SerializedName("type")
public String type;
private class Guid
{
#SerializedName("guid")
public String guid;
}
private class Profession
{
#SerializedName("name")
public String name;
}
}
I guess you can create a FreebaseResponse class that contains code, result (ArrayList<Person>), etc fields and use Gson to deserialize. the names that are not valid identifiers, e.g. /common/topic/image will be a problem. I haven't tried it myself but it seems to me that SerializedName annotation should do the trick.
If you need all the fields, the way you mentioned seems to me like the way to go. If you only want a small part of the data, you can get it directly. In general, I think that since JSON is meant for object representation, it is better to create the appropriate class. It will ease your way in the future as well, as you will need more from this data.
Related
is there anyway to correct Map method responses which use generics as response subfields with the appropriate implementation? Example:
Let's say I have a generic response class:
public class Response {
private String createdOn;
//other fields
private Map<String, Object> values;
private Model object;
//getters and setters
}
Generic model class:
public class Model{
}
Model Class A:
public class ModelA extends Model{
private String name;
private String lastname;
//getters and setters
}
And Model Class B:
public class ModelB extends Model{
private int number;
private boolean isTrue;
//getters and setters
}
And method doSomeStuff() which let's say returns a ResponseEntity< Response> where in this particular response "values" is a map< String, SomeRandomObject> and object is a ModelA object.
And suppose I have another method doSomeOtherStuff() which returns a ResponseEntity< Response> object where in that case "values" is a map< String, AnotherRandomObject> and object is a ModelB object.
Is there any way to map the response subfields of the first method to the appropriate ones? Using swagger-UI all I get is the following for both methods:
{
"createdOn": "string",
// other fields
"model": {},
"values": {}
}
Whereas I would like something like the following:
doSomeStuff():
{
"createdOn": "string",
// other fields
"model": {
"name": "string",
"lastname": "string",
}
"model": {
//All the subfields of SomeRandomObject
},
}
doSomeOtherStuff():
{
"createdOn": "string",
// other fields
"model": {
"number": "int",
"isTrue": "boolean",
}
"model": {
//All the subfields of AnotherRandomObject
},
}
Since it obviously cannot determine what type of objects are returned at the implementation level.
P.S. The above classes are as an example. I would really appreciate help to make the documentation work and not for ways to refactor it since the above logic is applied to more than 100 rest methods.
Edit: I am using springfox-swagger2 with springfox-swagger-ui.
I new to Spring boot microservices and exploring webflux framework. I'm trying to merge response from two microservices to one wrapper class to have the response in proper JSON. Below is the scenario in detail.
Micro-Service 1 : http://localhost:8080/products
in controller of this micro-service its returning Flux and I'm get
[
{
"id": "5b2fd1e5f57d731904c54ad7",
"name": "Product3",
"price": "30"
},
{
"id": "5b2fd1e4j9fdj3kds9djkj43",
"name": "Product2",
"price": "20"
}
]
Micro-Service 2 : http://localhost:8181/person
In controller of second service its returning Mono and for this also I'm getting correct response as below,
{
"id": ehj8u3jmodmdj,
"name": "PersonXXX",
"email": "PersonXXX#somecorp.com"
}
Now I want to create another microservice http://localhost:8282/personproduct which should combine the result of above two microservices in a wrapper class as below,
{
{
"id": ehj8u3jmodmdj,
"name": "PersonXXX",
"email": "PersonXXX#somecorp.com"
},
[
{
"id": "5b2fd1e5f57d731904c54ad7",
"name": "Product3",
"price": "30"
},
{
"id": "5b2fd1e4j9fdj3kds9djkj43",
"name": "Product2",
"price": "20"
}
]
}
Right now I have a Parent class Entity for both Product and Person classes and I'm calling both above mentioned micro-services via WebClient and concatinating the response using Flux.concat(personResp, productResp); where personResp is of type Mono and productResp is of type Flux but I'm getting response of this (3rd) microservice only in Text and not in JSON as below,
data:{"id":ehj8u3jmodmdj,"name":"PersonXXX","email":"PersonXXX#somecorp.com"}
data:{"id":"5b2fd1e5f57d731904c54ad7","name":"Product3","price":"30"}
data:{"id":"5b2fd1e4j9fdj3kds9djkj43","name":"Product2","price":"20"}
This might be due to each element is sent as a different stream.
So just want to know if is there any way to combine two responses in one wrapper class without using block() method on any of the calls done to these two services.
UPDATE
Currently Im calling product microservice as,
clientProd.get().uri(productUrl)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.retrieve().bodyToFlux(Product.class).onErrorReturn(new Product());
And similarly Person service as,
clientPerson.get().uri(personUri)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.retrieve().bodyToMono(Person.class).onErrorReturn(new Person());
And concatenating is using Flux.concat(),
Thanks in advance.
The correct way is to map those responses to classes:
public class Product{
private Long id;
private String name;
private Double price;
//constructors, getters, setters
}
public class Person{
private Long id;
private String name;
private String mail;
//constructors, getters, setters
}
public class Entity{
private Person person;
private List <Product> products;
//constructors, getters, setters
}
In this way you have three different POJOs that you can use according to the needs (the type of API you are calling).
Lets say we have the following JSON example:
{
"teachers": [{
"id": "abc",
"payment": 10,
"name": "xyz",
"clases": ["1", "3"]
}, {
"id": "qwe",
"payment": 12,
"name": "xcv",
"classes": ["1", "2"]
}],
"classes": [{
"id": "1",
"room": 7
}, {
"id": "2",
"room": 1
}, {
"id": "3",
"room": 2
}]
}
I would like to deserialize it to Java objects (getters/setters ommited):
class Teacher {
private String id;
private double payment;
private String name;
private List<CLassRoom> classRooms;
}
class ClassRoom {
private String id;
private int room;
}
As you see, we have a references here. I know I can deserialize it with Jackson (and would like to) but the problem is that I cannot touch DTO itself (so annotations are not possible, would also like to avoid wrappers (many classes)). Also, it would be nice if the "configuration" of deserialization was in separate file (json schema for example). I would also like to avoid some tags given by user - he should only pass me the values. Moreover, he should know where is the error, if he made some mistake.
Also, it would be nice if I could manipulate name of field in json (some clients may have different habits).
I didn't find anything which satisffied all of above requirements(entity reference and error handling are the most important). However - I just have heard about json schema, so maybe it provides such functionality (but I didn't find it though). Any helpful reference/example/lib? I will appreciate any help.
Just to be correct - imagine that the given json is a RELATIONAL database snapshot of the instance. I just want to create whole entity like the hibernate (or actually JPA) does :)
1. add jar of import org.json.JSONObject.
2. JSONObject object = new JSONObject(list)
2.1 object.has("teachers") if it is exists
2.2 JSONArray teacherArray = (JSONArray) object.get("teachers");
2.3 JSONObject teacherJsonObject = teacherArray .getJSONObject(0);
(if you have more than jsonobject in json arrary then itrate it.)
2.4 if(teacherJsonObject .has("id"))//you can check existence like this.
String id=teacherJsonObject .getString("id");
String payment=teacherJsonObject .getString("payment");
String name=teacherJsonObject .getString("name");
It may not be the best solution, but it's a working one.
Let's create a Parser class like the following:
public class Parser {
private List<Teacher> teachers;
private List<ClassRoom> classes;
public void parse() {
for (Teacher teacher : teachers) {
for (String classRoomId : teacher.getClasses()) {
for (ClassRoom classRoom : classes) {
if (classRoom.getId().equals(classRoomId)) {
teacher.getClassRooms().add(classRoom);
}
}
}
}
}
}
Modify your ClassRoom class to have a getter on the id field:
public class ClassRoom {
private String id;
private int room;
public String getId() {
return id;
}
}
And your Teacher class to get the Ids of classes AND the classRooms references:
public class Teacher {
private String id;
private double payment;
private String name;
private String[] classes;
private List<ClassRoom> classRooms = new ArrayList<>();
public String[] getClasses() {
return classes;
}
public List<ClassRoom> getClassRooms() {
return classRooms;
}
}
If you use the Gson library, you could then just parse your JSON like that:
Gson gson = new Gson();
Parser parser = gson.fromJson(jsonString, Parser.class);
parser.parse;
Now, every teacher will have their classRooms correctly referenced.
I have json as follows
{
"students":[{
"name":"abc",
"id":"1",
"age":"34",
"hobby":"sports"
},{
"name":"pqr",
"id":"2",
"age":"25",
"hobby":"dance"
},
]
}
and I want to update the value of {
"name":"pqr",
"id":"2",
"age":"25",
"hobby":"dance"
}, this hobby to "reading"
can someone help me? I'm new to json objects
Convert your json string to a java object and update the value using setter method
Go through this tutorial https://www.mkyong.com/java/jackson-2-convert-java-object-to-from-json/.
first step you have to make a student class
public class Student{
private String name;
private String id;
private String age;
private String hobby;
}
second step use GSON lib with arrayList of Student like this
ArrayList<Student>arrayList=new Gson().fromJson(MyJsonStructure,Student.class);
I am using the Kinvey Android SDK to retrieve data from their backend. It uses Gson behind the scenes. I have been unable to get it to deserialize an array of custom objects. Here is the entity definition and the JSON in question:
public class AlbumEntity extends GenericJson {
#Key("_id")
private String id;
#Key
private String name;
#Key
private String location_name;
#Key
private String start_date;
#Key("artifacts")
private Artifact[] artifacts;
static class Artifact extends GenericJson {
#Key
private String type;
#Key
private String photo_url;
public Artifact() {}
}
#Key("_kmd")
private KinveyMetaData meta;
public TripketEntity() {}
}
JSON body:
{
"_id": "5216fec12f7b521a26064f9d",
"_kmd": {
"ect": "2013-08-26T06:51:00.283Z",
"lmt": "2013-09-05T15:28:28.079Z"
},
"artifacts": [
{
"type": "photo",
"photo_url": "http://www.califliving.com/title24-energy/images/sanfrancisco.jpg"
},
{
"type": "photo",
"photo_url": "http://www.sanfrancisco.net/pictures/san-francisco.jpg"
},
{
"type": "photo",
"photo_url": "http://a2.cdn-hotels.com/images/themedcontent/en_GB/San%20Francisco_Top%2010.jpg"
},
{
"type": "photo",
"photo_url": "http://sanfranciscoforyou.com/wp-content/uploads/2010/03/san-francisco-city.jpg"
}
],
"location_name": "San Francisco",
"name": "My Trip to the Bay",
"start_date": "06/15/2013",
"owner": {
"_type": "KinveyRef",
"_collection": "user",
"_id": "5216fcd60b36c57d69000529"
},
"_acl": {
"creator": "kid_ePPs9jXc_5"
}
}
If I change the private Artifact[] artifacts object to private GenericJson[] artifacts, the array is deserialized as an array of GenericJson objects, with the data fields intact in the Unknown Fields list. How can I get it to work for my custom object?
Other things I have tried include List<Artifact> artifacts as well as ArrayList and Collection.
I'm an engineer at Kinvey working on the Android library-
Add a public modifier to the definition for the static inner class, and GSON should be able to pick it up:
...
#Key("artifacts")
private Artifact[] artifacts;
public static class Artifact extends GenericJson {
#Key
private String type;
#Key
private String photo_url;
public Artifact() {}
}
#Key("_kmd")
private KinveyMetaData meta;
...