JAXBContext.newInstance变体

Mar*_*tus 19 java xml xsd jaxb

我正在尝试JAXBContext类中的各种形式的newInstance方法(我使用的是Oracle JDK 1.7附带的默认Sun JAXB实现).

我不清楚只需将具体类与ObjectFactory类传递给newInstance方法即可.我应该注意到,我纯粹使用JAXB来解析XML文件,即仅在XML-> Java方向.

这是绝对最小的代码,它证明了我的观点:

xsd文件

<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified"
    xmlns          ="http://www.w3.org/2001/XMLSchema"
    xmlns:a        ="http://www.example.org/A"
    targetNamespace="http://www.example.org/A">
    <element name="root" type="a:RootType"></element>

    <complexType name="RootType">
       <sequence>
           <element name="value" type="string"></element>
       </sequence>
    </complexType>
</schema>
Run Code Online (Sandbox Code Playgroud)

鉴于上述XSD,以下JAXBInstance.newInstance调用成功创建了一个可解析样本a.xml文件的上下文:

  • jc = JAXBContext.newInstance("example.a");
  • jc = JAXBContext.newInstance(example.a.ObjectFactory.class);
  • jc = JAXBContext.newInstance(example.a.RootType.class,example.a.ObjectFactory.class);

但是,在运行时单独传递example.a.RootType.class失败并出现javax.xml.bind.UnmarshalException:

jc = JAXBContext.newInstance(example.a.RootType.class); // this fails at runtime.
Run Code Online (Sandbox Code Playgroud)

任何人都能解释一下吗?我正在试验这些JAXBContext :: newInstance变体的原因是我偶然发现了这个问题,其中接受的答案包括"基于个别类而不是对象工厂构建JAXB上下文"的选项.我正在使用的示例a.xmlJAXB Java代码在帖子的末尾跟随.

示例使用了a.xml

<?xml version="1.0" encoding="UTF-8"?>
<a:root xmlns:a="http://www.example.org/A"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.example.org/A A.xsd">
    <a:value>foo</a:value>
</a:root>
Run Code Online (Sandbox Code Playgroud)

JAXB解析代码

public static void main (String args[]) throws JAXBException, FileNotFoundException {
    JAXBContext jc = null;
    message("using package context (press any key:)");
    jc = JAXBContext.newInstance("example.a");
    work(jc); // SUCCEEDS

    message("using Object factory (press any key):");
    jc = JAXBContext.newInstance(example.a.ObjectFactory.class);
    work(jc); // SUCCEEDS

    message("using class enumeration (press any key):");
    try {
        jc = JAXBContext.newInstance(example.a.RootType.class);
        work(jc);  // FAILS
    } catch (javax.xml.bind.UnmarshalException e) {
        e.printStackTrace();
    }

    message("using class enumeration and Object factory too (press any key):");
    jc = JAXBContext.newInstance(example.a.RootType.class, example.a.ObjectFactory.class);
    work(jc); // SUCCEEDS

}

private static void work(JAXBContext jc) throws JAXBException, FileNotFoundException {
    Unmarshaller u = jc.createUnmarshaller();
    RootType root = ((JAXBElement<RootType>)u.unmarshal( new FileInputStream( "a.xml" ))).getValue();
    System.out.println( root.getValue() );
}
Run Code Online (Sandbox Code Playgroud)

bdo*_*han 16

从XML模式生成的JAXB模型

当创建一个JAXBContext从XML模式生成的模型,我总是建议做它生成的类的包名.

JAXBContext jc = JAXBContext.newInstance("example.a");
Run Code Online (Sandbox Code Playgroud)

使用newInstanceClassLoader参数的方法甚至更好.当您从Java SE迁移到Java EE环境时,这将为您带来悲伤.

JAXBContext jc = JAXBContext.newInstance("example.a", example.a.ObjectFactory.class.getClassLoader());
Run Code Online (Sandbox Code Playgroud)

当您JAXBContext在包名称上创建时,JAXB impl假定您从XML模式生成模型并引入ObjectFactory该类,因为它始终生成@XmlRegistry使用此名称注释的类.

从Java模型开始

这是我建议人们使用newInstance课程的方法.JAXBContext从JAXB类引导a时,调用的类没有什么特别之处ObjectFactory.ObjectFactory任何注释的类都可以扮演角色,@XmlRegistry因此不会自动查找.这就是为什么你的用例在你明确引用ObjectFactory时起作用而在你没有引用时失败的原因.