1

我按照MOXY中的 JAXB 继承中提到的第二个选项来映射下面列出的父类和子类。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 中元素的顺序之外,它工作正常。我相信这是代码中的错误。

4

2 回答 2

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而不是相应的设置器。因此,将Annotationprocessor其指定为瞬态属性,忽略了此方法被覆盖的事实。

使固定

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

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;
        }
    }
于 2012-08-10T18:47:17.410 回答
0

即使您已标记UnitedStatesAddressData@XmlTransient(使用 MOXy 的外部映射文档),它的超类AbstractAddress仍然是映射类。AbstractAddress因此,无法在propOrder设置中指定from 的此类属性TokenizedUnitedStatesAddressData。解决方案也是制作AbstractAddress @XmlTransient

使固定

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

<?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-type name="AbstractAddress" xml-transient="true">
         <xml-root-element />
      </java-type>
   </java-types>
</xml-bindings>

了解更多信息

于 2012-08-10T19:56:43.150 回答