Convert JSON style properties names to Java CamelCase names with GSON - java

I'm using GSON to convert JSON data I get to a Java object. It works pretty well in all my tests.
The problem is that our real objects have some properties named like is_online. GSON only maps them if they are named totally equal, it would be nice to have GSON convert the names to Java camel case isOnline.
It seems this is possible while creating the JSON data, camel case is converted to underscore separated words in JSON. But I can't find a way to specify this the other way round.

I have found the following setting works perfect when reading json with underscored attributes and using camelcasing in my models.
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create()

You can use the SerializedName annotation:
#SerializedName("field_name_in_json")
private final String fieldNameInJava;
Note: When you have set a FieldNamingPolicy already, SerializedName will overwrite its settings for that specific field (quite handy for special cases).

Bear in mind your example is an edge case. If you have a property 'foo' its getter should be named 'getFoo', and if you have a property named 'foo_bar' its getter should be named 'getFooBar', however, in your example you're mapping a boolean and booleans have special case naming conventions in java. A primitive boolean property named online should have a getter named 'isOnline', NOT 'getOnline' or even worse, 'getIsOnline'. A boolean wrapper object (i.e. Boolean) should not follow this special case and a property named 'online' should have a getter named 'getOnline'.
Hence, having boolean properties with 'is' in the name is an edge case, where you'll want to strip out this particular prefix during your conversion. In the reverse direction, your code may want to inspect the json object for both a raw property name as well as a 'is_XXX' version.

