[Некоторые правки, предлагающие альтернативу JAXB-RI, находятся в конце этого поста]
Ну, после долгих царапин мне, наконец, пришлось принять это для моей среды (JDK1.6.0_12 в WindowsXP и JDK1.6.0_20 на Mac Leopard) Я просто не могу заставить это работать, не прибегая к злу, которое является NamespacePrefixMapper.Почему это зло?Потому что это заставляет полагаться на внутренний класс JVM в вашем производственном коде.Эти классы не являются частью надежного интерфейса между JVM и вашим кодом (т.е. они меняются между обновлениями JVM).
По моему мнению, Sun должна решить эту проблему, или кто-то с более глубокими знаниями мог бы добавить к этому ответу - пожалуйста!
Двигаемся дальше.Поскольку NamespacePrefixMapper не предполагается использовать вне JVM, он не включен в стандартный путь компиляции javac (подраздел rt.jar, контролируемый ct.sym).Это означает, что любой код, который зависит от него, вероятно, будет хорошо компилироваться в 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.Вы можете обойти это с помощью комбинации {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:
Spring:
<!-- 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 "";
}
}
}
Ну, вот оно.Надеюсь, это поможет кому-то избежать боли, через которую я прошел.О, кстати, вы можете столкнуться со следующим исключением, если вы используете вышеуказанный злой подход в Jetty:
java.lang.IllegalAccessError: классу sun.reflect.GeneratedConstructorAccessor23 не удается получить доступ к его суперклассу sun.reflect.ConstructorAccessorImpl
Так что удачи в сортировке.Подсказка: rt.jar в пути загрузки вашего веб-сервера.
[Дополнительные правки, чтобы показать подход JAXB-RI (эталонная реализация)]
Если вы можете ввести Библиотеки JAXB-RI в своем коде вы можете внести следующие изменения, чтобы получить тот же эффект:
Main:
// 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;
Добавьте следующий JAR-файл из загрузки JAXB-RI (после перехода через лицензионные циклы) из папки / lib:
jaxb-impl.jar
Запуск Main.main () приведет к желаемому выводу.