Deserialize inmutable entity without modifying it - java

Is there any way to define a deserialization mechanism to instantiate a class with all final fields?
Is it possible to use a Builder to achieve this? I would like to avoid modifying this entity (Adding annotations, etc.)

If you're using JSON take a look at Jackson's #JsonCreator. It lets you specify how to construct the object see the jackson docs
If you don't want to annotate your class you can use a mixin to pick up the annotations from a different class. Something a bit like.
objectMapper.addMixIn(MyClass.class, MyAnnotations.class)

Related

How can I introspect a Java class's Jackson PropertyNamingStrategy when it is explicitly set by #JsonNaming?

I have some code which reads rows from a database and using Jackson ObjectMapper to convert them to objects. I am trying to make this as generic as possible, to serve as a library function.
For some particular object classes, the PropertyNamingStrategy is set explicitly via the #JsonNaming annotation to something other than how my row schema is defined (just the name casing is different, conceptually the names and data are the same).
I can use an intermediate library to convert the expected property names after I get them from the row schema to how the #JsonNaming annotation defines them. But that is very specific to one class.
Is there a way I can introspect a class type to find out what its PropertyNamingStrategy is? Or use ObjectMappper (or another Jackson utility) to find out, prior to doing the actual deserialization? That way my caller would not need to know or care about this when using my code.
Is there a way I can introspect a class type to find out what its
PropertyNamingStrategy is?
Yes, you can use the the SerializationConfig#introspectClassAnnotations method that returns a BeanDescription, gets its info and create an AnnotatedClass that will be inspected by the JacksonAnnotationIntrospector instance like below:
#JsonNaming(PropertyNamingStrategy.KebabCaseStrategy.class)
public class MyClass {}
AnnotatedClass acl = mapper.getSerializationConfig()
.introspectClassAnnotations(MyClass.class)
.getClassInfo();
JacksonAnnotationIntrospector jai = new JacksonAnnotationIntrospector();
//in this case it will prints class
//com.fasterxml.jackson.databind.PropertyNamingStrategy$KebabCaseStrategy
//In case of no annotation over the class the value will be null
System.out.println(jai.findNamingStrategy(acl));

Use Jackson Filter for an ObjectMapper to screen out null fields?

Is there some way to use a Jackson filter to screen out null fields? I know there are annotations, but I don't always want to screen out null fields. I only want to do it in some cases. Is there a way to define a filter to avoid serializing null fields that I can register with an ObjectMapper? Or is there some other way I can do this?
You can annotate the class you want ignore nulls in with #JsonInclude(Include.NON_NULL) or you can configure your ObjectMapper to do it for every class with mapper.setSerializationInclusion(Include.NON_NULL);
While you could probably do it with a filter, you'd end up with tons of conditional logic to maintain. If you don't want to annotate your classes you can do the same thing with MixIns.
You can also implement a per-class custom serializer to handle your specific use case if neither of the above works for you. Simply implement JsonSerializer or StdSerializer for the classes in question and annotate your target class with #JsonSerialize(using = MyClassSerializer.class)

Customizing Field Name Serialization in Jackson Object Mapper

Say I have a bean:
public class MyBean {
public String oneMississipi;
public int myBestFriend;
//Getters&Setters&Bears,Oh my.
}
And I am using com.fasterxml.Jackson DataBinding to transform instances of this pojo into json output... How do I customize the serialization of field names and can this be scoped to a global/class/field level?
e.g. I wish to dasherize my field names:
{
"one-mississipi": "two mississippi",
"my-best-friend": 42
}
I have already spent hours in Google and even trawling through the jackson code in order to find out where the field serialization occurs, but can't seem to see anywhere that it may delegate for custom field processing.
Does anyone have any ideas as to where this functionality lies if any? Much appreciated
Implement PropertyNamingStrategy and inside the resolving methods use AnnotatedMethod, AnnotatedField or AnnotatedParameter to get the declaring class. Then you can look for any custom annotation on that class and apply any custom naming depending on it.
The biggest problem with this approach is that it's not possible to get the actual concrete class being serialized or deserialized, it will always return the declaring class. So it won't be possible to override naming behavior in subtypes for the inherited members unless you bring them into the subtype.
Another solution would be using different mappers for classes that have different naming strategies. You can make it more or less transparent by creating a top-level "router" mapper that will decide which mapper instance to use (special care must be taken for configuration methods and other non ser/deser related methods). Assuming that you will have a finite number of the strategies this solution should be workable too.
The drawback of this solution is that you won't be able to mix different naming strategies during a single serialization / deserialization run.

Serializing objects with flexjson

I am trying to use flexjson library. But in my object I have to use:
com.google.api.client.util.DateTime which do not have no parameters constructor. I always get NoSuchMethodException with message: Flexjson will instantiate any protected, private, or public no-arg constructor. I have sources and trying to do something with that, here is the code:
constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
Exception is being thrown in clazz.getDeclaredConstructor() due to lacking empty constructor. What is the best approach to find constructor with let's say those signature:
DateTime(long timestamp)?
Have anyone encounter this kind of problem with this library? Maybe you can suggest to use other one. I am using it to serialize objects generated by Google Cloud Endpoints. Maybe I can do that with different approach?
You don't have to change the source code of Flexjson to do this. The way to handle this is to create your own implementation of ObjectFactory and register that for the type you are binding into. From there you can instantiate it however, you desire. It's easiest to subclass BeanObjectFactory and override the method instantiate(). In there you can do whatever you want to create an instance of an object you wish. By subclassing BeanObjectFactory it will take care of binding the individual properties from the JSON into your object using the setter/getter of that object. If your object doesn't support property methods you might find it easier to implement ObjectFactory and manually setting the values on that object from the JSON. There is lots of documentation on the Flexjson website about building ObjectFactories.
Then you can register your ObjectFactory to that data type using:
new JSONDeserializer<SomeObject>()
.use( DateTime.class, new DateTimeObjectFactory() )
.deserialize(json);

Exclude datamember when using renderJSON with play framework

I need to render objects in JSON and send them to the client but I need to exclude fields like email and password for obvious reasons.
I know play uses GSON (by google?) and you can pass a serializer class when calling the renderJSON() method. However I'm rendering different types of classes at once using a container class:
public class JSONContainer {
public List<User> userList;
public List<Toy> toyList;
}
For each class it's possible to make a Serializer class implementing GSON's JsonSerializer<...> method. But if I render a JSONContainer object like this: renderJSON(container) how can I pass the serializer classes to the rendering method?
Or is there maybe an easier/better way to do this?
Take a look at this post, which gives you a couple of options.
It would appear that the best option is to the #Expose (com.google.gson.annotations.Expose) annotation to mark the fields that you want to be serialised by Gson. You then need to use the GsonBuilder to specifically only include the #Expose fields.
Alternatively, as you have mentioned in your post, you can simply build your serialisations yourself. If you look at this post, it shows how specific class types are registered against the GsonBuilder, so any object of that found as part of the serialisation will use your specific serialiser.

Categories