Я пытаюсь использовать MOXy для настройки алгоритма именования для XML-маршалинга и генерации схемы для классов в нескольких пакетах.
Я следую документации Eclipse и могу заставить его работать для одного класса:
@XmlNameTransformer(com.example.test.NameGenerator.class)
public class Customer
или один пакет:
@XmlNameTransformer(com.example.test.NameGenerator.class)
package com.example.test;
(также работает внешний файл привязок, но снова вы можете указать только пакет для каждого файла привязки)
Однако, поскольку у меня есть объекты, связанные с несколькими пакетами, я не хочу определять трансформатор для каждого пакета. Кроме того, я хотел бы сделать это динамически (т.е. отдельные пакеты неизвестны до выполнения).
Я попытался определить трансформатор в родительском пакете (com.example
), но это не сработает - похоже, что это должен быть точный пакет, в котором находятся аннотированные классы.
Есть идеи?
Обновление - дополнительная информация
Возможно, я должен упомянуть, что основная причина, по которой я пытаюсь сделать это, чтобы я мог контролировать процесс генерации XML/XSD, и, в частности, я хочу, чтобы сложные типы были в прописном, а не по умолчанию ниже (без необходимости комментировать каждый один класс), например
@XmlRootElement
public class Test ...
должен генерировать:
<Test>
...
</Test>
вместо
<test>
...
</test>
Из других исследований, которые я сделал, единственный способ, которым я нашел это, - это XmlNameTransformer
. Но если есть другой способ, и я лаю неправильное дерево... определенно дайте мне знать!
Уровень пакета - это самый большой объем, на котором вы можете указать метаданные MOXy/JAXB. Вы можете использовать ту же реализацию XmlNameTransformer
но вам нужно будет указать ее для каждого пакета, к которому вы хотите применить.
Однако, поскольку у меня есть объекты, связанные с несколькими пакетами, я не хочу определять трансформатор для каждого пакета. Кроме того, я хотел бы сделать это динамически (т.е. отдельные пакеты неизвестны до выполнения).
Вы можете программно создать объектную модель, соответствующую внешнему картографическому документу. Затем вы можете передать экземпляр этого при создании JAXBContext
.
Развернувшись на ответ Блейз, вот как выглядит моя реализация. Это достигается использованием трансформатора для динамического набора пакетов.
import org.eclipse.persistence.jaxb.metadata.MetadataSourceAdapter;
import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings;
import org.eclipse.persistence.jaxb.xmlmodel.XmlSchema;
public class NameTransformerAdapter extends MetadataSourceAdapter {
private XmlBindings bindings;
/**
* @param packageName Fully qualified package name, like {@code com.example.test}
*/
public NameTransformerAdapter(String packageName) {
bindings = new XmlBindings();
bindings.setPackageName(packageName);
bindings.setXmlNameTransformer(XmlNameTransformer.class.getName());
bindings.setXmlSchema(new XmlSchema()); // this is necessary
}
@Override
public XmlBindings getXmlBindings(Map<String, ?> properties, ClassLoader classLoader) {
return bindings;
}
}
Указанный трансформатор довольно прост:
import org.eclipse.persistence.oxm.XMLNameTransformer;
public class XmlNameTransformer implements XMLNameTransformer {
/** Uses capitalized name of class */
public String transformTypeName(String name) {
return name.substring(name.lastIndexOf('.') + 1);
}
public String transformElementName(String name) {
return name;
}
public String transformAttributeName(String name) {
return name;
}
public String transformRootElementName(String name) {
return transformTypeName(name);
}
}
Пакеты определяются во время выполнения и отслеживаются как таковые:
List<MetadataSource> adapters = new ArrayList<MetadataSource>();
adapters.add(new NameTransformerAdapter(packageName));
Наконец, JAXBContext может быть получен с использованием вышеперечисленных адаптеров:
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
private JAXBContext getContext(Class<?>[] classes) throws JAXBException {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, adapters);
return JAXBContextFactory.createContext(classes, properties);
}