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

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.

Related

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.

Possible to use the #XmlSeeAlso dyncamiclly?

Instead of this
#XmlSeeAlso({User.class,Role.class,Function.class})
I would like something like this:
#XmlSeeAlso(Access.getWebServiceClasses())
Is it possible?
I want this since my webservice just contains interfaces and if I change the implementation I would just like to change in my factory so it returns the right classes instead of having to change in the webservice itself.
This isn't possible, since annotation elements must be simple types (strings, primitives or classes (see annotations).
It is possible however (in CXF) to override org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.getExtraClass() method which, by default checks #XmlSeeAlso of the interface. My implementation returns additional ObjectFactory classes.
Chances are that you're using <jaxws:endpoint /> in CXF's Spring XML configuration. To be able to override this method, you have create few classes:
org.apache.cxf.jaxws.spring.EndpointDefinitionParser must use class derived from org.apache.cxf.jaxws.spring.EndpointDefinitionParser.SpringEndpointImpl (when using JAXWS 2.1) or from org.apache.cxf.jaxws22.spring.JAXWS22SpringEndpointImpl (JAXWS 2.2)
This class must call super.setServiceFactory() passing org.apache.cxf.jaxws.support.JaxWsServerFactoryBean with overriden getExtraClass()
You have to provide your own org.apache.cxf.jaxws.spring.NamespaceHandler (you can create derived class) for your own namespace (e.g. http://cxf.apache.org/jaxws/dynamic) which will register your own parser for jaxws:endpoint element:
registerBeanDefinitionParser("endpoint", new EndpointDefinitionParser());
(sorry, I can't provide full example - I'm writing from memory and CXF's source code)

Best way to add annotations to inherited methods

I have a number of abstract superclasses from which my concrete class inherit various methods. Some of these methods need to have JPA or JAXB annotations placed on them in the concrete class. Currently I do this via the following:
#MyLocalAnnotations
#Override
public method inheritedMethodHere (yadda yadda)
{
super.inheritedMethodHere(yadda yadda);
}
Is there a way to do this without overriding the method? It seems like such a waste to override a method only to supply local annotations.
Unfortunately, there isn't a better way than what you are doing now. To do what you are describing you will have to override the method, considering that your JPA annotation will need information specific to the concrete class.
With JPA annotations, you actually have two options -- you can annotate the methods, or you can annotate the properties. On our project we've standardized on annotating properties rather than methods, but this won't help you either, as the properties are presumably part of the concrete class. (If they are somehow shared in the super-class, then you REALLY will need to annotate the methods, and override them).
Its hard to make a recommendation without seeing your schema, but if your entity classes have so much in common that they share many properties in the super-class -- might they simply be stored in the same table, perhaps with a differentiating type column?
Or alternatively if they are not nearly identical, might you just reproduce the common properties in each concrete class? You might be causing yourself more work rather than saving yourself by trying to capture the common properties in the super class. Since you will have to annotate them individually in the concrete classes, just declare them in the concrete classes. If you need common methods that interact with these properties, a separate Utility class to capture those functions could be the answer.
On our project we DO sometimes use a common super class for entities, but it captures some meta-data about the entity -- nothing that would impact persistence logic. Therefore, no JPA annotations are needed (nor would they make sense) in the abstract class.

Marshalling arraylist of abstract class in JAXB

I have a Java application that I want to save the data in XML instead of a database.
We decided to go with JAXB and instead of generating files based on the schema, we just added annotations to our Java files.
The issue we are running into is that we have an ArrayList of an abstract class called Node. A Node has subclasses of either Module or ScreenImage. When we marshall the arraylist, it doesn't save the type. Such as:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Module"
Does JAXB support elements that are abstract?
How do I get JAXB to save the type, so that I'm able to unmarshall it?
axtavt's suggestion is fine. I just want to add another approach. You could make use of #XmlSeeAlso, where you can declare other classes that should defined and visible to JAXBContext. You only have to make sure to declare the annotation within a class that is already visible to JAXBContext.
e.g.:
#XmlRootElement
#XmlSeeAlso({Node.class, Module.class, ScreenImage.class})
class SomeContent {
private List<Node> nodes;
///... accessors
}
It should work fine.
Note that if your Module and ScreenImage are not statically accessible from the bound classes (i.e. the classes specified in JAXBContext.newInstance(...)), they should be bound explicitly (add them to the JAXBContext.newInstance(...) parameters).

How do I prevent JAXB from binding superclass methods of the #XmlRootElement when marshalling?

I have a class that is annotated as the #XmlRootElement with #XmlAccessorType(XmlAccessType.NONE). The problem that I am having is that the superclass's methods are being bound, when I do not want them to be bound, and cannot update the class. I am hoping there is an annotation that I can put on the root element class to prevent this from happening.
Example:
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
public class Person extends NamedObject {
#XmlElement
public String getId() { ... }
}
I would expect that only the methods annotated #XmlElement on Person would be bound and marshalled, but the superclass's methods are all being bound, as well. The resulting XML then has too much information.
How do I prevent the superclass's methods from being bound without having to annotate the superclass, itself?
According to this StackOverflow post:
How can I ignore a superclass?
It is not possible with JAX-B to ignore the superclass without modifying the superclass.
Quoting the relevant portion of that post:
Update2: I found a thread on java.net
for a similar problem. That thread
resulted in an enhancement request,
which was marked as a duplicate of
another issue, which resulted in the
#XmlTransient annotation. The comments
on these bug reports lead me to
believe this is impossible in the
current spec.
Just add
#XmlAccessorType(XmlAccessType.NONE)
in front of EACH superclass declaration (and the class itself).
In your case:
#XmlAccessorType(XmlAccessType.NONE)
class NamedObject{
[ ... ]
}
Remember that this has to be done really for each superclass, it is often
forgotten when dealing with huge class dependency trees.
Interfaces, of course, don't need any JAXB annotations.
I know this question is quite old, but there is a kind of solution which works if your superclass is in the same package as its child.
Create a package-info.java in your package and insert
#XmlAccessorType(XmlAccessType.NONE)
package my.package.with.classes;
Obviously, it sets XmlAccessType.NONE upon all classes in the package. Myself, I use it in every package in our domain model. Therefore, I'm pretty safe. However, if your class is 'out of reach', f.e. it's in the JDK, use the solution from the accepted answer in [JAX-B] How can I ignore a superclass?.
I hope it's helpful for anynone who stumbles upon this question as I did.
I'm facing the exact same problem.
My superclass does not handle any JAXB annotations (it doesn't have to) and I would like my subclass not to include superclass properties while marshalling.
Adding the XmlAccesorType on superclass cannot be the solution as I have no way to modify the superclass.
Is there any other solution?
Replace your JAX-B implementation with MOXy and you can do anything you want. It has a ton of extensions that go above and beyond normal JAX-B, one of which will allow you to ignore inherited properties, etc. It also supports moving JAX-B annotations to an XML mapping file so you can keep multiple sets of mappings.
A solution I have found, but which might not work for you depending on what you want to do, is to override the getters you want to ignore and let them return null. The JAXB specs, and by extension the implementations, ignore fields that contain a null value. Note that if you still need to be able to access the superclass value itself using the subclass, you may need to add a secondary accessor method that is not a getter and adjust your code accordingly.

Categories