Inheritance mapping throwing an exception with MOXy

℡╲_俬逩灬. 提交于 2019-12-12 23:52:49

问题


I followed the second option mentioned in JAXB inheritance in MOXY to map my parent class and child class listed below. MOXy is throwing the below exception and not sure what the issue is

Parent class

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;
    }
}

Child Class

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

    private String preDirectional;

    private String streetName;

    private String streetType;

//getters and setters ignored
}

external binding file

<?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>

Error

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

UPDATE

I've tested this by removing "prop-order" and this works fine except that I can no longer control the order of the elements in generated XML. I believe this is a bug in the code.


回答1:


The cause for this is that the child class overrides the method from parent class as sown below but since the parent class has been defined to be xml-transient="true", the below check from TypeInfo is failing.

child class overriding getPrimaryAddress

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

TypeInfo.java offending code

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

UPDATE 2

The issue is not with the AbstractAddress. After some debugging, the issue seems to be with the below logic in the 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;
}

This method will tag any method that doesn't have both the get/set methods defined as "transient". In my case, I override just the getPrimaryAddress() method in TokenizedUnitedStatesAddressData class and not the corresponding setter. And hence the Annotationprocessor is designating it as a transient property neglecting the fact that this method is being overridden.

FIX

The issue is fixed after making sure that the overridden methods are properly handled in the transient check as shown below

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;
        }
    }



回答2:


Even though you have marked UnitedStatesAddressData as @XmlTransient (using MOXy's external mapping document), it's super class AbstractAddress is still a mapped class. As such properties from AbstractAddress can not be specified in the propOrder setting for TokenizedUnitedStatesAddressData. The solution will be to make AbstractAddress @XmlTransient as well.

Fix

I have modified your mapping document to do this below assuming that the AbstractAddress class is in the same package as the rest of your domain model.

<?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>

For More Information

  • http://blog.bdoughan.com/2012/08/jaxbs-xmltransient-and-property-order.html


来源:https://stackoverflow.com/questions/11905298/inheritance-mapping-throwing-an-exception-with-moxy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!