Gson Long lost data when parse from String - java

I have json string represenatation of some object
class objects is
public class SMPBBaseObjectsList {
public ArrayList<Object> data = new ArrayList<>();
public Integer count;
public Integer limitFrom;
public Integer limitTo;
public Boolean hasMore;
public String dataItemsClass;
}
And i have json
{"classItem":"smpb.utility.classes.SMPBBaseObjectsList","dataItemsClass":"smpb.base.classes.SMPBUser","dataSliceCode":"012013","data":[{"id":1374046117510970000,"Name":"Test3","classItem":"smpb.base.classes.SMPBUser","dataSliceCode":"012013"}],"filter":{"orderItems":[],"filterItems":[]}}
I try parse this json and create object of my class with next code:
String json = "{\"classItem\":\"smpb.utility.classes.SMPBBaseObjectsList\",\"dataItemsClass\":\"smpb.base.classes.SMPBUser\",\"dataSliceCode\":\"012013\",\"data\":[{\"id\":1374046117510970000,\"Name\":\"Test3\",\"classItem\":\"smpb.base.classes.SMPBUser\",\"dataSliceCode\":\"012013\"}],\"filter\":{\"orderItems\":[],\"filterItems\":[]}}";
SMPBBaseObjectsList list = new GsonBuilder().create().fromJson(json, SMPBBaseObjectsList.class);
System.out.println("BEFORE:" + json);
System.out.println("AFTER: " + list);
System outputs:
BEFORE:{"classItem":"smpb.utility.classes.SMPBBaseObjectsList","dataItemsClass":"smpb.base.classes.SMPBUser","dataSliceCode":"012013","data":[{"id":1374044905885298000,"Name":"Test3","classItem":"smpb.base.classes.SMPBUser","dataSliceCode":"012013"}],"filter":{"orderItems":[],"filterItems":[]}}
AFTER: {"classItem":"smpb.utility.classes.SMPBBaseObjectsList","dataItemsClass":"smpb.base.classes.SMPBUser","dataSliceCode":"012013","data":[{"Name":"Test3","id":1.374044905885298011E18,"classItem":"smpb.base.classes.SMPBUser","dataSliceCode":"012013"}],"filter":{"orderItems":[],"filterItems":[]}}
As u can see in Json String i have ID with value 1374044905885298000 , but when object serialized from string i got 1.374044905885298011E18
And problem is what this representation of Long lost last zeros 0000 and i got Long 1374044905885297920
Why? and how fix it?
Data in Array is String map, and it's already all Long id Double format.
I try registerAdapater for Long or Double but never triggered.
Version of Gson 2.2.4
UPDATE
It's not duplicate of question
How to prevent Gson from converting a long number (a json string ) to scientific notation format?

I can't tell exactly what the problem is, but you can solve it by creating another class, i.e. Data to use in the List instead of the Object class... I tried this code and it's working fine for me!
So, you need to replace the ArrayList<Object> in your SMPBBaseObjectsList by:
public ArrayList<Data> data = new ArrayList<>()
And create a new class like this:
public class Data {
public Long id;
public String Name;
public String classItem;
public String dataSliceCode;
}
I guess there's an issue when parsing the JSON to an Object object, it probably makes some conversion that leads to that number formatting, but unfortunately I'm not an expert in this Java low-level issues...
Anyway, with this code you are explicitly specifying that you want that value parsed into a Long, so there's no problem!

Related

Convert annotation string to enum value with Jackson

I have an enum with #JsonProperty annotated:
public enum Type {
#JsonProperty("Files")
File,
#JsonProperty("Folders")
Folder,
}
I know I can deserialize a JSON string ({"fieldName":"Files"}) to get an object. But is there any way to convert the string annotated in #JsonProperty to enum value with Jackson like:
String s = "Files"
Type t = jackson.valueOf(s); // Type.File
Or can I achieve this:
Type t = Type.File;
String s = jackson.toString(t); // "Files"
I believe that a private String value can resolve this, but the code would have duplicated constants (too many "Files" and "Folders"). I wonder if Jackson or Gson has solution to achieve this.
It should just work with help of ObjectMapper
Type t = new ObjectMapper().readValue("\"Files\"", Type.class);
System.out.println(Type.File.equals(t)); //"true"
Please note that the String needs to be a valid JSON string, so it must contain the double quotes. The string content cannot be Files, but rather has to be "Files"
The other direction:
Type t = Type.File;
new ObjectMapper().writeValue(System.out, t); // "Files"
If I am understanding you correctly, then perhaps this is what you are looking for:
String annotationValueAsSTring = Type.class.getField(Type.File.name())
.getAnnotation(JsonProperty.class).value();
-- Edited --
To retrieve the Enum value from the #JsonProperty String value, then you will need to create a helper method:
public static <T extends Enum<T>> Optional<T> getEnumValueFromJsonProperty(Class<T> enumClass,
String jsonPropertyValue) {
Field[] fields = enumClass.getFields();
return Arrays.stream(fields).filter(field -> field.getAnnotation(JsonProperty.class).value().equals(jsonPropertyValue)).map(field -> Enum.valueOf(enumClass, field.getName())).findFirst();
}

