Java objects to JSON: field names - java

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.

Related

#Transient variable is not serialized using jackson [duplicate]

We use JSON serialization with Jackson to expose internal state of the system for debugging properties.
By default jackson does not serialize transient fields - but I wish to serialize them as well.
How can I serialize these fields?
One way I know is to supply a getters for these fields - but I don't want to do that, as I have some getX methods that I don't want to be invoked ( for instance, there are some getters that change the objects state ).
I know I could create an annotation, but I really want to avoid it.
So my question is:
Is there a way to setup jackson to serialize all the objects fields? include transient ones.
My solution with Jackson 2.4.3:
private static final ObjectMapper mapper =
new ObjectMapper(){{
Hibernate4Module module = new Hibernate4Module();
module.disable(Hibernate4Module.Feature.USE_TRANSIENT_ANNOTATION);
registerModule(module);
}};
I don't think Jackson supports any type of configuration to enable it to serialize a transient field. There's an open issue to add that feature, but it's old and hasn't been addressed (as far as I can tell): http://jira.codehaus.org/browse/JACKSON-623
So my question is: Is there a way to setup jackson to serialize all
the objects fields? include transient ones.
So to answer your question, no.
Some other Java JSON tools, such as GSON do support a configuration option to serialize transient fields. If you can use another tool, you might look into that (for GSON, see: https://sites.google.com/site/gson/gson-user-guide).
To expand a little, you might try a different approach.
First, You shouldn't try to serialize a transient field. After all the definition of transient is "don't serialize this." Nevertheless I can think of a few specific situations where it might be necessary, or at least convenient (like when working with code you can't modify or such). Still, in 99% of cases, the answer is don't do that. Change the field so that it's not transient if you need to serialize it. If you have multiple contexts where you use the same field, and you want it serialized in one (JSON, for example), and not serialized in another (java.io, for example) then you should create a custom serializer for the case where you don't want it, rather than abuse the keyword.
Second, as to using a getter and having "some getters that change the objects state," you should try to avoid that too. That can lead to various unintended consequences. And, technically, that's not a getter, that's a setter. What I mean is, if it mutates state, you've got a mutator (setter) rather than accessor (getter), even if you name it following the "get" convention and return some stuff.
You can create a custom getter for that transient field and use #XmlElement attribute. It doesn´t matter the name of that getter.
For example:
public class Person {
#XmlTransient private String lastname;
#XmlElement(name="lastname")
public String getAnyNameOfMethod(){
return lastname;
}
}
Another way to let Jackson serialize property is to add #JsonProperty annotation above it.
I guess it's better approach cause you do not need to disable default behaviour for all #Transient fields, like in Gere's answer.

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.

How to [de]serialize to pojo objects from JSON when there is mixed camel case in names

I'm using Dropwizard (which uses Jackson under the hood) to create a bridging API service. It connects to two other API's that are very similar (API1 and API2).
I have my own POJO library that contains the request and response POJO's for API1 and API2. The only difference between those two API's is that for certain objects API1 emits capitalised keys, whereas the other doesn't. Basically one API1 is implemented in Java and API2 is implemented in .NET but both serve the same data.
{
"Name" : "foo",
"Address" : "bar"
}
versus
{
"name" : "foo",
"address" : "bar"
}
I want to avoid writing a POJO class for each one when otherwise they are identical objects.
What is the correct way to tell Jackson to accept either name?
I'm aware of #JsonProperty e.g.
#JsonProperty("Name")
private String name;
However even if this works for both "name" and "Name", it feels a bit untidy. To me, declaring this annotation should effectively mean ignore the coded field name in favour of the annotation.
Thanks in advance
You may take a look at PropertyNamingStrategy which you can define for the ObjectMapper in use.
You could define different strategies for different service consumers (when you are the producer) if the other side is not flexible regarding the convention used (does not accept both upper- and lowercase forms).
If you can afford to use Jackson 2.5, then you could take a look at mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
For full control over Jackson (de)serialization process, take a loot at custom serialization and custom deserialization.

jackson deserialization into pojos

I'm trying to deserialize JSON Object coming from an application I can't control. Here my JSON :
{"assembly":
{"name":"mm9",
"id":32,
"chromosomes":[
{"chromosome":
{"name":"MT"}
}]}}
My Pojos, are
class Assembly{
private String name;
private int id;
private ArrayList<Chromosome> chromosomes;
// getters & setters
}
class Chromosome {
private String name;
//getter/setters
}
But it's not working because of the extra fields "assembly" & "chromosome", so with a JSON like :
{"name":"mm9",
"id":32,
"chromosomes":[
{"name":"MT"}
] }}
it simply working.
Is there a way to modify configuration or something to achieve this without create more complex POJOS?
The problem is that in the first JSON snippet, chromosomes is a dictionary (Map), of which one of the entries (chromosome) happens to correspond to your Chromosome object.
A more accurate direct mapping to a Java class would be
class Assembly{
...
private Map<String, Chromosome> chromosomes;
}
Since you mention you can't control the format of the source JSON, you may want to look into using custom deserializers, or perhaps using the streaming support from Jackson rather than ObjectMapper for direct mapping, if you aren't happy changing your POJOs in this way.
By the way, it is best to refer to collections by their interface type (List) rather than a concrete type (ArrayList). It is very unlikely that code that refers to this class truly cares or needs to know that it is using an ArrayList, referring to just the List interface instead makes it a lot easier to swap other implementations in if needed (as a general principle).

Convert JSON style properties names to Java CamelCase names with GSON

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;}

Categories

Resources