使用MOXy抛出异常的继承映射

时间:2012-08-10 16:00:56

标签: jaxb eclipselink jaxb2 moxy

我按照JAXB inheritance in MOXY中提到的第二个选项来映射下面列出的父类和子类。 MOXy抛出以下异常而不确定问题是什么

家长班

public class UnitedStatesAddressData extends AbstractAddress implements UnitedStatesAddress, Serializable, Cloneable
{
    private String primaryAddress;

    public String getPrimaryAddress()
    {
        return primaryAddress;
    }

    public void setPrimaryAddress(final String primaryAddress)
    {
        this.primaryAddress = primaryAddress;
    }
}

儿童班

public class TokenizedUnitedStatesAddressData extends UnitedStatesAddressData implements TokenizedUnitedStatesAddress,
        CloneableAddress
{
    private String houseNumber;

    private String preDirectional;

    private String streetName;

    private String streetType;

//getters and setters ignored
}

外部绑定文件

<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.eclipse.org/eclipselink/xsds/persistence/oxm http://www.eclipse.org/eclipselink/xsds/eclipselink_oxm_2_4.xsd"
   version="2.4" package-name="com.abc.ic.domain.impl.country.us" xml-accessor-type="PROPERTY">
   <xml-schema element-form-default="QUALIFIED" namespace="http://xml.abc.com/XMLSchema/InterConnect">
      <!-- Do not specify 'prefix'. We doesn't want the namespace prefix in our instance documents as they increase the payload size. -->
      <xml-ns namespace-uri="http://xml.abc.com/XMLSchema/InterConnect" />
   </xml-schema>
   <java-types>
      <java-type name="TokenizedUnitedStatesAddressData">
         <xml-root-element name="USAddress" />
         <xml-type prop-order="preDirectional houseNumber streetName streetType postDirection unitDesignator apartmentNumber primaryAddress secondaryAddress cityName stateAbbreviation zipCode" />
         <java-attributes>
            <xml-element name="StreetPreDirection" java-attribute="preDirectional" />
            <xml-element name="StreetNumber" java-attribute="houseNumber" />
            <xml-element name="StreetName" java-attribute="streetName" />
            <xml-element name="StreetType" java-attribute="streetType" />
            <xml-element name="StreetPostDirection" java-attribute="postDirection" />
            <xml-element name="UnitDesignator" java-attribute="unitDesignator" />
            <xml-element name="UnitNumber" java-attribute="apartmentNumber" />
            <xml-element name="AddressLine1" java-attribute="primaryAddress" />
            <xml-element name="AddressLine2" java-attribute="secondaryAddress" />
            <xml-element name="City" java-attribute="cityName" />
            <xml-element name="State" java-attribute="stateAbbreviation" />
            <xml-element name="PostalCode" java-attribute="zipCode" />
         </java-attributes>
      </java-type>
      <java-type name="UnitedStatesAddressData" xml-transient="true">
         <xml-root-element />
      </java-type>
   </java-types>
</xml-bindings>

错误

javax.xml.bind.JAXBException: 
Exception Description: The property or field primaryAddress is annotated to be transient so can not be included in the proporder annotation.
 - with linked exception:
[Exception [EclipseLink-50009] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.JAXBException
Exception Description: The property or field primaryAddress is annotated to be transient so can not be included in the proporder annotation.]
    at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:908)
    at org.eclipse.persistence.jaxb.JAXBContext.<init>(JAXBContext.java:157)
    at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:170)
    at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:157)
    at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:117)
    at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:107)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:202)
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:331)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
    at com.abc.ic.platform.sts.domain.transformation.response.JaxbTest.beforeClass(JaxbTest.java:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: Exception [EclipseLink-50009] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.JAXBException
Exception Description: The property or field primaryAddress is annotated to be transient so can not be included in the proporder annotation.
    at org.eclipse.persistence.exceptions.JAXBException.transientInProporder(JAXBException.java:225)
    at org.eclipse.persistence.jaxb.compiler.TypeInfo.setProperties(TypeInfo.java:342)
    at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.buildTypeInfo(AnnotationsProcessor.java:755)
    at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.postBuildTypeInfo(AnnotationsProcessor.java:669)
    at org.eclipse.persistence.jaxb.compiler.XMLProcessor.processXML(XMLProcessor.java:344)
    at org.eclipse.persistence.jaxb.compiler.Generator.<init>(Generator.java:145)
    at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:904)
    ... 28 more