how to split a javascript returned String object in java

I have a string array of objects which I pulled from javascript into java as a single string . It looks like this .
[
{"sourcevalue":"KRISHNA#IN.IBM.COM","userIdValue":"Krishna L Pappu -
krishnalakshmi","objectId":"A1001001A20E08A74322C03420"},
{"sourcevalue":"KRISHNA#IN.IBM.COM","userIdValue":"Krishna L Pappu -
krishnalakshmi","objectId":"A1001001A20E08A74322C03420"},
{"sourcevalue":"KRISHNA#IN.IBM.COM","userIdValue":"Krishna L Pappu -
krishnalakshmi","objectId":"A1001001A20E08A74322C03420"}
]
Now I want to know how it can be split into objects like below in simple java:
{"sourcevalue":"KRISHNA#IN.IBM.COM","userIdValue":"Krishna L Pappu - krishnalakshmi","objectId":"A1001001A20E08A74322C03420"}
{"sourcevalue":"KRISHNA#IN.IBM.COM","userIdValue":"Krishna L Pappu - krishnalakshmi","objectId":"A1001001A20E08A74322C03420"}
{"sourcevalue":"KRISHNA#IN.IBM.COM","userIdValue":"Krishna L Pappu - krishnalakshmi","objectId":"A1001001A20E08A74322C03420"}
I tried with split method its just too clumsy. Thanks in advance
As #Rabbit has said, create a deserializer. There are many ways to do this, A sample could be:
class SimpleObj {
private String sourceValue;
private String userIdValue;
private String objectId;
... getters, and setters ommited
public static List<SimpleObj> deserializer(String data){
Type objType = new TypeToken<ArrayList<SimpleObj>>() {}.getType();
return new ArrayList<>(new Gson().fromJson(data, objType));
}
}
The method deserializer which takes in a string needs Gson() library to work, so import that to your classpath, the method would help you change the incoming string to a list of object, like the one you desire.
I hope this is helpful.
I used this piece of code to achieve my requirement of deserializing the json object list which I got from Javascript. Hope this helps for requirements of deserializing a list of objects which are retrieved from front end.
#SuppressWarnings("unchecked")
public static AttributeValue[] jsonToObject (String jsonObj, Class gilClass) {
Gson gson = new Gson();
return gson.fromJson(jsonObj, AttributeValue[].class);
}

Easy way to get to values from JSONArray

I recently started working with JSON in Java. We have been setting and getting our values as follows from this JSONArray:
[{"productId":"1"},{"productName":"hammer"}]
JSONObject jo = ja.getJSONObject(0);
We could easily get the values by calling jo.getString("productId"); which would return the 1.
The problem is that sometimes we get different types of JSON objects. They look like this:
[{"name":"productId", "value":"1"},{"name":"productName", "value":"hammer"}]
Is there a way to easily eliminate those predicate name/value and just group the actual name and value together (as in the first example)?
The short answer is no.
The longer answer is that you're not working with JSON, you're working with someone's misunderstanding of JSON.
Both of your examples look a bit like JSON, but they're both bogus.
[] is an array.
{} is an object.
Your first string [{"productId":"1"},{"productName":"hammer"}]
is an array of two objects, where each object has one property.
It's confusing to put dissimilar objects into an array together, but that's going on in both of your examples.
The second example [{"name":"productId", "value":"1"},{"name":"productName", "value":"hammer"}] shows an array of two objects, but again, the objects are dissimilar.
I think what they're going for is more like [{"productId":"1","productName":"hammer"}], so I guess the long answer to your question is that you need to go to whomever is providing this "JSON" and tell them to fix it.
To give you a clearer idea of the correspondence between objects (in Java and otherwise) and JSON, check out the Java program below:
public class Product {
String productName;
String productId;
public Product(String productId,String productName){
this.productName = productName;
this.productId = productId;
}
public String toString(){return toJSONString();}
public String toJSONString(){
return "{\"productId\":\""+productId+",\"productName:\""+productName+"\"}";
}
public static String arrayToJSONString(Product[] arry){
StringBuilder sb = new StringBuilder();
sb.append("["+arry[0]);
for (int n =1;n<arry.length;n++){
sb.append(","+arry[n]);
}
sb.append("]");
return sb.toString();
}
public static void main(String [] args){
Product p1 = new Product("1","hammer");
Product[] arry = {p1};
Product[] arry2 ={p1,new Product("2","shovel"), new Product("3","manure")};
System.out.println("One object");
System.out.println(" "+p1);
System.out.println("An array containing one object");
System.out.println(" "+Product.arrayToJSONString(arry));
System.out.println("An array containing three objects");
System.out.println(" "+Product.arrayToJSONString(arry2));
}
}
Here's the output showing the proper JSON representation:
One object
{"productId":"1,"productName:"hammer"}
An array containing one object
[{"productId":"1,"productName:"hammer"}]
An array containing three objects
[{"productId":"1,"productName:"hammer"},{"productId":"2,"productName:"shovel"},{"productId":"3,"productName:"manure"}]
(Newlines are an artifact of the HTML, not JSON)

GSON get string from complex json

I am trying to parse the JSON from this link: https://api.guildwars2.com/v2/items/56 , everything fine until i met the line: "infix_upgrade":{"attributes":[{"attribute":"Power","modifier":4},{"attribute":"Precision","modifier":3}]} ...
If i dont get this wrong: infix_upgradehas 1 element attributes inside him. attributes has 2 elements with 2 other inside them. Is this a 2 dimension array?
I have tried (code too long to post):
JsonObject _detailsObject = _rootObject.get("details").getAsJsonObject();
JsonObject infix_upgradeObject = _detailsObject.get("infix_upgrade").getAsJsonObject();
JsonElement _infix_upgrade_attributesElement = infix_upgradeObject.get("attributes");
JsonArray _infix_upgrade_attributesJsonArray = _infix_upgrade_attributesElement.getAsJsonArray();
The problem is that I dont know what to do next, also tried to continue transforming JsonArray into string array like this:
Type _listType = new TypeToken<List<String>>() {}.getType();
List<String> _details_infusion_slotsStringArray = new Gson().fromJson(_infix_upgrade_attributesJsonArray, _listType);
but im getting java.lang.IllegalStateException: Expected STRING but was BEGIN_OBJECT which i guess comes from the attributes...
With a proper formatting (JSONLint, for example, checks if the JSON data is valid and does the formatting, which makes the structure more clear than what the GW link gives), attributes looks actually like this:
"attributes": [
{
"attribute": "Power",
"modifier": 4
},
{
"attribute": "Precision",
"modifier": 3
}
]
So it's an array of JsonObject and each object as two key-value pairs. This is why the parser throws an error because you require that this array contains only String which is not the case.
So the actual type is:
Type _listType = new TypeToken<List<JsonObject>>(){}.getType();
The problem is that I dont know what to do next
Hold on. You are using Gson and Java is an OO language so I suggest you to create classes.
This would be easier for you to fetch the datas afterward and for the parsing since you just need to provide the class of the actual class the JSON data represents to the parser (some edge-cases could be handled by writing a custom serializer/deserializer).
The data is also better typed than this bunch of JsonObject/JsonArray/etc.
This will give you a good starting point:
class Equipment {
private String name;
private String description;
...
#SerializedName("game_types")
private List<String> gameTypes;
...
private Details details;
...
}
class Details {
...
#SerializedName("infix_upgrade")
private InfixUpgrade infixUpgrade;
...
}
class InfixUpgrade {
private List<Attribute> attributes;
...
}
class Attribute {
private String attribute;
private int modifier;
...
}
and then just give the type to the parser:
Equipment equipment = new Gson().fromJson(jsonString, Equipment.class);
Hope it helps! :)

The exact syntax to get nested attribute from Json response with gson

I receive from server a response in this form
{"error":null,"id":1,"result":{"admin":false,"firstname":"Jason","id":346,"idHotel":109,"idVendor":null,"lastname":"Butcher","sessionkey":"3c8a17ae47a6d131b1a14b44a1d8f9a9","urlAvatar":"avatar_316_mjm.jpg","urlThumb":"thumb_316_mjm.jpg"}}
And want to get the various singles attributes, in the nested json result as primitive
for example
Boolean error=..;
String admin=....;
String idHotel=...;
I have tried to make a class in this way
public class HotelLogin {
public boolean error;
public int id;
public Result result;
//get and set
public static class Result {
public String lastname;
...
...//get and set
}
}
and I have used this code tying to deserialize the JSONObject serverResponse
HotelLogin loggedRs= new HotelLogin();
Gson gson = new Gson();
response = gson.fromJson(serverResponse, HotelLogin.class);
But at this point I don't know how to get the single attributes of the inner json.
And if I use the code
Result user=login.getResult();
String lastname=user.getLastname();
Get a null pointer exception
Well, assuming that you have a variable or a return data which contains your server response, you can try this:
var newError = data.Error;
var newId = data.Id;
var newFirstName = data.result.firstname;
OR
var serverResponse = data; //(considering that this 'data' is your json object);
//you access it through dot notation.
serverResponse.error;
serverResponse.result.admin;
serverResponse.result.id;
Each one will get your required data. You can loop through your json object, if your prefer, but i like to use dot notation. Note that you can't always use it, since you must know if a attribute has a child node.

Categories

Resources