This program:
import foo.bar.baz.ClassSpecificallyIncluded;
import javax.xml.bind.JAXBContext;
public class A {
public static void main(String[]
Assume I have the following classes in a directory called forum20273355
:
If I create a JAXBContext
using the following code:
JAXBContext jc = JAXBContext.newInstance("forum20273355");
Then I will get the following exception:
Exception in thread "main" javax.xml.bind.JAXBException: Provider com.sun.xml.bind.v2.ContextFactory could not be instantiated: javax.xml.bind.JAXBException: "forum20273355" doesnt contain ObjectFactory.class or jaxb.index
- with linked exception:
[javax.xml.bind.JAXBException: "forum20273355" doesnt contain ObjectFactory.class or jaxb.index]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:146)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:334)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:431)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:394)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:298)
at forum20273355.Demo.main(Demo.java:8)
Caused by: javax.xml.bind.JAXBException: "forum20273355" doesnt contain ObjectFactory.class or jaxb.index
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:197)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:172)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:132)
... 5 more
jaxb.index
or ObjectFactory
Below we will create a jaxb.index
file and ObjectFactory
that will cause the Person
class to be processed to see what happens.
jaxb.index
jaxb.index
is a text file that contains a carriage return separated list of short class names.
Person
ObjectFactory
import javax.xml.bind.annotation.XmlRegistry;
@XmlRegistry
public class ObjectFactory {
public Person createPerson() {
return new Person();
}
}
Processed Classes
Obviously Person
was processed, but so was the super class Mammal
and the reference class Address
. The class that wasn't processed was the subclass Customer
.
forum20273355.Address
forum20273355.Mammal
forum20273355.Person
Obviously we could have added the subclass Customer
to the jaxb.index
or ObjectFactory
. We can also leverage the @XmlSeeAlso
annotation to make this happen.
package forum20273355;
import javax.xml.bind.annotation.XmlSeeAlso;
@XmlSeeAlso({Customer.class})
public class Person extends Mammal {
Now Customer
is processed as well.
forum20273355.Address
forum20273355.Customer
forum20273355.Mammal
forum20273355.Person
Everything you wrote in your comment is true. What is missing is that the jaxb.index
file or ObjectFactory
class is required to kick of the process. When a model is generated from an XML schema an ObjectFactory
is generated containing all the necessary references to bootstrap the model. When you start from Java classes I recommend bootstrapping from Java classes instead of the package name, but the same rules apply.
But the Sun Oracle documentation says: JAXBContext.newInstance( "com.acme.foo:com.acme.bar" ) The JAXBContext instance is initialized from a list of colon separated Java package names.
True, the package names specify where metadata will be looked for.
Each java package contains JAXB mapped classes, schema-derived classes and/or user annotated classes.
True.
Additionally, the java package may contain JAXB package annotations that must be processed. (see JLS 3rd Edition, Section 7.4.1. Package Annotations).
True, the package annotations will definitely be applied.
The answer to your question is effectively answered here:
Can you find all classes in a package using reflection?
Answer: No By design, java doesn't know and can't find every class in a package. Java is built on the concept of "Just in time". Which for this purpose means that java doesn't know what it's got until it's asked for something specifically.
So from that stand point, JAXB has no way to find what classes are in a package.
It would be inconvenient if JAXB had to be told precisely every class every time you needed context. So as a convenience method JAXB offers you the option of providing a package name.
In order to get round the limitations of java it attempts to load from that package an ObjectFactory
and a jaxb.index
file. It can do this because they are specific names. If one is found, then it uses them as a manifest for the package. If neither is found it has no option but to abort because it can't possibly know what's in the package.