【问题标题】:Interface mapping with Moxy in a binding.xml not working with multiple interfaces?binding.xml 中与 Moxy 的接口映射不能与多个接口一起使用?
【发布时间】:2014-12-08 17:35:51
【问题描述】:

我正在尝试使用 Moxy v2.5.2 binding.xml 映射一个类作为注释的替代方案,因为我无法将注释放在第三方父类中。

编辑:根据 Blaise 的反馈,我在下面修改了这部分

由于父接口,我似乎无法映射接口。

java代码sn-p:

    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 下面的示例运行良好,谢谢,但该示例没有像我这样的多个父类,这会导致异常,即使在绑定 xml 中我也使用了 super-type 属性.

调试 Moxy 代码后,当 Moxy 类“AnnotationsProcessor”扫描 CmsContent 的所有属性并尝试发现 CmsContent 中的属性 ContentItemGroup 是否为 Collection 时,会发生异常,方法:Helper.isCollectionType(..)。

在 Moxy 方法 JavaClassImpl.getSuperclass(..) 中,它将遍历接口 ContentItemGroup 属性的所有父类,并且将失败,因为父类不是以“java”或“javax”开头的。 注意:接口 ContentItemGroup 扩展了 2 个接口。

为什么会失败并且不使用绑定xml中定义的超类型?

它适用于 ContentItemGroup 不从任何接口扩展或从单个接口扩展的情况(这也适用于所有扩展父接口)。在这种情况下,它将成功通过以下方法。 但是,删除父接口不是一种选择:(

其他问题: 顺便说一句:当它工作时,如何将 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-transient)时:

<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 可以变得更加友好/可访问。 当向@Blaise 的PhoneNumber 接口添加多个接口时,它是下面的示例,我确实得到了相同的“多接口支持”错误。 我想使用 Moxy,因为我在平台的其他地方使用它,这些地方涉及到数千个运行良好的生成的 jaxb 类。然而,一个简单的映射案例似乎很难.. :(

【问题讨论】:

    标签: java jaxb moxy


    【解决方案1】:

    当您有一个接口前端模型时,它实际上是您正在映射的支持实现类。下面是一个指向我的示例的链接,该示例演示了如何使用注释完成此操作。

    对于下面的链接示例将是相应的映射文档:

    <?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 不喜欢多父母 接口(您的代码示例工作正常,但没有多个 接口)...请反馈?

    只有当您尝试将接口视为映射事物时,才会出现多父接口问题。我的建议是不要这样做。是否有任何地方没有将 a 属性覆盖为实际的实现类型?

    我无法重现您看到的错误。不过要注意的一件事是,当您执行以下操作时,您实际上是在告诉 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">
    

    【讨论】:

    • 谢谢,已经试过了,但是没有用,导致我上面描述的问题(3),即:定义“”导致“无法加载类”moxy 错误(包名正确)。如何解决?将实现类添加到上下文中也没有效果:(我知道您的博客文章(在您的许多其他文章之前使用过它;),谢谢。
    • 刚刚做了一个小测试:将所有类放在一个包中(impl),然后我认为它可以找到类 ContentItemGroupDefault (闻起来像一个错误?),但确实得到另一个错误,即ContentItemGroup(接口)不能被映射,因为它有多个接口。当方法“AnnotationsProcessor.processPropertyAnnotations”正在处理 CmsContent 类的属性时会发生这种情况。奇怪的是 ContentItemGroup 的类型是定义的(见上文),就像您在示例中为 phoneNumbers 所做的那样。有什么想法吗?
    • @edbras - 映射文档是基于打包的,因此如果您的域模型拆分为多个包,那么您将需要多个映射文档。
    • 我(已经)通过将它放在一个包中解决了这个问题,但是如何解决我上一条评论中描述的错误(3)?
    • @edbras - 这些属性是从超类型继承的?
    猜你喜欢
    • 1970-01-01
    • 2012-08-31
    • 1970-01-01
    • 1970-01-01
    • 2017-04-16
    • 1970-01-01
    • 2017-05-29
    • 2014-07-04
    • 2017-12-11
    相关资源
    最近更新 更多