Android and json using gson from REST service with nested objects - java

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());
}

Related

why don't you see the "keys" in the json?

when I enter postman, I get the json, but without his "keys" why? Maybe I'm making a mistake and I haven't noticed. Some help please.
I am using a stored procedure to be able to do a crud.
this is the json that shows me postman. Shows me without his "key"
{
"data": [
[
1,
"aaa",
"aaa#gmail.com"
],
[
2,
"bbb",
"bbb#gmail.com"
],
[
3,
"ccc",
"ccc#gmail.com"
]
]
}
I would like to get something like this.
{
"data": [
{
userCod: 1,
userName: "aaa",
userEmail: "aaa#gmail.com"
},
{
userCod: 2,
userName: "bbb",
userEmail: "bbb#gmail.com"
},
{
userCod: 3,
userName: "ccc",
userEmail: "ccc#gmail.com"
}
]
}
I leave the code
public class ApiResponse {
private List<UserTest> data;
public List<UserTest> getData() {
return data;
}
public void setData(List<UserTest> data) {
this.data = data;
}
}
#Entity
#Table(name = "tbUsers")
public class UserTest implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "userCod")
private Long id;
#Column(name = "userName")
private String name;
#Column(name = "userEmail")
private String email;
public Long getId() {
return id;
}
public void setId(Long 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;
}
}
#Repository
public class ClienteDaoImpl implements IClienteDao{
#Autowired
private EntityManager em;
#SuppressWarnings("unchecked")
#Override
public ApiResponse mntUsers(int op) {
ApiResponse api = new ApiResponse();
Session session = em.unwrap(Session.class);
ProcedureCall call = session.createStoredProcedureCall("sp_MntUser");
call.registerParameter(1, Integer.class, ParameterMode.IN);
call.setParameter(1, op);
call.execute();
api.setData(call.getResultList());
return api;
}
}
#RestController
#RequestMapping(value = "/mntUsers")
public class ClienteController {
#Autowired
private ClienteServiceImpl serviceImpl;
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> CrudUsers(#RequestParam(value = "option", required = true) Integer op) {
return new ResponseEntity<>(serviceImpl.mntUsers(op),HttpStatus.OK);
}
}
Create a method called getCollectionType
public static <T, C extends Collection<T>> C getCollectionType(Iterable<?> from, C to, Class<T> listClass) {
for (Object item: from) {
to.add(listClass.cast(item));
}
return to;
}
Then use it on the following line:
api.setData(getCollectionType(call.getResultList(),
new ArrayList<UserTest>(),
UserTest.class));

Retrofit 2 return List from Json is empty

