首页 文章

为什么需要特别讲述JAXBContext关于包中已有的类?

提问于
浏览
3

这个程序:

import foo.bar.baz.ClassSpecificallyIncluded;  
import javax.xml.bind.JAXBContext;  
public class A {  
    public static void main(String[] args) throws Exception {  
        System.out.println(JAXBContext.newInstance(ClassSpecificallyIncluded.class).toString());  
        System.out.println(JAXBContext.newInstance("foo.bar.baz").toString());  
    }  
}

为第一个和第二个JAXBContext生成不同的输出:

jar:file:/ C:/dev/trunk/rt/tomcat/shared/lib/webservices-rt-2.0.1.jar!/com/sun/xml/bind/v2/runtime/JAXBContextImpl.class Build-Id :1.0此上下文已知的类:[B boolean byte char foo.bar.baz.Class1 foo.bar.baz.Class1 $ NestedClass foo.bar.baz.Class2 foo.bar.baz.ClassSpecificallyIncluded foo.bar.baz.AnotherClass com.sun.xml.bind.api.CompositeStructure double float int java.awt.Image java.io.File java.lang.Boolean java.lang.Byte java.lang.Character java.lang.Class java.lang.Double java .lang.Float java.lang.Integer java.lang.Long java.lang.Object java.lang.Short java.lang.String java.lang.Void java.math.BigDecimal java.math.BigInteger java.net.URI java .net.URL java.util.Calendar java.util.Date java.util.GregorianCalendar java.util.UUID javax.activation.DataHandler javax.xml.bind.JAXBElement javax.xml.datatype.Duration javax.xml.datatype.XMLGregorianCalendar javax.xml.namespace.QName javax.xml.transform.Source long short void jar:file:/ C:/ dev / trunk / rt / tomcat / shared / lib / webservices-r t-2.0.1.jar!/com/sun/xml/bind/v2/runtime/JAXBContextImpl.class Build-Id:1.0此上下文已知的类:[B boolean byte char foo.bar.baz.Class1 foo.bar .baz.Class1 $ NestedClass foo.bar.baz.Class2 <<< CLASS IS MISSING HERE >>> foo.bar.baz.AnotherClass com.sun.xml.bind.api.CompositeStructure double float int java.awt.Image java .io.File java.lang.Boolean java.lang.Byte java.lang.Character java.lang.Class java.lang.Double java.lang.Float java.lang.Integer java.lang.Long java.lang.Object java .lang.Short java.lang.String java.lang.Void java.math.BigDecimal java.math.BigInteger java.net.URI java.net.URL java.util.Calendar java.util.Date java.util.GregorianCalendar java .util.UUID javax.activation.DataHandler javax.xml.bind.JAXBElement javax.xml.datatype.Duration javax.xml.datatype.XMLGregorianCalendar javax.xml.namespace.QName javax.xml.transform.Source long short void

然而,ClassSpecificallyIncluded位于foo.bar.baz包中:

//  
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6   
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>   
// Any modifications to this file will be lost upon recompilation of the source schema.   
// Generated on: 2012.05.14 at 10:47:17 PM IST   
//  

package foo.bar.baz;  

import javax.xml.bind.annotation.XmlAccessType;  
import javax.xml.bind.annotation.XmlAccessorType;  
import javax.xml.bind.annotation.XmlElement;  
import javax.xml.bind.annotation.XmlRootElement;  


@XmlAccessorType(XmlAccessType.FIELD)  
@XmlType(name = "", propOrder = {  
    "applicationArea",  
    "dataArea"  
})  
@XmlRootElement(name = "ClassSpecificallyIncluded")  
public class ClassSpecificallyIncluded {...

两个JAXBContexts的类路径和类加载器都是相同的 .

那么为什么第二个JAXBContext不知道ClassSpecificallyIncluded?

2 回答

  • 3

    您的问题的答案在这里得到了有效的回答:

    Can you find all classes in a package using reflection?

    Answer: 否按设计,java不会查找包中的每个类 . Java Build 在"Just in time"的概念之上 . 对于这个目的而言,这意味着java在获得特定内容之前不会获得 .

    所以从这个角度来看,JAXB无法找到包中的类 .

    如果每次需要上下文时都必须准确地告知每个 class ,那将是不方便的 . 因此,作为一种便捷方法,JAXB为您提供了提供包名称的选项 .

    为了绕过java的限制,它试图从该包加载 ObjectFactoryjaxb.index 文件 . 它可以这样做,因为它们是特定的名称 . 如果找到一个,那么它将它们用作包的清单 . 如果两者都找不到它,则除了中止之外别无选择,因为它可以在包中找到't possibly know what' .

  • 1

    在包名称上创建JAXBContext

    假设我在名为 forum20273355 的目录中有以下类:

    • 地址

    • 客户(延伸人)

    • 哺乳动物

    • Person(扩展Mammal并具有Address类型的属性)

    如果我使用以下代码创建 JAXBContext

    JAXBContext jc = JAXBContext.newInstance("forum20273355");
    

    然后我会得到以下异常:

    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或ObjectFactory

    下面我们将创建一个 jaxb.index 文件和 ObjectFactory ,这将导致 Person 类被处理以查看会发生什么 .

    jaxb.index

    jaxb.index 是一个文本文件,其中包含一个回车分隔的短类名列表 .

    Person
    

    ObjectFactory

    import javax.xml.bind.annotation.XmlRegistry;
    
    @XmlRegistry
    public class ObjectFactory {
    
        public Person createPerson() {
            return new Person();
        }
    
    }
    

    Processed Classes

    显然 Person 已被处理,但超类 Mammal 和引用类 Address 也是如此 . 未处理的类是子类 Customer .

    forum20273355.Address
    forum20273355.Mammal
    forum20273355.Person
    

    获取已处理的子类

    显然我们可以将子类 Customer 添加到 jaxb.indexObjectFactory . 我们还可以利用 @XmlSeeAlso 注释来实现这一目标 .

    package forum20273355;
    
    import javax.xml.bind.annotation.XmlSeeAlso;
    
    @XmlSeeAlso({Customer.class})
    public class Person extends Mammal {
    

    现在 Customer 也被处理了 .

    forum20273355.Address
    forum20273355.Customer
    forum20273355.Mammal
    forum20273355.Person
    

    更新

    你在评论中写的一切都是真的 . 缺少的是 jaxb.index 文件或 ObjectFactory 类需要踢这个过程 . 从XML模式生成模型时,会生成 ObjectFactory ,其中包含引导模型的所有必要引用 . 当您从Java类开始时,我建议从Java类而不是包名称引导,但适用相同的规则 .

    但Sun Oracle文档说:JAXBContext.newInstance(“com.acme.foo:com.acme.bar”)JAXBContext实例是从冒号分隔的Java包名称列表初始化的 .

    没错,包名称指定了要查找元数据的位置 .

    每个java包都包含JAXB映射类,模式派生类和/或用户注释类 .

    真正 .

    此外,java包可能包含必须处理的JAXB包注释 . (参见JLS第3版,第7.4.1节 . 包注释) .

    没错,肯定会应用包注释 .

相关问题