Mapping JSON to Java objects with different keywords - java

My company has a webserver API that provides search results in JSON format. I'm responsible for developing an Android app that consumes that API, and I have made some classes that model the objects in the JSON responses.
For the sake of habit and my own preference, I use to write my code in English only. However, most of the JSON keys are not in English. This way, I cannot readily use GSON to convert the JSON strings into Java Objects -- at least that is what I think.
I was wondering if there is any way to reference just once per class the connection between the JSON key and their corresponding instance variables in the code. In a way that after referenced, I could simply instantiate objects from JSON and create JSON strings from objects.
Is that possible?
Example:
// Java code
class Model {
String name;
Integer age;
}
// JSON with keys in Portuguese
{
"nome" : "Mark M.", # Key "nome" matches variable "name"
"idade" : 30 # Key "idade" matches variable "age"
}

Use the #SerializedName annotation.
Here is an example of how this annotation is meant to be used:
public class SomeClassWithFields {
#SerializedName("name") private final String someField;
private final String someOtherField;
public SomeClassWithFields(String a, String b) {
this.someField = a;
this.someOtherField = b;
}
}
The following shows the output that is generated when serializing an instance of the above example class:
SomeClassWithFields objectToSerialize = new SomeClassWithFields("a", "b");
Gson gson = new Gson();
String jsonRepresentation = gson.toJson(objectToSerialize);
System.out.println(jsonRepresentation);
===== OUTPUT =====
{"name":"a","someOtherField":"b"}
Source: SerializedName Javadocs

Related

How can I deserialize a list of enums using Jackson JSON?

I'm working on a configuration system. I'd like to be able to load config values from a JSON file and have them "automagically" convert to the Java type I need. I'm using Jackson for the JSON parsing. For primitive types like floats and strings, it's no big deal, but I'm running into a snag with enums.
Let's say I have the following enum:
public enum SystemMode
{
#JsonProperty("Mode1")
MODE1("Mode1"),
#JsonProperty("Mode2")
MODE2("Mode2"),
#JsonProperty("Mode3")
MODE3("Mode3");
private final String name;
private SystemMode(String name)
{
this.name = name;
}
#Override
#JsonValue
public String toString()
{
return this.name;
}
}
Now, let's say I want to represent a list of values of this enum for a given config variable using the following JSON representation:
{
"Project" : "TEST",
"System" : {
"ValidModes" : ["Mode1", "Mode2"]
}
}
And I'd like to be able to do something like the following:
ArrayList<SystemMode> validModes = (ArrayList<SystemMode>) configurator.getConfigValue("/System/ValidModes");
For reference, my configurator class's getConfigValue method is essentially a thin wrapper over the Jackson JSON parsing:
public Object getConfigValue(String JSON_String)
{
JsonNode node = JsonNodeFactory.instance.objectNode().at(JSON_String);
return objectMapper.convertValue(node, Object.class);
}
(The real method has some exception checking that has been omitted for clarity).
Now, when I call the above, Jackson correctly deduces that I want an ArrayList and fills it. However, instead of getting an ArrayList of SystemMode enums, I get an ArrayList of Strings and immediately throw an exception when I attempt to use the list. I have tried several different ways of representing the data to no avail. It seems no matter what I try, Jackson wants to return a list of strings instead of a list of enums.
So my question is this:
How can I make Jackson (version 2.9.4) JSON properly deserialize a list of enum values in a way that is compatible with my single "Object getConfigValue()" method?
The following will provide the correct binding for your enum.
public List<SystemMode> getConfigValue(String path)
{
JsonNode node = JsonNodeFactory.instance.objectNode().at(path);
return objectMapper.convertValue(node, new TypeReference<List<SystemMode>>(){});
}
The second option is to convert the list of String yourself, for example:
List<SystemMode> result = jsonResult.stream().map(SystemMode::valueOf).collect(Collectors.toList());
Third option:
public <T>List<T> getConfigValue(String path, Class<T> type)
{
JsonNode node = JsonNodeFactory.instance.objectNode().at(path);
CollectionType toType =
objectMapper.getTypeFactory().constructCollectionType(List.class, type);
return objectMapper.convertValue(node, toType);
}

Type choice for Play Framework JSON Form