I think what you want is here. Using annotations you can tell GSON that the mySuperCoolField is actually called this_field_is_fun in the JSON and it will unpack it correctly. At least I think it works for deserialization too.
If that doesn't work, you can use custom JsonSerializer/JsonDeserializers, which work great, but you have to update them for changes in your class (like when you add a field). You lose the auto-magic.
The easiest thing to do (which would be ugly, but very clean and simple if the first suggestion doesn't work) would be to simply name the field in a way to make GSON happy, and add extra accessor methods with the names you like, e.g.
public boolean isXXX() {return this.is_XXX;}

Related

Can we deal with JSON data directly instead of creating POJO classes while creating Rest Assured framework?

I have seen in many Rest Assured frameworks that we create POJO classes for Serialization & deserialization but let's say we have to automate more than 50-70 APIs thus, creating POJO classes for all seems tedious work so can we deal with JSON objects and data directly? We can get rid of getters and setters by using Lombok annotations but still, we will have to set variables. just curious about what should be the best practice we can follow?
Not sure if I understood correctly. So maybe this answer goes in the totally wrong direction.
If you have lots of Classes and member variables, to streamline handling, you could introduce a level of abstraction.
As an example:
instead of a class and its member variables, you could have a HashMap that stores [variable name] as key, and [variable value] as value.
for multiple object of the same class, instantiate multiple HashMaps
maybe hold all those produced HashMaps in a Collection like a List
maybe even have an 'outer' HashMap, that maps [class name] to [collection]
in the end it might look like this: HashMap[class name -> Collection], Collection contains multiple 'object' HashMaps. Object HashMaps map their [member variable name] to the [meber variable value]
Now, to the JSON part: Google's GSON already has classes in place that do exactly that (object abstraction), so you now have an easy bridge between JSON and Java.
And then you bring it all together and only write ONE serializer and ONE deserializer for ALL classes you wanna handle.
In the end, you still have to put value to POJO or any kinds of object (Map, List, JSON objects...) to create a json payload. I don't like the idea manipulating data directly, it's so rigid.
To make your work less tedious, some techniques can be applied:
Create inner classes if you don't want to create too many POJO classes separatly.
Use Builder pattern (Intellij suggestion or #Builder annotation in lombok) to create POJO instance more straightforward (comparing to basic Setter).
Create POJO instance with default value for each property, then only the property that matters.
Separate the creation of POJO object in other packages, like PersonFactory to build Person instance. It will help make test cleaner.

Java JSON deserialization without predefining everything

I realize this has probably been asked a hundred times but I have searched a lot and can't find specifically what I'm looking for.
Here is what I'd like. Given a string data, I'd like to deserialize into an object obj that doesn't have all the fields predefined. I'd like to just be able to ask for the fields I want such as obj.getString("stringFieldName") or obj.getInt("intFieldName"). I already have gson being used for other things so if it is possible with gson that would be great although not opposed to using another library.
The 'standard' Android JSON library (since API 1) already provides such untyped access.
See JSONObject, eg. getInt:
Returns the value mapped by name if it exists and is an int or can be coerced to an int, or throws otherwise.
Unless needing the JSON mapped onto a 'native' Java collection type this is probably the simplest way to achieve the request. It doesn't require any additional libraries.
With Jackson library you can annotate data model class with
#JsonIgnoreProperties(ignoreUnknown = true)
and the jacksonconverter will just parse only these fields that you defined. Other will be ignored.
Have you tried using Retrofit from Square? It works with GSON and Java Annotations and it's super easy to set up.

Java objects to JSON: field names

I have a pretty standard Java POJO. Let's call it Dog:
Dog.java has a series of fields. In Java, convention says field names should start with a lower case. This means I have:
public String name;
public String dogType;
public String weight;
At the same time, I have a requirement on my JSON format that the JSON members (name, dogType, and weight) all be written with a capital letter at the beginning i.e. Name, DogType, and Weight.
I am using Jackson.
If I use the standard serialization code as below, I get JSON member names written exactly the same way they are in Java.
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jReq);
System.out.println(json);
To address my problem, I have 2 options:
either I use the Jackson annotation #JsonProperty(value="DogType"), or
I use a naming strategy as described in the API.
My question is: is there a clean way of doing it?
There are quite a few questions on SO about this that explain both ways:
Change field case with an ObjectMapper
Model class for Jackson Parser to parse Uppercase properties
But none go into the pros and cons.
My initial hunch is that I should go for the naming strategy. Is that a good approach or a bad one?
I think you should go for the naming strategy, too. The advantage of this one is that you can always override it with the annotations, if needed.

Map JSON Response to POJO (with different names)

I know there are numerous posts out there for a similar problem, but mine seems to be a bit different. I am reading in a bunch of JSON and would like to build POJO from it, but I don't want to use the names of the JSON result. Is there a way to "map" the element names in JSON to the attributes in my POJOs (using gson or Jackson maybe)?
It's worth mentioning this application is being built for Android.
Thanks in advance!
If you're using Gson, you can append an attribute to your objects, like so:
#SerializedName("ServicesResult")
public String services;
Where "ServicesResult" is the actual name of the element in the JSON.
With Jackson, you have multiple options:
Use #JsonProperty("name") annotation to indicate name to use in JSON, add directly or use mix-in annotations (external)
Specify PropertyNamingStrategy to convert from "Java name" to "JSON name" (there is default java<->c-style converter bundled with 1.9)
Modify AnnotationIntrospector to change the name using some other mechanism than annotations
Jackson will also interpret the Basic package javax.xml.bind.annotation
If you use those annotations you can readily move between Json/XML

Dynamically create classes in Java

I would like to create a class in Java based on the fields defined in my XML config file:
For example: if the XML file contains (the syntax has been maligned for posting):
<property name="agent_host"></property>
<property name="subsystem"></property>
then internally it will create a class Event such as Event(String agentHost, String subSystem) that the client can instantiate. Note: the client always knows that this class will be called "Event" but does not know how many "mandatory parameters" it needs to pass.
On the other hand if I have a XML file with:
<property name="agent_host"></property>
then it will create Event(String eventHost) that the client can use for instantiation.
Yes, you could use reflection, but what comes to my mind is working with a class that you could add property.
Imagine a class that has one encapsulated HashMap using a String as a key (for the attribute name) and the value of the attribute so you could read the XML file and for evey property add the attribute to the class like.
For this line:
<property name="subsystem" type="String">value123</property>
GenericClass c = new GenericClass();
c.addAttribute("subsystem", new String("value123"));
//and you could implement a get and set methods like this:
public String getAttributeValue(String attributeName)
{
return internalHashMap.get(attributeName).toString();
}
Using this you could also implement a setAttributeValue
will be quite simple I think
If you really interested in creating a class dynamically, try Byte code Enhancement libraries like BCEL from Apache.
This isn't really a class you want, it's data. Why not use a hashmap? I really dislike "Bean" style classes--they encourage bad coding (there is no place in a generated class to put actual code, so everything ends up being manipulated by external code anyway).
You can just load a hashmap from your XML and inject it into a real object--that way you don't have to worry about actually passing a hash around, you are passing a real object with real business methods and real type safety--it just HAPPENS to use a hashmap internally to store data instead of member variables.
I've done a lot more than this, but at some point you realize Hibernate does everything you want for you.
I think the DynaBean from Commons-BeanUtils may be what you're looking for.
A DynaBean is a Java object that supports properties whose names and data types, as well as values, may be dynamically modified. To the maximum degree feasible, other components of the BeanUtils package will recognize such beans and treat them as standard JavaBeans for the purpose of retrieving and setting property values.

Categories

Resources