Jackson handle 3rd party java type - java

I am providing the ability to deserialize a list of entities returned from JPA, however the list type returned from JPA is DelegatingResultList which has no default constructor.
The implementation uses proxy beans with AOP where I intercept interfaces that extend a set of interfaces to provide basic queries.
I can easily fix this by checking in my aspect if the object type is DelegatingResultList and then copy to an ArrayList, but I don't want to have to do this for every single aspect that I'm covering.
I am using the default typing to set as a property like so:
objectMapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
The json in the serialized format with my value wrapper looks like this:
{"#class":"my.wrapper.ValueWrapper",
"response": ["org.apache.openjpa.kernel.DelegatingResultList",
[{"#class":"my.entity.TaxInfoEntity","taxType":"01","taxVal":"0.07"}, ..."]]"}
I have read about using mixins and custom deserializers, but everything I've tried doesn't seem to work.
I have tried using a Mixin, but I have no reference to the ResultList property as it's not saved in the json. Not to mention it doesn't even kick in when it's trying to deserialize.
I have tried using a custom deserializer but again, this never kicks in when deserializing. Would I be correct in assuming the mixin and custom deserializer only kick in if you try to deserialize passing the class as the type?
This of course would be read only as it's a cached value. So my intention is to convert to an Arraylist instead. How would I achieve this using Jackson?

Related

Warming up of the JSON serializer on a JAX-RS endpoint

I am using JAX-RS whereby I have an interface which contains annotated methods for my endpoints (Apache CXF). I am using Jackson as my serializer.
I have noticed that the first request is particularly slow. This is because the JSON serializer is building its internal metadata on how to serialize/deserialize a given type on the first request.
It is possible to get Jackson to do this upfront (before the first request) by registering the type with Jackson. Is it possible to do this in a generic way, such that I have an interface and using reflection it goes and finds all the inputs and outputs to the JAX-RS annotated methods and registers the types with Jackson?
I figured this must be an "already solved" problem and in the vein of DRY - is there something out there that will do this already without me having to write some nasty reflection code myself? (Or any helper methods in Spring etc that could help here?)

Passing Java Object to a RESTful service

I'm passing a Java object to a Web service that accepts json, using HttpURLConnection.
Employing com.fasterxml.jackson to convert the object to json string and then writing it to the output stream, the service works fine for simple dummy POJOs, but the application breaks when I use a complex object that I'm originally intend to send,
with the console filled with exceptions like StackOverflow and endless clutter of
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:690)
at
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
Common solutions are like annotating the class with json annotation.
Is there any other way to get around it, like using different accept:content-type for web service (other than json or xml as they require annotated objects) or like that?
You can use mixin annotations to provide hints for Jackson on how to serialize your data, without polluting the POJO with unnecessary dependencies.
Here's the reference to documentation article, that has good example:
http://wiki.fasterxml.com/JacksonMixInAnnotations

jackson - ignoring case in snake case keys

I have a requirement to receive JSON with keys that contain underscore and even ignore the case in words. For e.g. Device_control_API, device_control_API, Device_Control_API, device_control_aPI etc all should map to same property.
Now I know that I can create multiple setter methods using #JsonSetter with all combinations possible, but I don't think that will be good.
I have seen other questions which suggest using mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
for ObjectMapper object to ignore case, but I can't do that because I am using spring-boot and want my REST API to get payload in the form POJO object.
Is there any annotation or some way to do so
Please help !!!
I dont think you can use the MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES as annotation. Got the following information from here
Jackson on/off features: MapperFeature
Jackson defines a set of per-mapper configuration, which can ONLY be
defined before using ObjectMapper -- meaning that these settings can
not be changed on-the-fly, on per-request basis. They configure
fundamental POJO introspection details, and resulting built objects
(serializers, deserializers, related) are heavily cached. If you need
differing settings for these, you have to use separate ObjectMapper
instances.
And the MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES is one of the configuration.
But maybe a custom deserialization class could help you. There are many tutorials and questions on Stackoverflow.
I found some:
Jackson: using #JsonSerialize (or #JsonDeserialize) annotation to register a custom serializer (or deserializer)
Right way to write JSON deserializer in Spring or extend it
There is also this property:
spring.jackson.mapper.accept_case_insensitive_properties=true

How to extend Jackson property discovery in a "catch-all-types" way?

Following my previous question about serialization only, I'd like to go further and support JsonFormatVisitor.
I have the same requirements, that is:
I have objects of several types (interfaces).
I don't know the type of theses objets in advance.
I can't add annotations on theses types.
I can introspect all theses objets to get their state data.
Now that serialization works, I need to generate JsonSchema and hence do something like that:
SchemaFactoryWrapper visitor = WHAT?
mapper.acceptJsonFormatVisitor( mapper.constructType( Foo.class ), visitor );
JsonSchema jsonSchema = visitor.finalSchema();
String schemaString = mapper.writeValueAsString( jsonSchema );
I've implemented a SchemaFactoryWrapper that gets its expectAnyFormat called but I don't know what to do inside it. Looks like there's no schema for "any" objects.
Maybe I can hook elsewhere in jackson? Maybe it is possible to extends the whole Bean/Property introspection mechanism to support a completely different model (ie. not beans)?
I'm a bit lost, please help me find the treasure room :)
I can try to suggest some approaches that may be helpful.
First, even if you can not annotate classes directly, "mix-in annotations" can help -- this does assume static knowledge, however
Second, since schema-generation uses type detection used for serialization, you may want to register custom serializers; but this does not necessarily mean having to hand-write all. The most flexible way to register custom serializers is via Module interface (mapper.registerModule(new MyModule()); Modules can register Serializers instance which gets called when trying to locate a JsonSerializer for a type for the first time (after this, instance is cached to be re-used for other properties of same type).
This is where you could configure and return your custom JsonSerializer; but it might only need to handle schema-related callback(s) (one(s) called by schema generator).
It is also possible to extend/modify property discovery mechanism; whether this is easier depends. But the thing to look for is registering BeanSerializerModifier via Module.
It gets called during construction of BeanSerializer (general POJO serializer used unless something more specific is registered), and with it you can add/modify properties; or just replace resulting serializer altogether (and also then allows chaining of custom serializer with default one, if needed).

Changing names of properties while Serializing to JSON without source code

Need to serialize java objects to JSON while doing compression such as name change, exclusion etc. Objects use class from jar, source code of which is not available.
Looked through many libraries(Jackson , Gson), but found none solving this particular problem. Most of them are annotations based, which I can't use given I don't have source code.
One way to solve this problems is, use reflection and recursively go through object until you find a property name of which should be replaced or object is excluded in serialized JSON.
Need solution for this. Better if it is already implemented and tested.
You can also have a look at Genson library http://code.google.com/p/genson/.
You can rename and filter with quite concise code:
// renames all "fieldOfName" to "toName", excludes from serialization
// and deserialization fields named "fieldNamed" and declared in DefinedInClass
// and uses fields with all visibility (protected, private, etc)
Genson genson = new Genson.Builder().rename("fieldOfName", "toName")
.exclude("fieldNamed", DefinedInClass.class)
.setFieldFilter(VisibilityFilter.ALL)
.create();
genson.serialize(myObject);
If you want to do some more complex filtering (based on annotations for example) you can implement BeanMutatorAccessorResolver or extend BaseResolver.
Same for property renaming you can implement PropertyNameResolver and have full control.
And finally if you want to filter fields, methods or constructors according to their modifiers you can define your own VisiblityFilter.
Concerning performances of filtering/renaming there should be no problem as it is done only once per class and then cached.
To start using Genson you can have a look at the Getting Started Guide.
Found solution to the problem.
Google gson has class called GsonBuilder which has methods for exclusion strategy and naming strategy.
Using these two methods implemented a custom solution, where all the mapping and exclusion rules are stored using a xml and used at the time of serialization and de-serialization.
Works perfectly, though not sure about the performance of same.

Categories

Resources