Why does JAXBContext need to be told specifically about a class that is already in the package?

后端 未结 2 840
遥遥无期
遥遥无期 2020-12-17 06:36

This program:

import foo.bar.baz.ClassSpecificallyIncluded;  
import javax.xml.bind.JAXBContext;  
public class A {  
    public static void main(String[]          


        
相关标签:
2条回答
  • 2020-12-17 06:52

    Creating a JAXBContext on a Package Name

    Assume I have the following classes in a directory called forum20273355:

    • Address
    • Customer (extends Person)
    • Mammal
    • Person (extends Mammal & has property of type Address)

    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
    

    Specifying a 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
    

    Getting the Subclass Processed

    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
    

    UPDATE

    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.

    0 讨论(0)
  • 2020-12-17 07:00

    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.

    0 讨论(0)
提交回复
热议问题