[SPRING] NamespacePrefixMapper를 사용하지 않고 Spring JAXB 네임 스페이스 정의
SPRINGNamespacePrefixMapper를 사용하지 않고 Spring JAXB 네임 스페이스 정의
[이해 진행으로 심하게 편집]
NamespacePrefixMapper의 확장을 사용하지 않고 Spring Jaxb2Marshaller가 네임 스페이스 접두어의 사용자 정의 집합을 사용하도록 할 수 있습니까 (아니면 적어도 스키마 파일 / 주석에 지정된 접두어를 존중해야합니까)?
아이디어는 다른 클래스에 "has a"관계가있는 클래스를 가지게되는데,이 클래스는 다른 네임 스페이스를 가진 속성을 포함합니다. 이것을 더 잘 설명하기 위해 JDK1.6.0_12를 사용하는 다음 프로젝트 개요를 고려하십시오. (최신으로 직장에서 손을 얻을 수 있습니다.) org.example.domain 패키지에 다음 항목이 있습니다.
Main.java:
package org.example.domain;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class Main {
public static void main(String[] args) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(RootElement.class);
RootElement re = new RootElement();
re.childElementWithXlink = new ChildElementWithXlink();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(re, System.out);
}
}
RootElement.java:
package org.example.domain;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(namespace = "www.example.org/abc", name="Root_Element")
public class RootElement {
@XmlElement(namespace = "www.example.org/abc")
public ChildElementWithXlink childElementWithXlink;
}
ChildElementWithXLink.java:
package org.example.domain;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
@XmlRootElement(namespace="www.example.org/abc", name="Child_Element_With_XLink")
public class ChildElementWithXlink {
@XmlAttribute(namespace = "http://www.w3.org/1999/xlink")
@XmlSchemaType(namespace = "http://www.w3.org/1999/xlink", name = "anyURI")
private String href="http://www.example.org";
}
package-info.java:
@javax.xml.bind.annotation.XmlSchema(
namespace = "http://www.example.org/abc",
xmlns = {
@javax.xml.bind.annotation.XmlNs(prefix = "abc", namespaceURI ="http://www.example.org/abc"),
@javax.xml.bind.annotation.XmlNs(prefix = "xlink", namespaceURI = "http://www.w3.org/1999/xlink")
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.example.domain;
Main.main ()을 실행하면 다음과 같은 결과가 출력됩니다.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:Root_Element xmlns:ns1="http://www.w3.org/1999/xlink" xmlns:ns2="www.example.org/abc">
<ns2:childElementWithXlink ns1:href="http://www.example.org"/>
</ns2:Root_Element>
반면에 내가 원하는 것은 :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<abc:Root_Element xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:abc="www.example.org/abc">
<abc:childElementWithXlink xlink:href="http://www.example.org"/>
</abc:Root_Element>
이 부분이 작동하면 문제는 간단한 컨텍스트 구성을 사용하여 동일하게 제공되도록 Spring에서 Jaxb2Marshaller를 구성 (Spring 2.5.6, spring-oxm-tiger-1.5.6 Jaxb2Marshaller 제공)하고 marshal () 호출.
이 문제에 대한 지속적인 관심에 감사드립니다.
해결법
-
==============================
1.[JAXB-RI 대안을 제공하기위한 일부 편집은이 게시물의 끝 부분에 있습니다]
[JAXB-RI 대안을 제공하기위한 일부 편집은이 게시물의 끝 부분에 있습니다]
많은 머리를 긁어 낸 후에 마침내 제 환경 (Windows XP의 JDK1.6.0_12 및 Mac Leopard의 JDK1.6.0_20)을 받아 들여야했습니다. 나는 NamespacePrefixMapper 인 악의에 의존하지 않고서는이 작업을 수행 할 수 없습니다. . 그것은 왜 악한가? 프로덕션 코드에서 내부 JVM 클래스에 의존해야하기 때문입니다. 이러한 클래스는 JVM과 코드 간의 신뢰할 수있는 인터페이스의 일부가 아닙니다. 즉, JVM의 업데이트간에 변경됩니다.
제 의견으로는 Sun이이 문제를 다루어야하거나 더 깊은 지식을 가진 사람이이 답변에 추가 할 수 있습니다 - 제발하십시오!
계속 전진 해. NamespacePrefixMapper는 JVM 외부에서 사용되지 않아야하기 때문에 javac의 표준 컴파일 경로 (ct.sym에서 제어되는 rt.jar의 하위 섹션)에는 포함되어 있지 않습니다. 즉, IDE에 따라 달라지는 코드는 IDE에서 정상적으로 컴파일되지만 명령 행 (예 : Maven 또는 Ant)에서는 실패합니다. 이 문제를 극복하려면 rt.jar 파일을 빌드에 명시 적으로 포함시켜야하며, 심지어 경로에 공백이 있으면 Windows에 문제가있는 것 같습니다.
이 자리에 있으면 다음과 같은 문제가 발생하는 Maven 스 니펫이 있습니다.
<dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.1.9</version> <scope>system</scope> <!-- Windows will not find rt.jar if it is in a path with spaces --> <systemPath>C:/temp/rt.jar</systemPath> </dependency>
rt.jar에 이상한 곳으로 하드 코드 된 경로를주의하십시오. 대부분의 OS에서 작동하는 {java.home} /lib/rt.jar의 조합으로이 문제를 해결할 수 있지만 Windows 공간 문제로 인해 문제가 발생하지는 않습니다. 예, 프로필을 사용하고 그에 따라 활성화 할 수 있습니다 ...
또는 Ant에서 다음을 수행 할 수 있습니다.
<path id="jre.classpath"> <pathelement location="${java.home}\lib" /> </path> // Add paths for build.classpath and define {src},{target} as usual <target name="compile" depends="copy-resources"> <mkdir dir="${target}/classes"/> <javac bootclasspathref="jre.classpath" includejavaruntime="yes" debug="on" srcdir="${src}" destdir="${target}/classes" includes="**/*"> <classpath refid="build.classpath"/> </javac> </target>
그리고 Jaxb2Marshaller Spring 구성은 무엇입니까? 자, 여기 내 자신의 NamespacePrefixMapper로 완성됩니다 :
봄:
<!-- JAXB2 marshalling (domain objects annotated with JAXB2 meta data) --> <bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> <property name="contextPaths"> <list> <value>org.example.domain</value> </list> </property> <property name="marshallerProperties"> <map> <!-- Good for JDK1.6.0_6+, lose 'internal' for earlier releases - see why it's evil? --> <entry key="com.sun.xml.internal.bind.namespacePrefixMapper" value-ref="myCapabilitiesNamespacePrefixMapper"/> <entry key="jaxb.formatted.output"><value type="boolean">true</value></entry> </map> </property> </bean> <!-- Namespace mapping prefix (ns1->abc, ns2->xlink etc) --> <bean id="myNamespacePrefixMapper" class="org.example.MyNamespacePrefixMapper"/>
다음 내 NamespacePrefixMapper 코드 :
public class MyNamespacePrefixMapper extends NamespacePrefixMapper { public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) { if (requirePrefix) { if ("http://www.example.org/abc".equals(namespaceUri)) { return "abc"; } if ("http://www.w3.org/1999/xlink".equals(namespaceUri)) { return "xlink"; } return suggestion; } else { return ""; } } }
그럼 거기에 있습니다. 나는 이것이 누군가가 고통을 피하는 데 도움이되기를 바랍니다. 아, 그런데, 위의 사악한 접근법을 부두에서 사용하면 다음과 같은 예외가 발생할 수 있습니다.
java.lang.IllegalAccessError : 클래스 sun.reflect.GeneratedConstructorAccessor23의 슈퍼 클래스 sun.reflect.ConstructorAccessorImpl에 액세스 할 수 없습니다.
그래서 행운을 빌어 요. 단서 : 웹 서버의 bootclasspath에있는 rt.jar.
[JAXB-RI (Reference Implementation) 접근법을 보여줄 수 있도록 추가 편집]
코드에 JAXB-RI 라이브러리를 도입 할 수 있다면 다음과 같은 수정을 통해 동일한 효과를 얻을 수 있습니다.
본관:
// Add a new property that implies external access marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new MyNamespacePrefixMapper());
MyNamespacePrefixMapper :
// Change the import to this import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
/ lib 폴더에서 JAXB-RI 다운로드 (라이센스 고리를 뛰어 넘은 후)에서 다음 JAR을 추가하십시오.
jaxb-impl.jar
Main.main ()을 실행하면 원하는 출력이 생성됩니다.
-
==============================
2.(크게 편집 된 응답)
(크게 편집 된 응답)
귀하의 코드에서 문제가 일부 네임 스페이스 URI 불일치로 인한 것이라고 생각합니다. 때로는 "http://www.example.org/abc"및 다른 번 "www.example.org/abc"를 사용하고 있습니다. 다음과 같은 트릭을해야합니다 :
Main.java
package org.example.domain; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; public class Main { public static void main(String[] args) throws JAXBException { JAXBContext jc = JAXBContext.newInstance(RootElement.class); System.out.println(jc); RootElement re = new RootElement(); re.childElementWithXlink = new ChildElementWithXlink(); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(re, System.out); } }
RootElement.java
package org.example.domain; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(namespace="http://www.example.org/abc", name="Root_Element") public class RootElement { @XmlElement(namespace = "http://www.example.org/abc") public ChildElementWithXlink childElementWithXlink; }
ChildElementWithXLink.java
package org.example.domain; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSchemaType; @XmlRootElement(namespace="http://www.example.org/abc", name="Child_Element_With_XLink") public class ChildElementWithXlink { @XmlAttribute(namespace = "http://www.w3.org/1999/xlink") @XmlSchemaType(namespace = "http://www.w3.org/1999/xlink", name = "anyURI") private String href="http://www.example.org"; }
package-info.java
@javax.xml.bind.annotation.XmlSchema( namespace = "http://www.example.org/abc", xmlns = { @javax.xml.bind.annotation.XmlNs(prefix = "abc", namespaceURI ="http://www.example.org/abc"), @javax.xml.bind.annotation.XmlNs(prefix = "xlink", namespaceURI = "http://www.w3.org/1999/xlink") }, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) package org.example.domain;
이제 Main.main ()을 실행하면 다음과 같은 결과가 출력됩니다.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <abc:Root_Element xmlns:abc="http://www.example.org/abc" xmlns:xlink="http://www.w3.org/1999/xlink"> <abc:childElementWithXlink xlink:href="http://www.example.org"/> </abc:Root_Element>
-
==============================
3.@Blaise :이 정보로 MOXy의 문서를 업데이트 할 수 있습니까?
@Blaise :이 정보로 MOXy의 문서를 업데이트 할 수 있습니까?
NamespacePrefixMapper를 사용하지 않고 Spring JAXB 네임 스페이스 정의
네임 스페이스 접두사를 구성하는 방법은 여기에 설명되어 있지 않다고 생각합니다. 감사!
-
==============================
4.JDK 7의 JAXB 구현은 네임 스페이스 접두어를 지원합니다. JDK 1.6.0_21을 사용해 보았습니다.
JDK 7의 JAXB 구현은 네임 스페이스 접두어를 지원합니다. JDK 1.6.0_21을 사용해 보았습니다.
from https://stackoverflow.com/questions/3289644/define-spring-jaxb-namespaces-without-using-namespaceprefixmapper by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring 데이터 + 다중 데이터 소스가 있지만 하나의 리포지토리 세트 만있는 JPA (0) | 2018.12.23 |
---|---|
[SPRING] Spring : 컨텍스트 루트 외부에서 정적 리소스 제공 (0) | 2018.12.23 |
[SPRING] Spring bean에서 HttpServletRequest를 얻으려면 어떻게해야합니까? (0) | 2018.12.23 |
[SPRING] 매개 변수 속성을 가진 스프링 데이터 JPA 쿼리 (0) | 2018.12.23 |
[SPRING] Spring Framework 테스트 RESTful 웹 서비스 (컨트롤러) 오프라인 (즉, 서버 없음, 데이터베이스 없음) (0) | 2018.12.23 |