I have gotten confused by these two aspects of JAXB.
As far as I understand, when passing colon separated package names as context path to newInstance method of JAXBContext, JAXB will add all the classes under these packages to its scope to be used in operations like marshall/unmarshall/validate...etc.
The #XmlSeeAlso annotation instructs the JAXBContext to bind classes. All the examples I've seen use this annotation to specify only its child classes (I couldn't tell why actually).
Below are my questions:
1- Can the #XmlSeeAlso be omitted if the classes referred by the
annotation are within the packages passed to JAXBContext newInstance
method?
2- If the above is true, then why do we need this annotation in the first
place, where we can simply pass ALL the packages containing the classes we need to the newInstance
function?
3- If the above is not true, can we only use packages containing top
level classes passed to the newInstance, and use the annotation #XmlSeeAlso to reference all
children of these classes?
1- Can the #XmlSeeAlso be omitted if the classes referred by the
annotation are within the packages passed to JAXBContext newInstance
method?
yes, #XmlSeeAlso is used to instruct JAXBContext to look for classes that is not otherwise loaded by newInstance(). To let JAXBContext to know about the subclasses used, either you can specify with #XmlSeeAlso or pass all subclasses in the newInstance method.
2- If the above is true, then why do we need this annotation in the
first place, where we can simply pass ALL the packages containing the
classes we need to the newInstance function?
#XmlSeeAlso approach is used mostly when you are creating JAXB classes on your own. When you have XSD->JAXB approach, then JAXBContext.newInstance() with all packages separated by : is preferred.
Related
Are there such things as Java annotations that aren't tied to any class, method, field, etc.?
Like just writing
#MyAnnotation(someParameter=value, ...)
by itself, and it generates code.
It seems like ExecutableType might define what kinds of "elements" an annotation can annotate, but I'm not sure. If that's true, then ExecutableType derives from TypeMirror, one of whose members are NoType. So maybe it's possible? But I cannot find an example of this.
You cannot have a stand-alone annotation in Java.
Annotations can be applied to different things, for example: types, methods, fields, local variables, packages, method parameters and also on annotation definitions.
One annotation that is meant to be used on annotation definitions (therefore it's called a "meta-annotation") is #Target, which you use to indicate on what things the annotation you are defining is allowed to be used. You do this by specifying one or more element types as an argument to the #Target annotation - see the API docs of java.lang.annotation.ElementType.
The Java Language Specification paragraph 9.6.4.1 explains what annotations can be used on in more detail.
I was investigating object marshaling and unMarshaling using JAXB. while noticed that there is two option of getting an instance of JAXBContext.
one is based on class: JAXBContext context = JAXBContext.newInstance(ex.getClass());
Other one is based on package name: JAXBContext context = JAXBContext.newInstance(ex.getClass().getPackage().getName());
For the second way, you have to provide jaxb.index file, containing list of bean class names.
Maybe someone can explain, what is the difference between this two methods of getting JAXBContext instance? Which is better to use and when?
For the second way, you have to provide jaxb.index file, containing list of bean class names.
This is not correct. In JAXB2 this works without jaxb.index as well, the classes are "recognized" via ObjectFactory and #XmlSeeAlso.
The usual approach is to use JAXBContext context = JAXBContext.newInstance("my.package:my.another.package); as you normally want to consider all of the relevant classes and don't want to enumerate them explicitly.
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.
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.
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).