rob*_*inr 199 java jaxb xjc fpml
我正在尝试从FpML(Finanial产品标记语言)4.5版生成Java类.生成了大量代码,但我无法使用它.尝试序列化一个简单的文档,我得到这个:
javax.xml.bind.MarshalException
- with linked exception: [com.sun.istack.SAXException2: unable
to marshal type
"org.fpml._2008.fpml_4_5.PositionReport"
as an element because it is missing an
@XmlRootElement annotation]
Run Code Online (Sandbox Code Playgroud)
实际上没有类有@XmlRootElement注释,所以我可以做错什么?我将xjc(JAXB 2.1)指向fpml-main-4-5.xsd,然后包含所有类型.
ska*_*man 256
为了将其他人已经陈述或暗示过的内容联系在一起,JAXB XJC决定是否将@XmlRootElement注释放在生成的类上的规则是非常重要的(参见本文).
@XmlRootElement之所以存在,是因为JAXB运行时需要某些信息才能编组/解组给定对象,特别是XML元素名称和命名空间.你不能只将任何旧物体传递给Marshaller.@XmlRootElement提供此信息.
注释只是一种便利,但JAXB并不需要它.替代方法是使用JAXBElement包装器对象,它提供与对象相同的信息@XmlRootElement,而不是注释.
但是,JAXBElement构造对象很难,因为您需要知道XML元素名称和命名空间,而业务逻辑通常不知道.
值得庆幸的是,当XJC生成类模型时,它还会生成一个名为的类ObjectFactory.这部分是为了向后兼容JAXB v1,但它也是XJC放置生成的工厂方法的地方,这些方法JAXBElement在您自己的对象周围创建包装器.它为您处理XML名称和命名空间,因此您无需担心它.您只需要查看ObjectFactory方法(对于大型模式,可以有数百个)来查找所需的方法.
Gur*_*ard 67
这已在上面已经链接的博客文章的底部提到,但这对我来说很有用:
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(new JAXBElement<MyClass>(new QName("uri","local"), MyClass.class, myClassInstance), System.out);
Run Code Online (Sandbox Code Playgroud)
Mat*_*ise 47
正如在上面的一个答案中暗示的那样,如果在XSD中将其类型定义为命名类型,则不会在根元素上获得XMLRootElement,因为该命名类型可以在XSD中的其他位置使用.尝试将其设为匿名类型,即代替:
<xsd:element name="myRootElement" type="MyRootElementType" />
<xsd:complexType name="MyRootElementType">
...
</xsd:complexType>
Run Code Online (Sandbox Code Playgroud)
你将会拥有:
<xsd:element name="myRootElement">
<xsd:complexType>
...
<xsd:complexType>
</xsd:element>
Run Code Online (Sandbox Code Playgroud)
小智 34
解组时不需要@XmlRootElement - 如果使用Unmarshaller#unmarshall的2参数形式.
所以,如果不是这样做:
UserType user = (UserType) unmarshaller.unmarshal(new StringReader(responseString));
Run Code Online (Sandbox Code Playgroud)
应该做的:
JAXBElement<UserType> userElement = unmarshaller.unmarshal(someSource, UserType.class);
UserType user = userElement.getValue();
Run Code Online (Sandbox Code Playgroud)
后一个代码在UserType类级别不需要@XmlRootElement注释.
小智 20
Joe的回答(Joe Jun 26 '09 at 17:26)为我做了.简单的答案是,如果编组JAXBElement,则缺少@XmlRootElement注释是没有问题的.让我感到困惑的是生成的ObjectFactory有2个createMyRootElement方法 - 第一个不接受任何参数并给出解包的对象,第二个接受解包的对象并返回包装在JAXBElement中,并编组JAXBElement工作正常.这是我使用的基本代码(我是新手,如果代码在此回复中没有正确格式化,请道歉),大部分来自链接文本:
ObjectFactory objFactory = new ObjectFactory();
MyRootElement root = objFactory.createMyRootElement();
...
// Set root properties
...
if (!writeDocument(objFactory.createMyRootElement(root), output)) {
System.err.println("Failed to marshal XML document");
}
...
private boolean writeDocument(JAXBElement document, OutputStream output) {
Class<?> clazz = document.getValue().getClass();
try {
JAXBContext context =
JAXBContext.newInstance(clazz.getPackage().getName());
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(document, output);
return true;
} catch (JAXBException e) {
e.printStackTrace(System.err);
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
Oli*_*ger 18
您可以使用如何在XSD中为基类型生成@XmlRootElement类的绑定来解决此问题?.
这是Maven的一个例子
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.3.1</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>src/main/resources/xsd</schemaDirectory>
<packageName>com.mycompany.schemas</packageName>
<bindingFiles>bindings.xjb</bindingFiles>
<extension>true</extension>
</configuration>
</plugin>
Run Code Online (Sandbox Code Playgroud)
这是binding.xjb文件内容
<?xml version="1.0"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="path/to/myschema.xsd" node="/xs:schema">
<jxb:globalBindings>
<xjc:simple/>
</jxb:globalBindings>
</jxb:bindings>
</jxb:bindings>
Run Code Online (Sandbox Code Playgroud)
如您所知,答案是使用ObjectFactory().这是一个适合我的代码示例:)
ObjectFactory myRootFactory = new ObjectFactory();
MyRootType myRootType = myRootFactory.createMyRootType();
try {
File file = new File("./file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(MyRoot.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
//output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
JABXElement<MyRootType> myRootElement = myRootFactory.createMyRoot(myRootType);
jaxbMarshaller.marshal(myRootElement, file);
jaxbMarshaller.marshal(myRootElement, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
经过两天的挣扎,我找到了问题的解决方案。您可以使用ObjectFactory类来解决没有@XmlRootElement 的类。ObjectFactory 有重载方法来将它包装在 JAXBElement 周围。
方法:1做对象的简单创建。
方法:2将使用@JAXBElement包装对象。
始终使用Method:2来避免 javax.xml.bind.MarshalException - 链接异常缺少 @XmlRootElement 注释。
请在下面找到示例代码
方法:1做对象的简单创建
public GetCountry createGetCountry() {
return new GetCountry();
}
Run Code Online (Sandbox Code Playgroud)
方法:2将使用@JAXBElement包装对象。
@XmlElementDecl(namespace = "my/name/space", name = "getCountry")
public JAXBElement<GetCountry> createGetCountry(GetCountry value) {
return new JAXBElement<GetCountry>(_GetCountry_QNAME, GetCountry.class, null, value);
}
Run Code Online (Sandbox Code Playgroud)
工作代码示例:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
WebServiceTemplate springWSTemplate = context.getBean(WebServiceTemplate.class);
GetCountry request = new GetCountry();
request.setGuid("test_guid");
JAXBElement<GetCountryResponse> jaxbResponse = (JAXBElement<GetCountryResponse>)springWSTemplate .marshalSendAndReceive(new ObjectFactory().createGetCountry(request));
GetCountryResponse response = jaxbResponse.getValue();
Run Code Online (Sandbox Code Playgroud)
它也不适用于我们.但是我们确实找到了一篇广泛引用的文章,增加了一些背景......为了下一个人,我会在这里链接到它:http://weblogs.java.net/blog/kohsuke/archive/2006/03 /why_does_jaxb_p.html
使用 Maven 构建,您可以添加@XmlRootElement注释
与“ jaxb2-basics-annotate”插件。
查看更多信息:见
JAXBElement 包装器适用于@XmlRootElementJAXB 生成no 的情况。这些包装器在ObjectFactory由maven-jaxb2-plugin. 例如:
public class HelloWorldEndpoint {
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "person")
@ResponsePayload
public JAXBElement<Greeting> sayHello(@RequestPayload JAXBElement<Person> request) {
Person person = request.getValue();
String greeting = "Hello " + person.getFirstName() + " " + person.getLastName() + "!";
Greeting greet = new Greeting();
greet.setGreeting(greeting);
ObjectFactory factory = new ObjectFactory();
JAXBElement<Greeting> response = factory.createGreeting(greet);
return response;
}
}
Run Code Online (Sandbox Code Playgroud)
这个主题相当古老,但在企业业务环境中仍然相关。我尽量避免接触 xsd,以便将来轻松更新它们。这是我的解决方案..
xjc:simple就足够了<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc">
<jxb:globalBindings>
<xjc:simple/> <!-- adds @XmlRootElement annotations -->
</jxb:globalBindings>
</jxb:bindings>
Run Code Online (Sandbox Code Playgroud)
它将主要创建 XmlRootElements 用于导入 xsd 定义。
jaxb2-maven-plugin执行我遇到过,如果您尝试从多个 xsd 定义而不是每个 xsd 的执行定义生成类,则会产生巨大的差异。
因此,如果您有一个包含多个 的定义<source>,那么只需尝试拆分它们:
<execution>
<id>xjc-schema-1</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<xjbSources>
<xjbSource>src/main/resources/xsd/binding.xjb</xjbSource>
</xjbSources>
<sources>
<source>src/main/resources/xsd/definition1/</source>
</sources>
<clearOutputDir>false</clearOutputDir>
</configuration>
</execution>
<execution>
<id>xjc-schema-2</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<xjbSources>
<xjbSource>src/main/resources/xsd/binding.xjb</xjbSource>
</xjbSources>
<sources>
<source>src/main/resources/xsd/definition2/</source>
</sources>
<clearOutputDir>false</clearOutputDir>
</configuration>
</execution>
Run Code Online (Sandbox Code Playgroud)
生成器不会捕获一个类可能就足够的事实,因此每次执行都会创建自定义类。这正是我所需要的;)。
万一我对这个问题的经验给某人一个尤里卡!时刻..我将添加以下内容:
当使用通过IntelliJ的“从实例文档生成xsd”菜单选项生成的xsd文件时,我也遇到了这个问题。
当我接受该工具的所有默认设置时,它会生成一个xsd文件,与jaxb一起使用时,会生成no的java文件@XmlRootElement。在运行时,当我尝试进行封送时,遇到了与该问题相同的异常。
我回到IntellJ工具,在“ Desgin Type”下拉菜单中看到了默认选项(当然,我不明白,但我还是不知道),它是:
设计类型:
“本地元素/全局复杂类型”
我将其更改为
“本地元素/类型”
,现在它生成了一个(基本上)不同的xsd,@XmlRootElement当与jaxb一起使用时,生成了xsd 。不能说我了解它的来龙去脉,但是它对我有用。
因此,我使用 Mavenmaven-jaxb2-plugin从一个大型且复杂的 WSDL 文件生成类,并遇到了这个问题。问题是 WSDL 中的元素将complexType定义引用为 ,type因此未生成元素类,并且在尝试使用复杂类型类时会产生丢失错误@XmlRootElement。
在我看来,修改 WSDL 并不是一个真正可行的解决方案,唯一实用的似乎是设计一种在生成过程中添加缺少的注释的方法。它还会在编组时导致序列化问题,因为请求发送了错误的元素名称,并且响应中也没有具有匹配元素名称的类。
我最终做的是使用第二个 Maven 插件jaxb2-basics-annotate,它允许您通过使用 jaxb 绑定文件将缺少的注释添加到所需的类。这使您无需添加不必要的代码即可解决此问题,并且还意味着如果您将来需要使用更新的 WSDL 文件,您可以轻松地重新生成。
pom.xml(请注意,配置中有一个用于执行的插件部分 - WSDL 文件位置为 /src/main/resources/wsdl/EstimatingService.wsdl)
<project>
...
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<jaxb2.version>0.14.0</jaxb2.version>
<jaxb2.annotate.version>1.1.0</jaxb2.annotate.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>${jaxb2.version}</version>
</dependency>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
<version>${jaxb2.annotate.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>${jaxb2.version}</version>
<executions>
<execution>
<id>estimating</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaLanguage>WSDL</schemaLanguage>
<generateDirectory>target/generated-sources/acme/src/gen/estimating-service</generateDirectory>
<generatePackage>com.acme.shipping.estimating.service</generatePackage>
<schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
<schemaIncludes>
<include>EstimatingService.wsdl</include>
</schemaIncludes>
<bindingDirectory>${project.basedir}/src/main/resources/bindings</bindingDirectory>
<bindingIncludes>estimateServiceBinding.xjb</bindingIncludes>
<extension>true</extension>
<args>
<arg>-Xannotate</arg>
<arg>-XremoveAnnotation</arg>
</args>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
</plugin>
</plugins>
</configuration>
</execution>
...
// More executions here if you have multiple WSDL files (Dont forget to give it a different package name and id)
</executions>
</plugin>
</plugins>
</build>
...
</project>
Run Code Online (Sandbox Code Playgroud)
估计服务绑定.xjb(本示例中使用的 jaxb 绑定文件 - /src/main/resources/bindings/estimateServiceBinding.xjb)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:annox="http://annox.dev.java.net" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<jaxb:globalBindings generateElementProperty="false">
<xjc:simple />
</jaxb:globalBindings>
<!-- Target the schema section in the WSDL file using the given target namespace which contains the complexType definitions we want to annotate -->
<jaxb:bindings schemaLocation="../wsdl/EstimatingService.wsdl" node="//xs:schema[@targetNamespace='http://acme.com/schema/datatypes/v2']">
<jaxb:bindings node="xs:complexType[@name='GetQuickEstimateRequestContainer']">
<!-- Add the @XmlRootElement annotation to the generated class and then tell it use the correct element name required when marshalling. e.g GetQuickEstimateRequestContainer element is renamed to the element name that referenced it in the WSDL (GetQuickEstimateRequest) -->
<annox:annotateClass>@javax.xml.bind.annotation.XmlRootElement(name="GetQuickEstimateRequest")</annox:annotateClass>
</jaxb:bindings>
<jaxb:bindings node="xs:complexType[@name='GetQuickEstimateResponseContainer']">
<annox:annotateClass>@javax.xml.bind.annotation.XmlRootElement(name="GetQuickEstimateResponse")</annox:annotateClass>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Run Code Online (Sandbox Code Playgroud)
生成的类(GetQuickEstimateRequestContainer.java) 具有 @XmlRootElement 注释和正确的元素名称
@XmlRootElement(name = "GetQuickEstimateRequest")
public class GetQuickEstimateRequestContainer {
...
// class member fields & setters and getters
...
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
239481 次 |
| 最近记录: |