Parsing nested objects with Jackson - java

I am using Robospice + Retrofit + Jackson. I have not plain class which has another class object as a field. I need to parse json and create class with field.
Here is my class
#JsonIgnoreProperties(ignoreUnknown=true)
public class User implements UserInformationProvider {
#JsonProperty("customer_id")
public int id;
#JsonProperty("firstname")
public String firstName;
#JsonProperty("lastname")
public String lastName;
#JsonProperty("email")
public String email;
#JsonProperty("telephone")
public String phone;
#JsonProperty("token_api")
public String token;
#JsonProperty("token_expire")
public int tokenExpireTime;
public UserPreferences userPreferences;
#Override
public String getUserFirstName() {
return firstName;
}
#Override
public String getUserLastName() {
return lastName;
}
#Override
public String getUserEmail() {
return email;
}
#Override
public String getUserIconUrl() {
return null;
}
}
And preferences class
public class UserPreferences {
public boolean offersNotifications;
public boolean statusChangedNotifications;
public boolean subscriptionNotifications;
#JsonProperty("new_offers")
public boolean newOffersNotify;
#JsonProperty("order_status_changed")
public boolean orderStatusChangedNotify;
#JsonProperty("hot_offers")
public boolean hotOffersNotify;
}
Request that I need to parse into POJO.
{
"customer_id": 84,
"token_api": "ef5d7d2cd5dfa27a",
"token_expire_unix": "1435113663",
"preferences": {
"new_offers": "1",
"order_status_changed": "1",
"hot_offers": "1"
}
}
Please help, how can I do this using Jackson. I would be very grateful for any help. Thanks in advance.

The main problem lies inside of UserPreferences. Right now your code is attempting to deserialize "1" as a boolean. Java will not do this translation for you, so you will need to create a custom deserializer and apply it to the fields with numeric booleans.
Create a Custom Deserializer
A deserializer allows you to specify a class and apply custom operations to how it is created from JSON:
public class NumericBooleanDeserializer extends JsonDeserializer<Boolean> {
#Override
public Boolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
int intValue = p.getValueAsInt();
switch (intValue) {
case 0:
return Boolean.TRUE;
case 1:
return Boolean.FALSE;
default:
// throw exception or fail silently
}
return null; // can throw an exception if failure is desired
}
}
Apply Custom Deserialization to Fields
Since you probably don't want to register this on your ObjectMapper and apply it to all deserialization, you can use the #JsonDeserialize annotation. Your UserPreferences class will end up looking something like this:
public class UserPreferences {
public boolean offersNotifications;
public boolean statusChangedNotifications;
public boolean subscriptionNotifications;
#JsonProperty("new_offers")
#JsonDeserialize(using = NumericBooleanDeserializer.class)
public boolean newOffersNotify;
#JsonProperty("order_status_changed")
#JsonDeserialize(using = NumericBooleanDeserializer.class)
public boolean orderStatusChangedNotify;
#JsonProperty("hot_offers")
#JsonDeserialize(using = NumericBooleanDeserializer.class)
public boolean hotOffersNotify;
}
Make Sure #JsonProperty Matches JSON Keys
Since your JSON has "preferences" and the name of your Java property is userPreferences you will need to slap a #JsonProperty("preferences") on the property inside of User

Related

Deserializing JSON wrapper object with list returns null properties