I am developing a REST webservice using the Play Framework 2.5 (Java) and the form data binding (from Spring Framework).
I am quite experienced with this API and like the way it formalizes validation constraints (e.g. Required), so I would like to avoid using the BodyParser API.
I need to parse a JSON request such as this :
{
"elements": [
{
"val": "1"
},
{
"val": ["1","2","3"]
}
]
}
The problem is that "val" accepts two different types : a string (java.lang.String in Java) and an array of strings (java.util.List in my code).
How could I "typesafely" model such a JSON form in my Java code ?
I have already tried to use an abstract (and generic) class implemented by two different subclasses with different types for the "val" attribute, but Spring fails to instantiate the object (BeanInstantiationException).
Here is the current data model :
public class Foo {
#Constraints.Required
public List<Fii> elements;
}
public class Fii {
#Constraints.Required
// Which type ? Object ?
public ? val;
}
public class Response
{
List<ResponseEntry> response;
/*getters + setters */
public static class ResponseEntry
{
private List<Value> elements;
/*setters + getters*/
public static class Value
{
private List<Object> val;
}
}
}
Unfortunately, with the structure of the JSON you are handling, the only way to deserialize it is to have the value attribute be type Object. However, once the JSON is deserialized, you can easily figure out whether value is an object or a single value.
Notice that JSON only supports five data types: objects (Map in java), arrays, strings, numeric and boolean. It looks like in your case, value would most likely be either a number or a map of numbers; then you have two possibilities to check for. Using a quick instanceof comparison, you should be able to figure out what type of value it is.
ObjectMapper mapper = new ObjectMapper();
Response r = mapper.readValues(json, Response.class);
Value val = r.response.get(0).values.get(0);
if (val.value instanceof Map)
; // multiple
else
; // single

Gson error: Expected a string but was BEGIN_ARRAY

My json:
{"code":200,"data":[{"xxx":"xxx","yyy":1234,"zzz":"56789"},{...}]}
I need Gson to take the data part in the shape of [{...}] and put it to simple String. But Gson keeps trying to parse it as an array and throws this JsonSyntaxException. Is it possible to get the result as I want it?
Gson fromJson call:
ParsedResponse parsedResponse = gson.fromJson(jsonString, ParsedResponse.class);
ParsedResponse class:
public class ParsedResponse {
#SerializedName("code")
private int code;
#SerializedName("data")
private String data;
private int statusCode;
// getters, setters
}
EDIT:
The system works when I have {...} in data, so why couldn't it work with [{...}]? I just need Gson to take the string [{...}] and put it to String variable.
Basically, no. Just put into Array and then convert to what you need.
Other approach is to see if you can over-ride some parser implementation of GSON.
Or write your own JSON to reflection library. :-).
*** Or, just write your own JSON parsing as your data format might be well-known to you and simply enough. :-)

Gson serialization depending on field value

I have a POJO that is similar to:
public class MyGsonPojo {
#Expose
#SerializedName("value1")
private String valueOne;
#Expose
#SerializedName("value2")
private boolean valueTwo;
#Expose
#SerializedName("value3")
private int valueThree;
// Getters and other stuff here
}
The issue is that this object has to be serialized into a json body for a call
to the server. Some fields are optional for the request and if I even send it with default and null values, the API responds differently (Unfortunately changing the api is not an option).
So basically I need to exclude fields from serialization if any of them is set to a default value. For example if the field valueOne is null the resulting json should be:
{
"value2" : true,
"value3" : 2
}
Any idea how to make this a painless effort? I wouldn't want to build the json body manually.
Any help would be great. Thank you in advice.
Steps to follow:
Convert the JSON String into Map<String,Object> using Gson#fromJson()
Iterate the map and remove the entry from the map which are null
Form the JSON String back from the final map using Gson#toJson().
I have already posted the sample code in the same context here:
Remove empty collections from a JSON with Gson
Option 1) Use a TypeAdapter, see accepted answer here:
Option 2) If using Jackson instead of gson is a possibility, you can annotate/serialize on getters instead of on fields, and put your logic for returning
whatever you need for "default values" in your getters.
//won't get serialized because it's private
private String valueOne;
...
#JsonSerialize
String getValueOne(){
if (valueOne == null) return "true"
else...
}
You could also use a single #JsonInclude(Include.NON_NULL) or #JsonInclude(Include.NON_EMPTY) annotation at the top of your class to prevent any null or empty fields from being serialized.

How do I parse json string that contains list with gson?

How do I parse this particular json string with Gson in Java?
{"orders":[{"oid":"347","status":"1"},{"oid":"348","status":"1"}],"a":14.15,"b":0}
What is problematic is the orders list.
I suppose one has to use a "type token" parameter to Gson.parse(json,type-toke), but it is not clear to me how this can be done.
You have to create java types that it can be mapped to. So, you would have something like this.
public class Result {
private List<Order> orders;
private Number a;
private Number b;
// getter and setter for orders, a, and b
}
public class Order {
private Number oid;
private Number status;
// getter and setter for oid and status
}
Then you can just do the parsing with something like
Result result = gson.fromJson( yourSring, Result.class );
caveat, this is uncompiled, untested code, but should get you close.
Now, you can use json-path in java, see document. It's simple and clever.
http://code.google.com/p/json-path/

Categories