更新

我已经通过删除“prop-order”测试了这个,这很好用,除了我不能再控制生成的XML中元素的顺序。我相信这是代码中的一个错误。

2 个答案:

答案 0 :(得分:1)

原因是子类会覆盖父类中的方法,如下所示,但由于父类已被定义为xml-transient =“true”,因此TypeInfo中的以下检查失败。

子类重写getPrimaryAddress

public class TokenizedUnitedStatesAddressData extends UnitedStatesAddressData implements TokenizedUnitedStatesAddress,
        CloneableAddress
{
@override
public String getPrimaryAddress()
{
   return primaryAddress;
}
}

TypeInfo.java违规代码

if (p.isTransient() && propOrderList.contains(p.getPropertyName()))
{
throw org.eclipse.persistence.exceptions.JAXBException.transientInProporder(p.getPropertyName());
}

更新2

问题不在于AbstractAddress。经过一些调试后,问题似乎与AnnotationProcessor.getPropertyPropertiesForClass(final JavaClass cls, final TypeInfo info, final boolean onlyPublic, final boolean onlyExplicit)

中的以下逻辑有关
if ((setMethod == null) && !(hasJAXBAnnotations(getMethod)))
{
    // if there's no corresponding setter, and not explicitly
    // annotated, don't process
    isPropertyTransient = true;
}

此方法将标记任何没有两者定义为“瞬态”的get / set方法的方法。在我的例子中,我只覆盖getPrimaryAddress()类中的TokenizedUnitedStatesAddressData方法而不是相应的setter。因此Annotationprocessor将其指定为瞬态属性,而忽略了此方法被覆盖的事实。

<强> FIX

在确保在瞬态检查中正确处理被覆盖的方法后,问题得到解决,如下所示

if ((setMethod == null) && !(hasJAXBAnnotations(getMethod)))
{
    if (!isMethodOverrriden(cls.getQualifiedName(), getMethod.getName()))
    {
        // if there's no corresponding setter, and not explicitly
        // annotated, don't process
        isPropertyTransient = true;
    }
}

public static boolean isMethodOverrriden(final String classQualifiedName, final String methodName)
    {
        Method myMethod;
        try
        {
            myMethod = Class.forName(classQualifiedName).getMethod(methodName, null);
        }
        catch (Exception e1)
        {
            return false;
        }

        Class<?> declaringClass = myMethod.getDeclaringClass();
        if (declaringClass.equals(Object.class))
        {
            return false;
        }

        Class<?> superclass = declaringClass.getSuperclass();
        if (superclass == null)
        {
            return false;
        }
        else
        {
            try
            {
                superclass.getMethod(myMethod.getName(), myMethod.getParameterTypes());
            }
            catch (NoSuchMethodException e)
            {
                // recursively check all super classes
                isMethodOverrriden(superclass.getName(), methodName);
            }
            return true;
        }
    }

答案 1 :(得分:0)

即使您已将UnitedStatesAddressData标记为@XmlTransient(使用MOXy的外部映射文档),它的超类AbstractAddress仍然是映射类。由于无法在AbstractAddress的{​​{1}}设置中指定来自propOrder的此类属性。解决方案也是TokenizedUnitedStatesAddressData AbstractAddress

<强>修正

我已经修改了您的映射文档以执行此操作,假设@XmlTransient类与您的域模型的其余部分位于同一个包中。

AbstractAddress

了解更多信息