I am new to Java programming and I am working on a Spring Boot application with a REST service which will call another service and return a JSON response.
I am using OkHttpClient for handling this call.
However from the JSON response, I only require few attributes as final output in List format.
How can I extract only the required attributes from my okHttpCliwnt response ?
My response from the third party service looks like below :
{
"employeeDetail": [{
"employee": {
"name": "abc",
"age": "30",
"details": {
"role": "developer",
"phone": "123"
}
}
},
{
"employee": {
"name": "abc",
"age": "30",
"details": {
"role": "sr.developer",
"phone": "1234"
}
}
}
]
}
From this response, my final response needs to only be like below:
{
"employeeDetail": [{
"name": "abc",
"age": "30",
"role": "developer"
},
{
"name": "abc",
"age": "30",
"role": "sr.developer"
}
]
}
Please assist me.
I searched but for such nesting I couldn't find anything concrete. however I tried with JsonNode and I got to this.
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(str);
JsonNode empDetNode = rootNode.path("employeeDetail");
Iterator<JsonNode> elements = empDetNode.elements();
List<Employee> empList = new ArrayList<Employee>();
Gson gson = new Gson();
while (elements.hasNext()) {
Employee emp1 = new Employee();
JsonNode emp= elements.next();
JsonNode empl= emp.path("employee");
JsonNode name= empl.path("name");
JsonNode age= empl.path("age");
JsonNode details= empl.path("details");
JsonNode role= details.path("details");
emp1.setAge(age.toString());
emp1.setName(name.toString());
emp1.setRole(role.toString());
empList.add(emp1);
}
EmpDetl empdetl = new EmpDetl();
empdetl.setEmployeeDetl(empList);
Employee Class
public class Employee {
private String name;
private String age;
private String role;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
EmployeeDetl
import java.util.List;
public class EmpDetl {
private List<Employee> employeeDetl;
public List<Employee> getEmployeeDetl() {
return employeeDetl;
}
public void setEmployeeDetl(List<Employee> empLists) {
this.employeeDetl = empLists;
}
#Override
public String toString() {
return "EmpDetl [empLists=" + employeeDetl + "]";
}
}
I don't know how to convert JSON to List<> but you can convert JSON to Java object using Gson.
After that, you can add the contents of the object or the object itself to the list.
Here's a snippet from https://www.mkyong.com/java/how-do-convert-java-object-to-from-json-format-gson-api/
Gson gson = new Gson();
// 1. JSON to Java object, read it from a file.
Staff staff = gson.fromJson(new FileReader("D:\\file.json"), Staff.class);
// 2. JSON to Java object, read it from a Json String.
String jsonInString = "{'name' : 'mkyong'}";
Staff staff = gson.fromJson(jsonInString, Staff.class);
// JSON to JsonElement, convert to String later.
JsonElement json = gson.fromJson(new FileReader("D:\\file.json"),
JsonElement.class);
String result = gson.toJson(json);
Jackson might be the tool you are looking for. You just need to create a class, let's say Employee.java:
public class Employee {
#JsonProperty("name")
private String name;
#JsonProperty("age")
private String age;
#JsonProperty("role")
private String role;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
and EmployeeDetail.java
import java.util.List;
#JsonRootName(value = "employeeDetail")
public class EmployeeDetail {
private List<Employee> employees;
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
More annotations, please refer
You have to do the parsing manually using org.json or some other json framework.
Related
I am having two Spring Rest service create-employee and create-staff like as shown below
create-employee
#RequestMapping(value="/create-employee", method = RequestMethod.POST, consumes = "application/json")
public ResponseEntity<Void> createEmployee(final #RequestBody User user) {
try {
// employee createion logic
} catch (Exception exception) {
log.error("Exception in createEmployee:"+exception.getMessage());
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
}
create-staff
#RequestMapping(value="/create-staff", method = RequestMethod.POST, consumes = "application/json")
public ResponseEntity<Void> createStaff(final #RequestBody User user) {
try {
// staff creation logic
} catch (Exception exception) {
log.error("Exception in createStaff:"+exception.getMessage());
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
}
For both the services I am using a dto named User like as shown below:
public class User {
#JsonProperty("employeeName")
private String name;
#JsonProperty("age")
private Integer age;
#JsonProperty("managerName")
private String headName;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getHeadName() {
return headName;
}
public void setHeadName(String headName) {
this.headName = headName;
}
}
Now the issue is that for both create-employee and create-staff since I am using User.java as the request body. The posting json body looks like this
{
"employeeName" : "string",
"age" : "integer",
"managerName" : "string"
}
but actually what I want is that for create-staff service I would like to have the json body as below
{
"staffName" : "string",
"age" : "integer",
"managerName" : "string"
}
and create-staff service I would like to have the json body as below
{
"employeeName" : "string",
"age" : "integer",
"managerName" : "string"
}
But for both the services I need to use the same User.java dto but with different JsonProperty for the two services
Can anyone please hep me on this
Jackson also supports JsonAlias which might be helpful for you, just make sure you updated your jacskon mapper to version 2.9.1
public class User {
#JsonAlias({"employeeName","staffName"})
private String name;
#JsonProperty("age")
private Integer age;
#JsonProperty("managerName")
private String headName;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getHeadName() {
return headName;
}
public void setHeadName(String headName) {
this.headName = headName;
}
}
Model
public class Organisation {
private String name;
public Organisation() { }
public Organisation(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
controller
#RequestMapping(method = RequestMethod.GET)
public List<Organisation> getAll() {
Organisation organisation = new Organisation("google");
List<Organisation> organisations = new ArrayList<>();
organisations.add(organisation);
return organisations;
}
This will give out response like this:
[
{
"name": "google"
}
]
What if we want something like this:
{
"data": [{
"type": "organisations"
"attributes": {
"name": "google"
}
]
}
So how to customize the json. I know that Spring MVC by default uses Jackson to convert models into JSON. Is there a way to customize it. I am trying to send response in JSONApi standard. Also can someone tell how to create links in responses
Create Classes as:
public class Object1 {
private List<Object2> data;
public Object1() {
}
public Object1(List<Object2> data) {
this.data = data;
}
//getters and setters
}
public class Object2 {
private String type;
private Object3 attributes;
public Object2() {
}
public Object2(String type, Object3 attributes) {
this.type = type;
this.attributes = attributes;
}
//getters and setters
}
public class Object3 {
private String name;
public Object3(String name) {
this.name = name;
}
public Object3() {
}
//getters and setters
}
Now your controller method shoul be like:
#RequestMapping(method = RequestMethod.GET)
public Object3 getAll() {
List<Object2> data = new ArrayList<>();
data.add(new Object2("organisations", new Object3("google")));
return new Object1(data);
}
When I get List from server with spring I get in client object user like this:
{
"id": 1,
"name": "hgfhj",
"age": 120,
"createdDate": 1457211138000,
"admin": true
}
UserController.java method:
#RequestMapping(value = "/user/", method = RequestMethod.GET)
public ResponseEntity<List<User>> getList() {
List usersList = userService.getList();
ResponseEntity<List<User>> respEntity = null;
if(usersList.isEmpty()){
respEntity =new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);
return respEntity;
}
respEntity =new ResponseEntity<List<User>>(usersList, HttpStatus.OK);
return respEntity;
}
And when I use Gson I get in client object user like this:
{
"id": 1,
"name": "hgfhj",
"age": 120,
"isAdmin": true,
"createdDate": "Mar 5, 2016 10:52:18 PM"
}
UserController.java method:
#RequestMapping(value = "/user/", method = RequestMethod.GET)
public String getList() {
List usersList = userService.getList();
ResponseEntity<List<User>> respEntity = null;
respEntity =new ResponseEntity<List<User>>(usersList, HttpStatus.OK);
Gson gson = new Gson();
String json = gson.toJson(usersList);
return json;
}
In all project user property name "isAdmin", I do not understand why it's changed to "admin". How can I use spring but get in client "isAdmin" without gson?
User.java:
#Entity
public class User {
/*#Column(name="id")*/
#Id
#GeneratedValue
private int id;
#Column(name="name")
private String name;
#Column(name="age")
private int age;
#Column(name="isAdmin")
private boolean isAdmin;
#Column(name="createdDate")
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern = "dd.MM.yyyy")
private Date createdDate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public boolean isAdmin() {
return isAdmin;
}
public Date getCreatedDate() {
return createdDate;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setIsAdmin(boolean isAdmin) {
this.isAdmin = isAdmin;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
}
please do following changes into your User class's setter method,
#JsonProperty("isAdmin") // i guess you want isAdmin into response..
public void setIsAdmin(boolean isAdmin) {
this.isAdmin = isAdmin;
}
Annotate your User objects attributes with #JsonProperty to spesify the name you want as output.
Example
public class User {
...
#SerializedName("isAdmin")
#Column(name="isAdmin")
private boolean admin;
...
}
this will return something like
{
"isAdmin" : true
}
for more information: http://www.javacreed.com/gson-annotations-example/
Updated:
For future reference #JsonProperty("name") needs to be on the getters with gson, not the attributes.
I have seen multiple answers to this problem in stackoverflow and outside. But I am not able to understand the real issue here.
I have a pojo class which is given below.
public class User{
private int id;
private String name;
private String houseNumber;
private String location;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getname() {
return name;
}
public void setname(String name) {
this.name = name;
}
public String gethouseNumber() {
return houseNumber;
}
public void sethouseNumber(String houseNumber) {
this.houseNumber = houseNumber;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
I have a JSON file as follows:
[{
"id":1,
"name": "roy",
"houseNumber":"No/242",
"location" :"Germany"
},
{
"id":2,
"name": "philip",
"houseNumber":"No/252",
"location" :"Germany"
}]
Every json entry of the file has the field location with a value. But why am I getting the exception Unrecognized field "location" inspite of having the field in both my POJO and the JSON file? I would like to know the reason of this. Many solutions suggest using annotations for JSON like #JsonIgnoreProperties. It did not work for me.
Try using camel case correctly on your getters and setters, I know that does sometimes cause Jackson to produce unexpected results.
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHouseNumber() {
return houseNumber;
}
public void setHouseNumber(String houseNumber) {
this.houseNumber = houseNumber;
}
I tried your code and it works fine for me
The #JsonIgnoreProperties is not required. you can do the following
String jsonString = "[{\"id\":1,\"name\": \"roy\",\"houseNumber\":\"No/242\",\"location\" :\"Germany\"},{\"id\":2,\"name\": \"philip\",\"houseNumber\":\"No/252\",\"location\" :\"Germany\"}]";
ObjectMapper mapper = new ObjectMapper();
List<User> a = mapper.readValue(jsonString, new TypeReference<ArrayList<User>>() {});
I'm encountering problem with my android app for REST service.
I got following json response from server:
{
"0": {
"id": 1,
"name": "Some Guy",
"email": "example1#example.com"
},
"1": {
"id": 2,
"name": "Person Face",
"email": "example2#example.com"
},
"3": {
"id": 3,
"name": "Scotty",
"email": "example3#example.com",
"fact": {
"hobbies": ["fartings", "bikes"]
}
}
}
My objects are:
User class:
public class User {
#SerializedName("id")
private
int id;
#SerializedName("name")
private
String name;
#SerializedName("email")
private
String email;
#SerializedName("fact")
private
Fact fact;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Fact getFact() {
return fact;
}
public void setFact(Fact fact) {
this.fact = fact;
}
public User(){}
}
Fact class:
public class Fact {
#SerializedName("hobbies")
private List<Hobbies> hobbies;
public List<Hobbies> getHobbies() {
return hobbies;
}
public void setHobbies(List<Hobbies> hobbies) {
this.hobbies = hobbies;
}
public Fact(){}
}
Hobbies class:
public class Hobbies {
private String hobby;
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public Hobbies(){}
}
When I use below code in my app:
private User jsonToUser(String result){
User users = null;
if(result != null && result.length() > 0){
Gson gson = new GsonBuilder().create();
users = gson.fromJson(result, User.class);
}
return users;
}
Object returned by function is filled by nulls. I've tried to use class Users which is empty and extends ArrayList
public class Users extends ArrayList<User> {
//
}
and app was giving me error:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2
I wish to use it for:
ArrayAdapter<User> adapter = new ArrayAdapter<User>(activity, android.R.layout.simple_list_item_1, users);
Could you tell me what I'm doing wrong, please? It worked for my twitter timeline app, but doesn't wor for this.
Your code users = gson.fromJson(result, User.class); would work, if you want to convert a JSON string like { "id": 1, "name": "Some Guy", "email": "example1#example.com" } into one User object.
But a JSON string like yours
{
"0": {
"id": 1,
"name": "Some Guy",
"email": "example1#example.com"
},
...
}
is interpreted as an Array (or HashMap?!) of User objects.
Try the following using Array:
users = gson.fromJson(result, User[].class);
or (if GSON interprets it as a HashMap):
users = gson.fromJson(result, HashMap<String, User>.class);
The more elegant way using code from Collections example from the Gson user guide would be using Collection:
Type collectionType = new TypeToken<Collection<User>>(){}.getType();
Collection<User> users= gson.fromJson(result, collectionType);
In the "Collections limitations" part is written the following:
While deserializing, Collection must be of a specific generic type
I'm not sure, but that could mean, that you have to to set collectionType to use List and not Collection as specific type.
or (if GSON interprets it as a HashMap):
Type hashMapType = new TypeToken<HashMap<String, User>>(){}.getType();
HashMap<String, User> users= gson.fromJson(result, hashMapType);
Good luck =)
EDIT
My try with the last solution was successul:
public class User {
private String id, name, email;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
public static void main(String[] args) {
String result = ""
+ "{\"0\": { \"id\": 1, \"name\": \"Some Guy\", \"email\": \"example1#example.com\"},"
+ "\"1\": { \"id\": 2, \"name\": \"Person Face\", \"email\": \"example2#example.com\"}"
+ "}";
Gson gson = new Gson();
Type hashMapType = new TypeToken<HashMap<String, User>>() {
}.getType();
HashMap<String, User> users = gson.fromJson(result, hashMapType);
for (String key : users.keySet()) {
printUser(users.get(key));
}
}
private static void printUser(User user) {
System.out.printf("%s %s %s\n", user.getId(), user.getName(),
user.getEmail());
}