Я пытаюсь использовать Moxy v2.5.2 binding.xml для сопоставления класса в качестве альтернативы аннотациям, поскольку я не могу помещать аннотации в родительский класс третьей стороны.
EDIT: я изменил эту часть ниже после обратной связи с Blaise
Кажется, я не могу сопоставить интерфейс из-за родительских интерфейсов.
Фрагмент кода Java:
public final class CmsContent {
private ContentItemGroup group;
.... getter/setters
}
public class ContentItemGroupDefault extends CoreKeyBase implements ContentItemGroup {
private String bla;
.... getter/setters
}
Файл привязки:
<xml-bindings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="com.core.domain" xml-mapping-metadata-complete="true" xml-accessor-type="NONE">
<java-types>
<java-type name="CmsContent" super-type="java.lang.Object" xml-accessor-type="NONE" >
<xml-root-element name="content" />
<java-attributes>
<xml-element java-attribute="group" name="group" type="com.core.domain.impl.ContentItemGroupDefault" />
</java-attributes>
</java-type>
<java-type name="ContentItemGroupDefault" super-type="java.lang.Object" xml-accessor-type="NONE">
<java-attributes>
<xml-attribute java-attribute="id" name="key" /> <!-- from parent class -->
<xml-transient java-attribute="name" />
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
И код для его маршала:
final Map<String, Object> properties = new HashMap<String, Object>();
final InputStream bindings = CmsContent.class.getResourceAsStream("jaxb-binding.xml");
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, bindings);
final Class<?>[] classes = new Class<?>[] { CmsContent.class};
final JAXBContext context = JAXBContext.newInstance(classes, properties);
final Marshaller marshaller = context.createMarshaller();
final CmsContent content = createCmsContent();
marshaller.marshal(content, System.out);
Известное исключение:
The java interface com.core.domain.ContentItemGroup can not be mapped by JAXB as it has multiple mappable parent interfaces. Multiple inheritence is not supported
Примечание: приведенный ниже пример @Blaise работает хорошо, спасибо за это, но этот пример не имеет нескольких родительских классов, как в моем случае, что вызывает исключение, даже в bind xml я использую атрибут super-type.
После отладки кода Moxy исключение возникает, когда класс Moxy "AnnotationsProcessor" проверяет все свойства CmsContent и пытается выяснить, является ли свойство ContentItemGroup в CmsContent Collection, метод: Helper.isCollectionType(..).
В методе Moxy JavaClassImpl.getSuperclass(..) он будет проходить через все родительские классы свойства интерфейса ContentItemGroup и будет терпеть неудачу, потому что родительский класс не запускается с "java" или "javax". Примечание. Интерфейс ContentItemGroup расширяет два интерфейса.
Почему он терпит неудачу и не использует ли он определенный супер-тип в привязке xml?
Он работает в случае, если ContentItemGroup не распространяется на какой-либо интерфейс или в случае, если он распространяется из одного интерфейса (который также учитывает все расширения родительских интерфейсов). В этом случае он успешно пройдет метод ниже. Однако удаление родительских интерфейсов не является вариантом :(
Другая проблема: BTW: когда она работает, как выводить свойства из родительского класса ContentItemGroupDefault в качестве атрибута xml? В приведенном выше примере "id" из родительского класса не отображается в xml. В случае, если я удаляю атрибут "супертипа", все свойства родительского класса появляются на выходе, даже когда я отмечаю их как "переходный". Что я делаю не так?
Метод JavaClassImpl.getSuperclass(..):
public JavaClass getSuperclass() {
if(this.superClassOverride != null) {
return this.superClassOverride;
}
if(jClass.isInterface()) {
Class[] superInterfaces = jClass.getInterfaces();
if(superInterfaces != null) {
if(superInterfaces.length == 1) {
return javaModelImpl.getClass(superInterfaces[0]);
} else {
Class parent = null;
for(Class next:superInterfaces) {
if(!(next.getName().startsWith("java.") || next.getName().startsWith("javax."))) {
if(parent == null) {
parent = next;
} else {
throw JAXBException.invalidInterface(jClass.getName());
}
}
}
return javaModelImpl.getClass(parent);
}
}
}
return javaModelImpl.getClass(jClass.getSuperclass());
}
ОБНОВИТЬ:
@BLAISE: <java-type name="AbstractCmsContent" xml-transient="true">
При изменении привязки xml ContentItemGroupDefault к (добавление xml-переходного процесса):
<java-type name="ContentItemGroupDefault" super-type="java.lang.Object" xml-accessor-type="NONE" xml-transient="true">
Я получаю следующее исключение:
Exception Description: A descriptor for class com.core.cms.moxy.ContentItemGroupDefault was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.
Который я не понимаю. Также при добавлении ContentItemGroupDefault в JAXContent эффект не имеет. При добавлении свойства "xml-transient" в сопоставление CmsContent, это приведет к тому же исключению, но затем приведет к классу CmsContent.
ОБНОВЛЕНИЕ: Тем временем я исправил его, используя Woodstox напрямую, что обошлось мне около 4 часов, включая тестирование. После дней разочарования я, похоже, не получаю Moxy для выполнения простого сопоставления. Даже если я ошибаюсь, я думаю, что Moxy может быть более дружественным/доступным для этих простых простых мета-отображений. При добавлении нескольких интерфейсов к интерфейсу PhoneNumber для @Blaise, приведенному ниже, я получаю ту же ошибку "Поддержка нескольких интерфейсов". Я хотел использовать Moxy, поскольку я использую его в других местах платформы, что касается тысяч сгенерированных классов jaxb, которые хорошо работают. Тем не менее, простой случай отображения кажется трудным.. :(
Когда у вас есть интерфейс с фронтальной моделью, это действительно классы реализации, которые вы сопоставляете. Ниже приведена ссылка на пример, который я демонстрирую, как это делается с аннотациями.
Для этого связанного примера ниже будет соответствующий документ сопоставления:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="blog.interfaces">
<java-types>
<java-type name="CustomerImpl">
<xml-root-element name="customer"/>
<java-attributes>
<xml-element java-attribute="address" type="blog.interfaces.AddressImpl"/>
<xml-element java-attribute="phoneNumbers" name="phone-number" type="blog.interfaces.PhoneNumberImpl"/>
</java-attributes>
</java-type>
<java-type name="PhoneNumberImpl">
<java-attributes>
<xml-value java-attribute="value"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Спасибо @Blaise. С вашей обратной связью я снова изолировал проблему и обновил приведенный выше пример кода. Moxy не любит несколько родительских интерфейсов (ваш пример кода отлично работает, но не имеет нескольких интерфейсов)... Пожалуйста, обратная связь?
Проблема с несколькими родительскими интерфейсами должна возникать только в том случае, если вы пытаетесь обрабатывать интерфейс как отображаемую вещь. Моя рекомендация заключалась бы в том, чтобы не делать этого. Есть ли где-нибудь, что вы не переопределили свойство как фактический тип реализации?
Я не смог воспроизвести ошибку, которую вы видите. Следует отметить, однако, что когда вы делаете следующее, вы действительно говорите MOXy, что суперкласс этого класса - Object
. Что касается MOXy, это не будет обрабатывать настоящий суперкласс CmsContent
.
<java-type name="CmsContent" super-type="java.lang.Object" xml-accessor-type="NONE" >
Если вы просто хотите рассматривать суперкласс CmsContent
как просто неотображаемый и иметь свойства, которые рассматриваются как свойства подклассов, тогда вы должны отметить этот класс как @XmlTransient
. Это делается в метаданных XML, таких как:
<java-type name="AbstractCmsContent" xml-transient="true">