Serializing jackson generated classes - java

I use jackson (via resteasy) to convert json to a Java object. I've only defined an interface for the object and jackson generates the implementation automatically. Great!
Now I'm trying to save the object and restore it later. My interface extends Serializable, so my datastore saves it without complaint. When it comes time to load it later, though, the generated class definition is nowhere to be found. I get
java.lang.ClassNotFoundException: org.codehaus.jackson.generated.my.class.name
What are my options for saving and loading objects with class definitions generated by Jackson?

Maybe serialize POJO as java.util.Map instead? JDK serialization is tightly bound to concrete classes, so it may not work well with Jackson's abstract type materialization (I assume you are using "Mr Bean" module).

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

Java class parser

I am parsing all the class files in a jar via Objectweb asm (http://forge.ow2.org/projects/asm/). The idea is to parse and store (and use for something later) all the public/protected methods and fields in each class file. It is working as expected. What I dont get is the list of methods, declared by the interface and those inherited from superclasses and superinterfaces. Is there a smart parser available that would give me the above list?
I could load the class file and then use java.lang.Class object to get what I need. But loading classes might fail because of dependencies. I would rather parse and get that info.
The data you want is simply not there. Inherited members are implicit: you only have the names of the class and interfaces where they can be looked for, and you need to parse the corresponding class files.
You can simply do this :
Class superclass = aClass.getSuperclass();
aClass.getClass().getInterfaces();
aClass.getClass().getMethods();

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.

JAXB - trying to marshall a java object from external jar

I'm trying to marshall this class using jaxb
import com.vividsolutions.jts.geom.Point;
public class TaskPost {
...
Point point;
...
}
(with getters and setters)
Class point is imported from an external jar which i have no source code to, how can i manually marshal this?
I need to use specific methods to get the data from the point class (for now its printing one of the fields SRID>0/SRID> (which are html tags))
Any help would be appreciated.
A JAXB implementation does not require any annotations on a model class so it would apply the default mappings to it. Alternatively, you could write an XmlAdapter to convert Point to/from your own model class for the purpose of marshalling/unmarshalling.

How to handle various concrete implementations of an Interface with JAX-B

I have a class that any I need to marshal to XML.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class ClassToBeMarshalled {
public Interface object;
}
The Interface is implemented by a lot of concrete classes and most of them are vendor specific whose source code I don't have access to.
So my problem is:
If I try to marshal that class, JAX-B will complain that the current concrete implementation of Interface is not known in the context - In another words, the concrete class was not loaded into the context by calling JAXBContext.newInstance providing the current implementation.
The most common ways to sort out that problem are:
1) Use XMLSeeAlso - not a viable option as there are a lot of concrete classes
2) Annotate each class with #XmlRootElement - not a viable option as I don't have access to all the classes
Does anyone know a way to make JAX-B load the concrete class into its context as the need arises?
Thanks.
P.S.: I'm using JAX-B RI
You could mark your object as #XmlAnyElement(InterfaceHandler.class) where InterfaceHandler is a DomHandler capable of translating between a DOM representation and the actual implementing classes. That handler should probably store the class name when marshalling, and use that class name to create the instance when unmarshalling. It might either configure the instance manually, perhaps using some helper classes designed to work with beans, or it might use another jaxb context which includes that specifically named class and will handle that object with all its nested children.
Also have a look at the #XmlElementRef annotation. I fear that in order to make this work properly, you'd have to at least know all the implementing classes at compile time, but perhaps there is a way you can make this work for you as well, with less trouble than the generic solution outlined in the previous paragraph.

Categories