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

时间:2013-11-28 19:12:52

标签: jaxb

这个程序:

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
   布尔
   字节
   焦炭
   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
   双
   浮
   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
   长
   短
   无效

     

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
   布尔
   字节
   焦炭
   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
   双
   浮
   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
   长
   短
   无效

然而,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 个答案:

答案 0 :(得分:3)

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

Can you find all classes in a package using reflection?

<强>答案: 没有设计,java不知道,也找不到包中的每个类。 Java建立在“及时”的概念之上。对于这个目的而言,这意味着java在得到特定内容之前不知道它是什么。

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

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

为了克服java的限制,它尝试从该包加载ObjectFactoryjaxb.index文件。它可以这样做,因为它们是特定的名称。如果找到一个,那么它将它们用作包的清单。如果两者都找不到,它就没有选择,只能中止,因为它不可能知道包中的内容。

答案 1 :(得分:1)

在包名称上创建JAXBContext

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

  • 地址
  • 客户(延伸人)
  • 哺乳动物
  • Person(扩展Mammal&amp;具有地址类型的属性)

如果我使用以下代码创建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.indexObjectFactory

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

<强> jaxb.in​​dex

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

Person

<强>的ObjectFactory

import javax.xml.bind.annotation.XmlRegistry;

@XmlRegistry
public class ObjectFactory {

    public Person createPerson() {
        return new Person();
    }

}

已处理的课程

显然已处理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节。包   注解)。

是的,肯定会应用包注释。