Как запретить JAXB писать неиспользуемые пространства имен во время сортировки

Кто-нибудь когда-нибудь мог удалить неиспользуемые пространства имен во время маршала объекта, используя JAXB? Вот ссылка на запрошенную функцию: https://github.com/javaee/jaxb-v2/issues/103 (см. Описание)

Есть ли свойство для настройки JAXB для этого? Это было исправлено в MOXy?

В настоящее время я перебираю объект, который нужно маршалировать, и извлекаю все классы, которые должны быть связаны в Class[] classesToBeBound. Затем я создаю новый JAXBContext.newInstance(classesToBeBound)

Неиспользуемые пространства имен теперь не включены в XML.

Я знаю, что валидация XML действительна даже для неиспользуемых пространств имен, но для меня это то, что должна обрабатывать инфраструктура.

Следующая ссылка https://blogs.oracle.com/enterprisetechtips/entry/customizing_jaxb упоминает различные исправления (где-то посередине текста), но при попытке найти решение в этих ссылках либо ссылка не работает, либо никто не решил Это.

Любые комментарии приветствуются.

(РЕДАКТИРОВАТЬ) Простой текст:

ДАНО

a new instance of JAXBContext and add 2 classes with each a separate namespace. 

КОГДА

marshalling a class that has these 2 classes as a property but only 1 of them is not null 

ЗАТЕМ

I expect only the namespace of the property that is not null to be visible in the XML. 

НО ФАКТИЧЕСКИЙ

that both namespaces are in the xml. 

Таким образом, мой вопрос состоял в том, как я могу удалить или сказать JAXB НЕ писать неиспользуемые пространства имен?

Чтобы положить его в java-код: ДАЛИ

public class Foo{
  private Bar bar; //namespace something2
  private User user; //namespace user
}

КОГДА

JAXBContext c = JAXBContext.newInstance(Foo.class, Bar.class, User.class);
...
Foo foo = new Foo();
foo.setBar(null);
foo.setUser(new User("Bob"));
marshaller.umarshal(foo);

Затем я ожидаю, что XML будет

<foo xmlns="something1"  xmlns:user="user">
  <user:name>Bob</user:name>
</foo>

НО АКТУАЛЬНО (обратите внимание на пространство имен some2)

<foo xmlns="something1" xmlns:user="user" xmlns:bar="something2">
  <user:name>Bob</user:name>
</foo>

Конечно, это упрощенный пример, и наша спецификация типа имеет около 30 различных пространств имен.

Ответ 1

Насколько я знаю, это действительно невозможно в JAXB - и на самом деле это хорошо известная проблема. Как вы заметили, список созданных пространств имен - это те, которые были зарегистрированы в вашем JAXBContext, а не те, которые эффективно используются при сортировке :-(

В прошлом я использовал тот же обходной путь, что и вы (определите различные используемые классы и сузьте JAXBContext до этого ограниченного набора классов).

Другой типичный обходной путь - это двухэтапная обработка: сначала выполняется сортировка с помощью JAXB, а затем XSLT-преобразование, позволяющее избавиться от "говорящих" загрязняющих пространств имен.

Ответ 2

Да, они могут быть опущены. Я не уверен, что понял проблему, с которой вы столкнулись. Но нет никаких проблем для маршалирования объекта без пространств имен.

Ответ 3

Это может быть невозможно, поскольку при маршалинге этой иерархии объектов во время создания корневого тега информация о том, какие объекты имеют значение null v/s, но не null, может быть недоступна. Любая попытка получить эту информацию заранее может также иметь связанные с ней побочные эффекты, поскольку вызываются соответствующие методы доступа. Следовательно, JAXB будет статически использовать информацию из JAXBContext для заполнения этой информации.

Ответ 4

Вы можете попробовать использовать другую реализацию javax.xml.bind.Marshaller.

Например, реализация org.eclipse.persistence.jaxb.JAXBMarshaller хорошо справляется с этим случаем и удаляет все ненужные пространства имен при маршалинге объекта.

Для этого вам необходимо выполнить следующие шаги:

  • Добавьте org.eclipse.persistence.jaxb.JAXBMarshaller добавив eclipselink-2.6.5.jar в путь к классам. Если вы используете gradle, вы можете добавить compile 'org.eclipse.persistence:eclipselink:2.6.5' к вашим зависимостям.
  • Создайте файл jaxb.properties в том же пакете, где находятся объекты для маршала (следуя примеру в вашем вопросе - JAXBContext c = JAXBContext.newInstance(Foo.class, Bar.class, User.class); в пакете одного из этих классов Foo, Bar или User).
  • В файле jaxb.properties добавьте свойство follow, которое указывает желаемую фабрику контекста:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

При этом org.eclipse.persistence.jaxb.JAXBMarshaller будет использоваться в качестве реализации javax.xml.bind.Marshaller в среде исполнения. И тогда при маршалинге объектов не появятся ненужные пространства имен.

Ответ 5

Попробуйте что-то вроде этого marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "класс, для которого пространство имен не требуется"); в вашем случае это должен быть marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, bar.class);