I am facing with a IMHO a strange behaviour of GSON. Let's take the following example:
{
"Name": "emaborsa",
"Surname": null
}
and my POJO is:
public class User {
#SerializedName("Name")
private String name;
#SerializedName("Surname")
private String surname;
// getter and setter
}
I deserialize it using the following code:
Gson g = new Gson();
User user = g.fromJson(json, User.class);
The variable name is set with "emaborsa", the variable surname I expected it were set to null but there is a string "null " instead.
Is it the correct behaviour or am I missing something? I tried to google it but it is hard to find something related to String and null...
This worked fine for me, using your code as the basis:
package gsonexample3;
import com.google.gson.Gson;
import com.google.gson.annotations.*;
public class User {
public static void main(String[] args) {
Gson g = new Gson();
User user = g.fromJson(json, User.class);
}
#SerializedName("Name")
private String name;
#SerializedName("Surname")
private String surname;
private static String json = "{\"Name\": \"emaborsa\", \"Surname\": null}";
}
Looks like you have to specify that you want to serialize nulls.
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.serializeNulls()
Coming from - https://howtodoinjava.com/gson/serialize-null-values/
Related
I'm trying to fetch JSON data from my website throw REST API with retrofit2.
But when I run the app this error message show:
Can not find a (Map) Key deserializer for type [simple type, class com.example.app.ReferralApiModel]
I'm using retrofit library.
This is my code for the retrofit call:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(AppConfig.URL)
.addConverterFactory(JacksonConverterFactory.create())
.client(defaultHttpClient)
.build();
ReferralsPlaceHolderApi placeHolderApi = retrofit.create(ReferralsPlaceHolderApi.class);
Call<List<Map<ReferralApiModel, String>>> call = placeHolderApi.getReferrals();
And this is my ReferralsPlaceHolderApi class:
public interface ReferralsPlaceHolderApi {
#JsonDeserialize(keyAs = ReferralsCustomDeserializer.class)
#GET(AppConfig.ENDPOINT_REFERRALS)
Call<List<Map<ReferralApiModel, String>>> getReferrals();
}
Also this is my ReferralApiModel class:
public class ReferralApiModel {
private String date;
private String amount;
private String currency;
private String status;
public ReferralApiModel() {}
public ReferralApiModel(String date, String amount, String currency, String status) {
this.date = date;
this.amount = amount;
this.currency = currency;
this.status = status;
}
public String getDate() {
return date;
}
public String getAmount() {
return amount;
}
public String getCurrency() {
return currency;
}
public String getStatus() {
return status;
}
}
This is the json data that I'm trying to get:
"[{\"id\":\"1\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"1\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"302\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 12:53:29\",\"status\":\"0\",\"payment\":\"0\",\"username\":\"aaa\"},{\"id\":\"2\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"2\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"303\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 13:03:43\",\"status\":\"1\",\"payment\":\"0\",\"username\":\"aaa\"},{\"id\":\"3\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"2\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"304\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 13:04:33\",\"status\":\"2\",\"payment\":\"0\",\"username\":\"aaa\"}]"
Can anyone help me with this?.
Also I've found that this problem may be a class mapping problem, from this answer :
https://stackoverflow.com/a/16383752/8055951
If it's ?!, Can someone tell me how to map the ReferralsPlaceHolderApi class.
Thanks.
Jackson cannot deserialize custom classes as map keys. The key of your deserialized map is ReferralApiModel. I order to achieve it, you need to write your own KeyDeserializer and register it for your class with Jackson. You can see here or here how to do that.
Also the json string in the question makes it look as if you don't need to deserialize into List<Map<ReferralApiModel, String>>, but into List<ReferralApiModel> instead. Which would make writing custom key deseriaslizers redundant.
Edit: Ok, receiving json array, which has been json sting-ified is just strange. It would be best, if someone on your team is responsible for this API and can fix it. If not, you have workarounds:
Parse twice with object mapper - first parse it to normal string, which would be json array, then parse this string into List<YourObject>
ObjectMapper mapper = new ObjectMapper();
String string = mapper.readValue(initialJson, String.class);
List<ReferralApiModel> list = mapper.readValue(string, TypeFactory.defaultInstance().constructCollectionType(List.class, ReferralApiModel.class));
list.forEach(System.out::println);
Turn it manually into proper json array. That means remove first and last char - double quote, and remove all those escapes - \. Something like this:
String jsonString = "the string";
jsonString = jsonString.substring(1, jsonString.length() - 1).replace("\\", "");
ObjectMapper mapper = new ObjectMapper();
List<ReferralApiModel> list = mapper.readValue(jsonString, TypeFactory.defaultInstance().constructCollectionType(List.class, ReferralApiModel.class));
list.forEach(System.out::println);
I have this as a substring. It is a JSON string. I am trying to get the id string from it. I was able to do this by using two indexOf's and then substring the two indexOf's. What is a better solution.
Here is my string
"{"id":"762c094a-4b65-499e-b5b2-de34ef8d726e","createdTimestamp":1605558195131,"username":"sssdv","enabled":false,"totp":false,"emailVerified":false,"firstName":"cdf","lastName":"dddz","email":"hgddf#fdaddf.com","disableableCredentialTypes":[],"requiredActions":[],"notBefore":0,"access":{"manageGroupMembership":true,"view":true,"mapRoles":true,"impersonate":true,"manage":true}}"
And here is my code.
int id = results.indexOf("id");
int cr = results.indexOf("createdTimestamp");
String strId = results.substring(id + 5, cr - 3);
A better solution is to use an actual JSON parser. There are plenty out there. Take a look at this answer on a different question. I would suggest using Gson:
String json = "{\"id\":\"762c094a-4b65-499e-b5b2-de34ef8d726e\",\"createdTimestamp\":1605558195131,\"username\":\"sssdv\",\"enabled\":false,\"totp\":false,\"emailVerified\":false,\"firstName\":\"cdf\",\"lastName\":\"dddz\",\"email\":\"hgddf#fdaddf.com\",\"disableableCredentialTypes\":[],\"requiredActions\":[],\"notBefore\":0,\"access\":{\"manageGroupMembership\":true,\"view\":true,\"mapRoles\":true,\"impersonate\":true,\"manage\":true}}";
Gson gson = new GsonBuilder().setPrettyPrinting().create(); // Create the Gson instance
JsonElement element = gson.fromJson(json, JsonElement.class); // Parse it
String id = element.getAsJsonObject().get("id").getAsString(); // Get your desired element
System.out.println(id);
An even better solution would be to create a class with the fields from your JSON and parse the JSON string to that class:
public class MyObject {
// The names and types of these fields must match the ones in your JSON string
private String id, username, firstName, lastName, email;
private long createdTimestamp;
private boolean enabled, totp, emailVerified;
private String[] disableableCredentialTypes, requiredActions;
private int notBefore;
private Access access;
public String getId() {
return id;
}
// Other getters and setters...
private static class Access {
private boolean manageGroupMembership, view, mapRoles, impersonate, manage;
// ...
}
public static void main(String[] args) throws IOException {
String json = "{\"id\":\"762c094a-4b65-499e-b5b2-de34ef8d726e\",\"createdTimestamp\":1605558195131,\"username\":\"sssdv\",\"enabled\":false,\"totp\":false,\"emailVerified\":false,\"firstName\":\"cdf\",\"lastName\":\"dddz\",\"email\":\"hgddf#fdaddf.com\",\"disableableCredentialTypes\":[],\"requiredActions\":[],\"notBefore\":0,\"access\":{\"manageGroupMembership\":true,\"view\":true,\"mapRoles\":true,\"impersonate\":true,\"manage\":true}}";
Gson gson = new GsonBuilder().setPrettyPrinting().create(); // Create the Gson instance
MyObject object = gson.fromJson(json, MyObject.class); // Parse the string to your data type
System.out.println(object.getId()); // Print the id
}
}
String results = "{\"id\":\"762c094a-4b65-499e-b5b2-de34ef8d726e\",\"createdTimestamp\":1605558195131,\"username\":\"sssdv\",\"enabled\":false,\"totp\":false,\"emailVerified\":false,\"firstName\":\"cdf\",\"lastName\":\"dddz\",\"email\":\"hgddf#fdaddf.com\",\"disableableCredentialTypes\":[],\"requiredActions\":[],\"notBefore\":0,\"access\":{\"manageGroupMembership\":true,\"view\":true,\"mapRoles\":true,\"impersonate\":true,\"manage\":true}}";
String[] parts = results.split("\"");
System.out.println(parts[3]); //gives the id, every time
Getting empty java object while populating the following type of Json.
a.json:
------
{
"queries": [{
"query": {
"id": "q1",
"description": "Fire query to get the Auth token !!"
}
}
],
"executeQuery": ["q2", "q3"]
}
Query.java :
-----------
Note : #Data will take care of creating setter getter by Lombok library.
#Data
public class Query {
#Expose #SerializedName("id")
String id;
#Expose #SerializedName("description")
String description;
}
GRT.java :
----------
#Data
public class GRT{
#Expose #SerializedName("queries")
List<Query> queries ;
#Expose #SerializedName("executeQuery")
List<String> executeQuery;
}
Client call :
----------------------------------------------
private void readJson() throws IOException{
String fileName = "a.json";
// Get Gson object
Gson gson = newGsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
// read JSON file data as String
String fileData = new String(Files.readAllBytes(Paths.get(fileName)));
// parse json string to object
GenericRestTestDefinition grtDef = gson.fromJson(fileData, GenericRestTestDefinition.class);
System.out.println(grtDef.toString());
}
Printing the following :
GRT(queries=[Query(id=null, description=null)], executeQuery=[q2, q3])
Dont know why GRT-> Query Object is not getting populated ????
The proper JSON for this would look like this..
{
"queries":
[
{"id":"q1","description":"Fire query to get the Auth token"},
{"id":"q2","description":"Fire query to get the Auth token 2"}
]
}
public class Test {
public static void main(String[] args) throws Exception {
readJson();
}
private static void readJson() throws IOException {
String json ="{\"queries\":[{\"id\":\"q1\",\"description\":\"Fire query to get the Auth token\"}]}";
// Get Gson object
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
GRT grt = new GRT();
grt.setQueries(Arrays.asList( new Query[]{new Query("q1", "Fire query to get the Auth token")} ));
System.out.println(gson.toJson(grt));
// parse json string to object
GRT grtDef = gson.fromJson(json, new TypeToken<GRT>(){}.getType());
System.out.println(grtDef.queries.get(0));
}
}
If you can't change the json file format you can use this pattern:
#Data
public class GRT{
#Expose #SerializedName("queries")
private List<QueryWrapper> queries = new ArrayList<>();
public List<Query> getQueries() {
return queries.stream().map(it->it.query).collect(Collectors.toList());
}
#Expose #SerializedName("executeQuery")
List<String> executeQuery = new ArrayList<>();
}
#Data
public class QueryWrapper {
#Expose #SerializedName("query")
Query query;
}
#Data
public class Query {
public
#Expose #SerializedName("id")
String id;
#Expose #SerializedName("description")
String description;
}
I am using #JsonIgnore property to ignore some attributes in pojo, but these fields are not ignore in json response after parsing json using Gson library please help.
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#JsonIgnoreProperties(ignoreUnknown=true)
public class RideInvite extends RideInviteOld implements Serializable
{
private static final long serialVersionUID = -3729010679180341959L;
private double newFare = -1;
#JsonIgnore
private long prefPickupDropId;
#JsonIgnore
private String pickupLandmark;
#JsonIgnore
private String dropLandmark;
}
using following code to parse
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
jsonText = gson.toJson(msgObject);
Response after parsing
{"newFare":-1.0,"prefPickupDropId":2,"savePickupDropPoints":false,"pickupDropBasedOnTraffic":true,"allowFareChange":true}
here prefPickupDropId and savePickupDropPoints are json ignored but still value attribute is present in json text
I can not use #Expose for fields because my project is build in such away that ignoring fields which are not required json ignore and same pojos are using for preparing http response. This was working fine earlier but recently I am facing this issue
thanks in advance
Approach1:
Instead of using com.fasterxml.jackson.annotation.JsonIgnore you should use
com.google.gson.annotations.Expose to achieve your requirement.
Here is working code snippet -
import java.io.Serializable;
import com.google.gson.annotations.Expose;
public class RideRecord implements Serializable {
#Expose
private double newFare = -1;
private long prefPickupDropId;
private String pickupLandmark;
private String dropLandmark;
public RideRecord(double newFare, long prefPickupDropId, String pickupLandmark, String dropLandmark) {
super();
this.newFare = newFare;
this.prefPickupDropId = prefPickupDropId;
this.pickupLandmark = pickupLandmark;
this.dropLandmark = dropLandmark;
}
}
use the following code to parse:
RideRecord msgObject = new RideRecord(-1.0, 2, "sfo", "powell bart station");
GsonBuilder builder = new GsonBuilder();
builder.excludeFieldsWithoutExposeAnnotation();
Gson gson = builder.create();
String jsonText = gson.toJson(msgObject);
System.out.println(jsonText);
It will give output:
{"newFare":-1.0}
because only newFare is the field which is exposed.
you can play with the #Expose attribute to meet your requirements.
Approach2:
If you don't want to use #Expose then also you can achieve your
requirement by just creating Gson object as below -
RideRecord msgObject = new RideRecord(-1.0, 2, "sfo", "powell bart station");
GsonBuilder builder = new GsonBuilder();
builder.addSerializationExclusionStrategy(new ExclusionStrategy() {
#Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
return fieldAttributes.getName().equals("prefPickupDropId") || fieldAttributes.getName().equals("pickupLandmark") || fieldAttributes.getName().equals("dropLandmark");
}
#Override
public boolean shouldSkipClass(Class<?> arg0) {
// TODO Auto-generated method stub
return false;
}
});
Gson gson = builder.create();
String jsonText = gson.toJson(msgObject);
System.out.println(jsonText);
In this case also you will get the same output :
{"newFare":-1.0}
You're using Jackson with GSON and those are too separate frameworks.
One of the approaches is to initialize Gson to exclude fields that do not have the expose annotation.
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Then mark every field you need to use with the #Expose annotation:
ex:
class MyClass {
#Expose public String name;
}
SoapObject data=(SoapObject) envelope.bodyIn;
String result = String.valueOf(((SoapObject) envelope.bodyIn).getProperty(0));
JSONObject _jobjec = new JSONObject(result);
UserId = _jobjec.get("UserId").toString();
UserParentId = _jobjec.get("UserParentId").toString();
UserName = _jobjec.get("UserName").toString();
UserPassword = _jobjec.get("UserPassword").toString();
UserMobile = _jobjec.get("UserMobile").toString();
UserEmail = _jobjec.get("UserEmail").toString();
UserMpin = _jobjec.get("UserMpin").toString();
This is my COde i am trying to JOSon Parse and get value but what happen { ,} remove in result when i make json Object and trying and get value then i get Excepion i am getting
String.valueOf(((SoapObject) envelope.bodyIn).getProperty(0) :
{"UserId":"2","UserParentId":"1","UserName":"Anilkumar","UserPassword":"12546",
"UserMobile":"8130513899","UserEmail":"anilaat87#gmail.com","UserMpin":"7890",
"UserBalance":"20.0000","UserResponseMessage":"Is Valid"}
but unable to parse it
Directly using JSONObject to parse POJO is tedious and error prone, recommended using one of the below libraries:
GSON
JACKSON
MOSHI
JSON.simple
First, define your POJO class, you can use some online service, e.g. this one or this,
Just paste your example json string, then you can get below pojo class (you don't need to write it on your own) in 2 seconds:
package com.example;
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Example {
#SerializedName("UserId")
#Expose
public String userId;
#SerializedName("UserParentId")
#Expose
public String userParentId;
#SerializedName("UserName")
#Expose
public String userName;
#SerializedName("UserPassword")
#Expose
public String userPassword;
#SerializedName("UserMobile")
#Expose
public String userMobile;
#SerializedName("UserEmail")
#Expose
public String userEmail;
#SerializedName("UserMpin")
#Expose
public String userMpin;
#SerializedName("UserBalance")
#Expose
public String userBalance;
#SerializedName("UserResponseMessage")
#Expose
public String userResponseMessage;
}
Then to get the java object, use below gson calls:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Example instance = gson.fromJson(jsonString, Example.class);
If you use Jackson or other libraries, the same process applies, and they differ only in the detailed function calls.
you have to write code like this
SoapObject data=(SoapObject) envelope.bodyIn;
String result = String.valueOf(((SoapObject)envelope.bodyIn).getProperty(0));
JSONObject _jobjec = new JSONObject(result);
UserId = _jobjec.getString("UserId");
UserParentId = _jobjec.getString("UserParentId");
UserName = _jobjec.getString("UserName");
UserPassword = _jobjec.getString("UserPassword");
UserMobile = _jobjec.getString("UserMobile");
UserEmail = _jobjec.getString("UserEmail");
UserMpin = _jobjec.getString("UserMpin");