JAXB에 의해 생성된 @XmlRootElement가 없습니다.
FpML(Financial Products Markup Language) 버전 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]
실제로 @XmlRootElement 주석이 있는 클래스는 없습니다.무엇을 잘못하고 있는 걸까요?xjc(JAXB 2.1)를 fpml-main-4-5.xd에 포인팅합니다.이것에는 모든 타입이 포함됩니다.
XJC를 말한 합니다.@XmlRootElement
생성된 클래스에 대한 주석은 단순하지 않습니다(이 문서 참조).
@XmlRootElement
JAXB 런타임에서는 특정 오브젝트(특히 XML 요소 이름 및 네임스페이스)를 정리/해제하기 위해 특정 정보가 필요하기 때문에 존재합니다.오래된 물건을 마샬러에게 넘겨줄 순 없어 @XmlRootElement
에 이 정보를 나타냅니다.
주석은 편리할 뿐이지만 JAXB에는 필요하지 않습니다.대신 사용할 수 있습니다.JAXBElement
오브젝트: 래퍼 오브젝트와 합니다.@XmlRootElement
주석이 아닌 오브젝트 형태로 표시됩니다.
★★★★★★★★★★★★★★.JAXBElement
일반적으로 비즈니스 로직에서는 알 수 없는 XML 요소 이름과 네임스페이스를 알아야 하기 때문에 오브젝트는 구축하기가 어렵습니다.
모델을 때 XJC라는 합니다.ObjectFactory
을 위해 가 JAXB v1을 JAXBElement
자신의 오브젝트에 래퍼를 붙입니다.XML 이름과 네임스페이스를 대신 처리하므로 걱정할 필요가 없습니다. 요.ObjectFactory
메서드(및 대규모 스키마의 경우 수백 개까지 가능)를 사용하여 필요한 스키마를 찾을 수 있습니다.
이것은 이미 링크되어 있는 블로그 투고의 하부에 기재되어 있습니다만, 이것은 저에게 있어서 매우 도움이 됩니다.
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);
위의 답변 중 하나에서 알 수 있듯이 XSD에서 루트 요소의 유형이 명명된 유형으로 정의되어 있으면 루트 요소에서 XMLRootElement를 얻을 수 없습니다.이러한 명명된 유형은 XSD의 다른 곳에서 사용될 수 있기 때문입니다.익명의 타입으로 해 주세요.즉, 다음과 같은 것이 아닙니다.
<xsd:element name="myRootElement" type="MyRootElementType" />
<xsd:complexType name="MyRootElementType">
...
</xsd:complexType>
다음과 같은 것이 있습니다.
<xsd:element name="myRootElement">
<xsd:complexType>
...
<xsd:complexType>
</xsd:element>
@XmlRootElement는 Unmarshaller#unmarshall이라는2개의 파라미터 형식을 사용하는 경우 마샬링 해제에는 필요하지 않습니다.
따라서 다음 작업을 수행하는 대신
UserType user = (UserType) unmarshaller.unmarshal(new StringReader(responseString));
다음을 수행해야 합니다.
JAXBElement<UserType> userElement = unmarshaller.unmarshal(someSource, UserType.class);
UserType user = userElement.getValue();
후자의 코드는 UserType 클래스레벨에서 @XmlRootElement 주석을 필요로 하지 않습니다.
이 문제는 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>
.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>
Joe의 답변(Joe Jun 26 '09 17:26)으로 알 수 있습니다.간단한 답변은 JAXBelement를 Marshal하면 @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;
}
}
아시다시피 답은 Object Factory()를 사용하는 것입니다.여기 나에게 도움이 된 코드 샘플이 있습니다:)
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();
}
나는 이틀 동안 허우적거린 끝에 문제의 해결책을 찾아냈다.ObjectFactory 클래스를 사용하여 @XmlRootElement가 없는 클래스를 해결할 수 있습니다.ObjectFactory에서 JAXBelement를 감싸는 메서드가 오버로드되었습니다.
Method:1은 오브젝트를 단순하게 만듭니다.
메서드:2는 오브젝트를 @JAXBelement로 랩합니다.
javax.xml.bind를 피하려면 항상 Method:2를 사용합니다.MarshalException - 링크된 예외에 @XmlRootElement 주석이 없습니다.
아래의 샘플 코드를 찾으십시오.
Method:1은 오브젝트를 단순하게 만듭니다.
public GetCountry createGetCountry() {
return new GetCountry();
}
메서드: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);
}
작업 코드 샘플:
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();
이 문제에 대한 나의 경험이 누군가에게 유레카!의 순간을 줄지도 모른다.다음을 추가합니다.
IntelliJ의 "Generate xsd from Instance document" 메뉴 옵션을 사용하여 생성한 xsd 파일을 사용할 때도 이 문제가 발생하였습니다.
jaxb와 함께 하면 no-s-no-no-java-no-java-no-java 되었습니다.@XmlRootElement
. 시 실행 시 이 질문에서 설명한 것과 동일한 예외를 받았습니다.
IntelJ 툴로 돌아가서 [Desgin Type]드롭다운에 디폴트옵션을 표시했습니다(물론 저는 이해하지 못했습니다).그리고 내가 정직하다고 해도 여전히 그렇지 않다)는 것이었다.
데스긴 유형:
"로컬 요소/글로벌 복합 유형"
이거로 바꿨어요
"로컬 요소/유형"
에서 (xsd가 되어 "xsd"가 생성되었습니다@XmlRootElement
jaxb와 함께 .이런저런 얘기를 다 이해한다고는 할 수 없지만 나한테는 효과가 있었어.
는 JAXBelement가 없는 경우에 할 수 .@XmlRootElement
JAXB를 사용하다은 러음음음음음음음음음음 these these these these these these these these these these these these these these these these these these .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;
}
}
저희도 안 돼요.하지만 널리 인용된 기사를 찾았는데...다음 사용자를 위해 여기에 링크하겠습니다.http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html
에서는 Maven을 할 수 .@XmlRootElement
」
「」와 함께jaxb2-basics-annotate
「플러그인.
자세한 것은, 을 참조해 주세요.
JAXB를 사용하여 XML 스키마에서 클래스를 생성하도록 Maven 구성
xsd를 이렇게 바꾸려고 했나요?
<!-- create-logical-system -->
<xs:element name="methodCall">
<xs:complexType>
...
</xs:complexType>
</xs:element>
이 주제는 상당히 오래되었지만 여전히 엔터프라이즈 비즈니스 맥락에서 관련이 있습니다.향후 업데이트를 쉽게 하기 위해 xsds를 만지지 않도록 노력했습니다.다음은 저의 해결책입니다.
1. ★★★★★★★★★★★★★★★★.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>
대부분 xsd 정의를 Import하기 위한 XmlRootElements를 만듭니다.
2. 나누기.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>
생성기는 하나의 클래스로 충분할 수 있다는 사실을 인식하지 못하기 때문에 실행당 사용자 지정 클래스를 만듭니다.그리고 그것이 바로 내가 필요로 하는 것이다;)
문제를 해결하려면 먼저 wsimport를 사용하여 컴파일할 xml 바인딩을 구성해야 합니다.generateElementProperty는 false로 설정합니다.
<jaxws:bindings wsdlLocation="LOCATION_OF_WSDL"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>
<jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='NAMESPACE_OF_WSDL']">
<jxb:globalBindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xjc:generateElementProperty>false</xjc:generateElementProperty>
</jxb:globalBindings>
</jaxws:bindings>
</jaxws:bindings>
저는 maven을 하고 있었습니다.maven-jaxb2-plugin
크고 복잡한 WSDL 파일에서 클래스를 생성하여 이 문제에 대처합니다.는 WSDL의 가 WSDL을 입니다.complexType
「」라고 정의type
되지 않은 된 complexType이 됩니다.@XmlRootElement
WSDL을 수정하는 것은 실제로 실행 가능한 솔루션이 아닙니다.실용적인 유일한 방법은 생성 중에 누락된 주석을 추가하는 방법을 고안하는 것이었습니다.또한 요구가 잘못된 요소 이름을 전송하고 있고 응답에 일치하는 요소 이름을 가진 클래스가 없었기 때문에 마샬링 시 시리얼라이제이션에 문제가 발생했습니다.
두 플러그인을 .jaxb2-basics-annotate
을 사용하여 누락된 주석을 할 수 있습니다.jaxb는 생략할 수 있습니다.이것에 의해, 불필요한 코드를 추가하지 않고 이 문제를 해결할 필요가 없어집니다.또, 향후 갱신된 WSDL 파일을 사용할 필요가 있는 경우에도, 간단하게 재작성할 수 있습니다.
pom.xml (실행 설정에는 플러그인 섹션이 있음을 주의해 주십시오.WSDL 파일의 위치는 /src/main/resources/wsdl/Estimating Service.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>
extimateServiceBinding.xjb(이 예에서는 /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>
@XmlRootElement 주석과 올바른 요소 이름을 가진 생성된 클래스(GetQuickEstimateRequestContainer.java)
@XmlRootElement(name = "GetQuickEstimateRequest")
public class GetQuickEstimateRequestContainer {
...
// class member fields & setters and getters
...
}
저는 같은 문제로 잠시 고민하고 있었고, 제게 잘 맞는 최종 결과를 게시하고 싶을 뿐입니다.지금까지의 기본적인 문제는 다음과 같습니다.
- XmlRootElement 주석이 없는 JAXB 클래스 인스턴스에서 xml 문자열을 생성해야 합니다.
- 클래스는 마샬링 프로세스에 바인딩할 추가 클래스가 필요합니다.
이 문제에 대해서는, 다음의 클래스가 올바르게 동작합니다.
public class Object2XmlConverter {
public static <T> String convertToString(final T jaxbInstance, final Class<?>... additionalClasses)
throws JAXBException {
final Class<T> clazz = (Class<T>) jaxbInstance.getClass();
final JAXBContext jaxbContext;
if (additionalClasses.length > 0) {
// this path is only necessary if you need additional classes to be bound
jaxbContext = JAXBContext.newInstance(addClassesToBeBound(clazz, additionalClasses));
} else {
jaxbContext = JAXBContext.newInstance(clazz);
}
final QName qname = new QName("", jaxbInstance.getClass().getSimpleName());
final JAXBElement<T> jaxbElement = new JAXBElement<T>(qname, clazz, null, jaxbInstance);
final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
final StringWriter stringWriter = new StringWriter();
jaxbMarshaller.marshal(jaxbElement, stringWriter);
return stringWriter.toString();
}
private static <T> Class<?>[] addClassesToBeBound(final Class<T> clazz, final Class<?>[] additionalClasses) {
final Class<?>[] classArray = new Class<?>[additionalClasses.length + 1];
for (int i = 0; i < additionalClasses.length; i++) {
classArray[i] = additionalClasses[i];
}
classArray[classArray.length - 1] = clazz;
return classArray;
}
public static void main(final String[] args) throws Exception {
final Ns1TargetHeaderTyp dataTyp = ...;
System.out.println(convertToString(dataTyp));
}
}
언급URL : https://stackoverflow.com/questions/819720/no-xmlrootelement-generated-by-jaxb
'programing' 카테고리의 다른 글
**는 C언어로 무엇을 합니까? (0) | 2022.05.29 |
---|---|
VueJS + Gravity Forms API (0) | 2022.05.29 |
curl_global_init, curl_easy_init 및 기타 함수에 대한 정의되지 않은 참조(C) (0) | 2022.05.29 |
vue b-table 모든 행을 표시하도록 페이지 번호 사용자 지정 (0) | 2022.05.29 |
콘솔을 사용하여 커밋에 데이터를 삽입하려면 어떻게 해야 합니까?VueX (0) | 2022.05.29 |