I got json like below:
{"examinationTypes":[{"ExaminationTypeVO":{"id":1,"name":"Badanie krwi"}},{"ExaminationTypeVO":{"id":2,"name":"Spirometria"}},{"ExaminationTypeVO":{"id":3,"name":"Wymaz"}},{"ExaminationTypeVO":{"id":4,"name":"Ciśnienie"}},{"ExaminationTypeVO":{"id":5,"name":"EKG"}},{"ExaminationTypeVO":{"id":6,"name":"Elektrowstrząsy"}},{"ExaminationTypeVO":{"id":7,"name":"Tomografia"}},{"ExaminationTypeVO":{"id":8,"name":"Lewatywa"}},{"ExaminationTypeVO":{"id":9,"name":"Aneskopia"}},{"ExaminationTypeVO":{"id":10,"name":"Rektoskopia"}},{"ExaminationTypeVO":{"id":11,"name":"Kolonoskopioa"}},{"ExaminationTypeVO":{"id":12,"name":"Echo serca"}},{"ExaminationTypeVO":{"id":13,"name":"Ablacja"}},{"ExaminationTypeVO":{"id":14,"name":"Badnaie dopplerowskie"}},{"ExaminationTypeVO":{"id":15,"name":"Kapilaroskopia"}}]}
I have defined types:
#JsonRootName(value="ExaminationTypeVO")
#JsonIgnoreProperties(ignoreUnknown = true)
public class ExaminationTypeVO {
private Long id;
private String name;
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;
}
}
and
public class ExaminationTypesVO {
private List<ExaminationTypeVO> examinationTypes;
public List<ExaminationTypeVO> getExaminationTypes() {
return examinationTypes;
}
public void setExaminationTypes(List<ExaminationTypeVO> examinationTypes) {
this.examinationTypes = examinationTypes;
}
When I am deserializing it like that:
ExaminationTypesVO l = m.readValue(result, ExaminationTypesVO.class);
I receive an wrapper object but the list inside contains objects of type ExaminationTypeVO with all properties set to null.
Can anybody help to figure it out?
Your issue is that you have an extra level of object that you are trying to deserialize. Trying to not be confusing as I explain this: you have an array of objects, those objects contain a single ExaminationTypeVO object.
If you are stuck with the structure of the JSON that you provided, then you will need to add another "level" to your deserialization. You can do this via a wrapper object inside of your ExaminationTypesVO class:
public class ExaminationTypesVO {
private List<ExaminationTypeVOWrapper> examinationTypes;
public List<ExaminationTypeVOWrapper> getExaminationTypes() {
return examinationTypes;
}
public void setExaminationTypes(List<ExaminationTypeVOWrapper> examinationTypes) {
this.examinationTypes = examinationTypes;
}
public static class ExaminationTypeVOWrapper {
private final ExaminationTypeVO examinationTypeVO;
#JsonCreator
public ExaminationTypeVOWrapper(#JsonProperty("ExaminationTypeVO") ExaminationTypeVO examinationTypeVO) {
this.examinationTypeVO = examinationTypeVO;
}
public ExaminationTypeVO getExaminationTypeVO() {
return examinationTypeVO;
}
}
}
If you have control over the JSON that you are deserializing, you can just remove the extra "level" (ExaminationTypeVO wrapping object) and not have to change your code. Your new JSON in this approach would look like:
{
"examinationTypes": [
{
"id": 1,
"name": "Badanie krwi"
}, ...
]
}
With either of these approaches you can remove both of the class-level annotations you have on ExaminationTypeVO.

How to grab JSON Array and use gson to parse each json object? (Retrofit)

I am returning an array of results with my json Objects, and I am trying to use my customObjectResponse class to pull out each of the fields within each of the objects... the problem it is expecting an object so how do I edit my class to allow it to take in an array of object to be able to then call the fields of each object... I am confused as to what needs to be added:
Here is a response example of what is being passed to be used:
[
{
itemId: 'dfsdfsdf343434',
name: 'tests',
picture: '6976-7jv8h5.jpg',
description: 'testy.',
dateUpdated: 1395101819,
}
]
Here is my response Object Class:
public class ObjResponse{
private String itemId;
private String name;
private String picture;
private String description;
private String location;
private int dateUpdated;
private String msg;
//gridview constructor
public ObjResponse(String picture) {
this.picture = picture;
}
//public constructor
public ObjResponse() {
}
public String getItemId() {
return itemId;
}
public void setItemId(String itemId) {
this.itemId = itemId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getDateUpdated() {
return dateUpdated;
}
public void setDateUpdated(int dateUpdated) {
this.dateUpdated = dateUpdated;
}
public String getMsg() {
return msg;
}
}
what I am trying, but is not working, even if I separate the classes into their own files:
Data passed in:
items: [{obj1: "A", obj2: ["c", "d"]}, {etc...}]
public class Response {
public class List<Custom> {
private List<Custom> items;
}
public class Custom {
private String obj1;
private List<Obj2> obj2;
}
public Class Obj2 {
private String letters;
}
}
I ended up just calling in the callback a list of the customObject and it did the job...
new Callback<List<ObjResponse>>() {
I originally had trouble getting an idea of how the OP solved his problem but, after days of debugging I have finally figured out how to solve this issue.
So you essentially have data in the format like so (JSON Array of JSON Objects):
[
{
...
}
]
Your class that models the data and contains the getter and setter methods are nothing more than your typical POJO.
public class Person implements Serializable {
#SerializedName("Exact format of your json field name goes here")
private String firstName;
// Getters and Setters....
}
In your interface that contains your RESTful annotations you want to convert your call from:
Before:
public interface APInterface {
#GET("SOME URL TO YOUR JSON ARRAY")
Call<Person>(...)
}
After:
public interface APInterface {
#GET("SOME URL TO YOUR JSON ARRAY")
Call<List<Person>>(...)
}
In your android activity you want to convert all calls in the form of Call<Person> to Call<List<Person>>
Finally when making the initial asynchronous request call, you will want to convert your callbacks like so.
call.enqueue(new Callback<List<Person>>() {
#Override
public void onResponse(Call<List<Person>> call, Response<List<Person>> response) {
if(response.isSuccessful()){
List<Person> person = response.body();
// Can iterate through list and grab Getters from POJO
for(Person p: person){...}
} else {
// Error response...
}
}
#Override
public void onFailure(Call<List<Person>> call, Throwable t) {...}
});
Hope this helps others whom are lost from the accepted answer above.
This can also work by just passing an array of response objects. So if this is your response object:
public class CustomUserResponse {
public String firstName;
public String lastName;
...
}
You can use related syntax, depending on how you use the callbacks. Such as:
new Callback<CustomUserResponse[]>(){
#Override
public void success(CustomUserResponse[] customUserResponses, Response rawResponse) {
}
#Override
public void failure(RetrofitError error) {
}
};
OR
public class GetUserCommand implements Callback<CustomUserResponse[]> { ...
Put simply, in every place where you normally replace T with a response class, replace it with an array, instead as in CustomUserResponse[].
NOTE: to avoid confusing errors, be sure to also use an array in the Retrofit interface definition:
#POST ( "/users" )
public void listUsers(#Body GetUsersRequest request, Callback<CustomUserResponse[]> callback);
You could try something like this
JSONObject jsonObject = new JSONObject(<your JSON string result>);
JSONArray jsonArray = jsonObject.getJSONArray();
//use GSON to parse
if (jsonArray != null) {
Gson gson = new Gson();
ObjResponse[] objResponse = gson.fromJson(jsonArray.toString(), ObjResponse[].class);
List<ObjResponse> objResponseList = Arrays.asList(objResponse);
}
This should definitely work.

How do I parse an value that can be an object or a string - Java - Jackson

I am using Jackson to deserialize some xml. My xml has a value that can be an object or a string. Here is my xml
<FormFieldHidden name="RequestTime">
<DefaultValue>
<DataSourceName>DataSourceCurrentTime</DataSourceName>
</DefaultValue>
</FormFieldHidden>
<FormFieldHidden name="TradPtnrID">
<DefaultValue>043355932</DefaultValue>
</FormFieldHidden>
Here is my java:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Forms {
public Form form;
public Forms() {
form = new Form();
}
public static class Form extends Asset {
public String version;
public String description;
public List<Section> sections;
}
public static class Section {
public String label;
public int totalColumns;
public List<FormFieldHidden> formFields;
}
public static class FormFieldHidden {
public String defaultValue;
}
}
How can I pull out the defaultValue whether it is an object or string?
I havent work with Jackson but maybe instanceof will help,
in pseudocode
if (value instanceof Class){Class c=value;}
else{String s=value;}

Serialize using Jackson ObjectMapper

I am trying to serialize the below ArrayList of GAccount objects using Jackson library with following code:
List<Gaccount> gAccounts;
ObjectMapper mapper=new ObjectMapper();
json=mapper.writeValueAsString(gAccounts);
However, I have noticed that only Id and Name fields are serialized but not properties. Sorry, but I am new to Jackson library. Do I have to manually serialize that field ?
package in.co.madhur.ganalyticsdashclock;
import java.util.ArrayList;
import java.util.List;
public class GAccount
{
private String Id;
private String Name;
private List<GProperty> properties=new ArrayList<GProperty>();
public GAccount(String Id, String Name)
{
this.Id=Id;
this.Name=Name;
}
public String getName()
{
return Name;
}
public void setName(String name)
{
Name = name;
}
public String getId()
{
return Id;
}
public void setId(String id)
{
Id = id;
}
List<GProperty> getProperties()
{
return properties;
}
void setProperties(List<GProperty> properties)
{
this.properties = properties;
}
#Override
public String toString()
{
return Name;
}
}
The default visibility is to use all public getter methods and all public properties. If you make the getter this:
public List<GProperty> getProperties()
it should work.
You could also change the auto-detection defaults, but it's overkill here. See http://www.cowtowncoder.com/blog/archives/2011/02/entry_443.html for more info.
I am using jackson 2.9.0. The default visibility is always 'false' to all the members. In this case, we alway need to use a different visibility, otherwise the result json string will be empty. Here is the code extracted from JsonAutoDetect
public boolean isVisible(Member m) {
switch(this) {
case ANY:
return true;
...
case PUBLIC_ONLY:
return Modifier.isPublic(m.getModifiers());
default:
return false;
}
}

GSON.fromJson nested Java Objects

I am trying to make updates to my android app to accomodate the recent facebook changes with pictures. Previously i just got a string back for the user photo but not its returning an array. I have updated my code but the data is just coming back null, can someone point me in the right direction?
Thanks
GSON call
Gson gson = new GsonBuilder().create();
FBFriendResponse resp = gson.fromJson(response, FBFriendResponse.class);
New facebook data structure
"picture": {
"data": {
"url": "######.jpg",
"is_silhouette": false
}
}
public class FBFriend implements Comparable<FBFriend>
{
public String id, name, gender;
public FBFriendPicture picture;
#Override
public int compareTo(FBFriend another) {
return this.name.compareTo(another.name);
}
}
public class FBFriendPicture
{
public FBFriendPictureData pictureData;
}
public class FBFriendPictureData
{
public String friendPictureURL;
public Boolean friendPictureIssilhouette;
}
Resolved the issue. It was due to the wrong names used in the classes
public class FBFriend implements Comparable<FBFriend>
{
public String id, name, gender;
public FBFriendPicture picture;
#Override
public int compareTo(FBFriend another) {
return this.name.compareTo(another.name);
}
}
public class FBFriendPicture
{
public FBFriendPictureData data;
}
public class FBFriendPictureData
{
public String url;
public Boolean is_silhouette;
}

Categories