I have been fighting with Retrofit 2.3 for about 2 weeks now. The List always comes back as empty for me. It simply makes a call and gets the JSON information yet it won't process the list.
Json appears like this:
{
"users": [
{
"id": 2,
"name": "Users Name",
"username": "myusername",
"facebook_id": null,
"level": "1",
"birthdate": "1999-09-09T00:00:00+00:00",
"email": "user#gmail.com",
"activated": "",
"created": "2017-12-07T04:18:30+00:00",
"answers": [
{
"id": 31,
"question_id": 2,
"user_id": 2,
"answer": "School",
"questions": [
{
"id": 2,
"question": "Where did you meet your best friend?"
}
]
},
{
"id": 32,
"question_id": 3,
"user_id": 2,
"answer": "Dog",
"questions": [
{
"id": 3,
"question": "What was your first pet's name?"
}
]
}
]
}
],
"message": "Success"
}
Retrofit Interface class:
public interface RestInterface {
String url = "http://myurl.com";
/**
* Login
*
* #param username Username
* #param password Password
*
*/
#FormUrlEncoded
#Headers("User-Agent:My-Application")
#POST("login")
Call<userlogin> Login(#Field("username") String username,
#Field("password") String password);
}
Userlogin class:
public class userlogin {
#SerializedName("users")
#Expose
private List<users> users;
#SerializedName("message")
#Expose
private Object message;
public List<users> getUsers() {
return users;
}
public void setUsers(List<users> users) {
this.users = users;
}
public Object getMessage() {
return message;
}
public void setMessage(Object message) {
this.message = message;
}
}
users class:
public class users {
#SerializedName("id")
#Expose
private Integer id;
#SerializedName("name")
#Expose
private String name;
#SerializedName("username")
#Expose
private String username;
#SerializedName("facebook_id")
#Expose
private String facebookId;
#SerializedName("level")
#Expose
private String level;
#SerializedName("birthdate")
#Expose
private String birthdate;
#SerializedName("email")
#Expose
private String email;
#SerializedName("activated")
#Expose
private String activated;
#SerializedName("created")
#Expose
private String created;
#SerializedName("answers")
#Expose
private List<Answer> answers = null;
public users(){
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getFacebookId() {
return facebookId;
}
public void setFacebookId(String facebookId) {
this.facebookId = facebookId;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
public String getBirthdate() {
return birthdate;
}
public void setBirthdate(String birthdate) {
this.birthdate = birthdate;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getActivated() {
return activated;
}
public void setActivated(String activated) {
this.activated = activated;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public List<Answer> getAnswers() {
return answers;
}
public void setAnswers(List<Answer> answers) {
this.answers = answers;
}
}
Basically what happens is when it is called my "message" part comes back "Successful" which on my PHP side basically just states there were no errors. If there were any then it would return the error for display.
When trying to get the users information it always comes back with an empty List.
My response is always the same:
03-14 20:06:26.698 30995-30995/com.josh.testapp D/Response: {"message":"Success","users":[]}
03-14 20:06:26.699 30995-30995/com.josh.testapp I/System.out: Users:: []
03-14 20:06:26.699 30995-30995/com.josh.testapp D/Message: Success
I'm not sure what it is I'm missing. The users should be coming back as a list containing user information, in this case just the information of the user logging in. But in other parts, this will display sub-users information as well which is why it is in List form in the first place.
Please help or guide me in the right direction.
login.java (where the call is made)
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RestInterface.url)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
RestInterface restInterface = retrofit.create(RestInterface.class);
Call<userlogin> call = restInterface.Login(
username.getText().toString(), // username
pass.getText().toString() // password
);
call.enqueue(new Callback<userlogin>() {
#Override
public void onResponse(Call<userlogin> call, retrofit2.Response<userlogin> response) {
if (response.isSuccessful()) {
userlogin ul = response.body();
try{
String res = new Gson().toJson(response.body());
Log.d("Response", res);
System.out.println("Users:: " + ul.getUsers().toString());
Log.d("Message", ul.getMessage().toString());
List<users> userList = ul.getUsers();
for(int i = 0; i < userList.size(); i++){
Log.d("Users", userList.get(i).getUsername());
}
} catch (Exception e){
Log.d("exception", e.getMessage());
}
} else {
Log.d("unSuccessful", response.message());
}
}
#Override
public void onFailure(Call<userlogin> call, Throwable t) {
Log.d("onFailure", t.getMessage());
}
});
After AbdulAli pointed out that it appeared to not be receiving the users list I decided to look over my code and run a few more tests on the server API. I discovered there was an issue with sessions. They weren't picking up and therefor returned a "Successful" yet empty user list. After implementing some CookieJar functions in I was able to pass my cookie for sessions and the user list was no longer empty.
While I feel like an idiot for missing something so obvious, I am very grateful for you pointing that out AbdulAli.

Convert a received JSON response to List<T> in Java

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.

Spring boot REST API Missing URI template variable

I have followed this tutorial to build REST API using Spring boot. It taught alot. But What I am trying to do really got me stuck.
What I am trying to get is:
{
"marks":{
"id":"1",
"name":"test",
"remark":"passed",
"course": {
"id": "1",
"name": "Spring Boot",
"description": "Solves many problems",
"topic": {
"id": "1",
"name": "Java",
"description": "Powerful Programming Language"
}
}
But I get the error when I tried to add the marks- as :
{
"timestamp": 1515600105327,
"status": 500,
"error": "Internal Server Error",
"exception": "org.springframework.web.bind.MissingPathVariableException",
"message": "Missing URI template variable 'courseId' for method parameter of type String",
"path": "/topics/1/courses/1/marks"
}
My Marks Model is:
public class Marks {
#Id
private String id;
private String name;
private String remark;
#ManyToOne
private Course course;
#ManyToOne
private Topic topic;
public Marks() {
}
public Topic getTopic() {
return topic;
}
public void setTopic(Topic topic) {
this.topic = topic;
}
public Marks(String id, String name, String remark,String topicId, String courseId) {
this.id = id;
this.name = name;
this.remark = remark;
this.topic = new Topic(topicId, "","");
this.course = new Course(courseId, " ", " ", " ");
}
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 getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
}
And MarksController.java:
public class MarksController {
#RestController
public class MarksController {
#Autowired
private MarksService marksService;
#RequestMapping("/topics/{topicId}/courses/{id}/marks")
public List<Marks> getAllMarks(#PathVariable String courseId) {
return marksService.getAllMarks(courseId);
}
#RequestMapping(method=RequestMethod.POST, value="/topics/{topicId}/courses{courseId}/marks")
public void addMarks(#RequestBody Marks marks,#PathVariable String topicId ,#PathVariable String courseId) {
marks.setTopic(new Topic(topicId, "", ""));
marks.setCourse(new Course(courseId, "", "", ""));
marksService.addMarks(marks);
}
}
And MarksService.java:
public class MarksService {
#Service
public class MarksService {
#Autowired
private MarksRepository marksRepository;
public void addMarks(Marks marks) {
marksRepository.save(marks);
}
}
And MarksRepository.java:
public interface MarksRepository extends CrudRepository<Marks, String> {
public List<Marks> findByCourseId(String courseId);
public List<Marks> findByTopicId(String topicId);
}
Can anyone help me get the result as in the mentioned JSON.
For the POST method
This:
/topics/{topicId}/courses{courseId}/marks
Should be:
/topics/{topicId}/courses/{courseId}/marks
Note the additional / between courses and {courseId}
For the GET method
This:
/topics/{topicId}/courses/{id}/marks
Should be:
/topics/{topicId}/courses/{courseId}/marks
Note the use of courseId to agree with the parameter name in MarksController.getAllMarks.

GSOn error Expected a string but was BEGIN_OBJECT when parsing JSON response

I retrieve a JSON result from an API :
[{
"oid": "axd7wtlk6xd2fbwlc5wk",
"id": "aazzzza",
"name": "aazzaa",
"logo": {
"type": 0,
"data": "iVB.............5CYII="
},
"timestamp": 1438608571013,
"email": "contact#azzaa.net",
"modified": "test",
"url": "http://www.azzaa.net"
},
{
"oid": "quj3dzygfwygl5uxsbxk",
"name": "KZZZ",
"modified": "test",
"timestamp": 1438854099511,
"id": "kess"
},...]
but when I try to map to a customer object I get the error Expected a string but was BEGIN_OBJECT :
response = webService.RequestGet(url, header);
result = null;
try {
result = new JSONArray(response);
Utils.LogWarning(response);
} catch (JSONException e) {
Utils.LogError("Could not load json response", e);
}
Type customerType = new TypeToken<Collection<Customer>>() {
}.getType();
ArrayList<Customer> alCustomers = null;
alCustomers = new Gson().fromJson(result.toString(), customerType);
Here is my Customer class :
public class Customer implements Serializable {
private String id = "";
private String name = "";
private String email = "";
private String url = "";
private String address = "";
private String stamp = "";
//private transient String logo = "";
private long timestamp = 0L;
private String modified = "";
...
}
I have been through a lot of answers regarding this problem that I have also for other types of objects, but I can't find a working solution.
Create a modal with the values of JSON result like
public class Customer {
private String oid;
private String id;
private String name;
private String timestamp;
private String email;
private String modified;
private String url;
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
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 getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getModified() {
return modified;
}
public void setModified(String modified) {
this.modified = modified;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Logo getLogo() {
return logo;
}
public void setLogo(Logo logo) {
this.logo = logo;
}
private Logo logo;
}
public class Logo {
private int type;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
private String data;
}
Gson gson = new Gson();
Type listType = new TypeToken<List<Customer>>(){}.getType();
List<Customer> customer= (List<Customer>) gson.fromJson(jsonOutput, listType);

Categories