Wolfgang Fahl
Wolfgang Fahl

Reputation: 15769

EclipseLink error 50035 when using XmlIDREF/XmlID with interfaces and generalization

I am trying out the @XmlIDREF reference approach. The annotation is:

 /**
   * getter for Attribute/List<Attribute> attributes
   * @return attributes
   */
  @XmlElementWrapper(name="attributes")
  @XmlElements({
    @XmlElement(name="Attribute", type=AttributeJaxbDao.class)
  })
  @XmlIDREF
  public List<Attribute> getAttributes() { 

which leads to the error message:

javax.xml.bind.JAXBException: 
Exception Description: Since the property or field [attributes] is set as XmlIDREF, the target type of each XmlElement declared within the XmlElements list must have an XmlID property.  Please ensure the target type of XmlElement [Attribute] contains an XmlID property.
 - with linked exception:
[Exception [EclipseLink-50035] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.JAXBException
Exception Description: Since the property or field [attributes] is set as XmlIDREF, the target type of each XmlElement declared within the XmlElements list must have an XmlID property.  Please ensure the target type of XmlElement [Attribute] contains an XmlID property.]
    at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:832)
    at org.eclipse.persistence.jaxb.JAXBContext.<init>(JAXBContext.java:143)

although AttributeJaxbDao has the annotation:

 /**
   * getter for xsd:string/String id
   * @return id
   */
  @XmlAttribute(name="id")  
  @XmlID
  public String getId() { 

There are two differences to the "standard use" @XmlIDREF/@XmlID:

  1. AttributeJaxbDao is a derived class - the annotation is in the superclass
  2. Attribute is an Interface - the type has specifically been named to be AttributeJaxbDao.class in the @XmlElement annotation

How come the error shows up in this situation? Would there be a work around for this. I'd like to avoid to be forced to not use the interface and the generalization.

Upvotes: 1

Views: 367

Answers (1)

bdoughan
bdoughan

Reputation: 148977

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

There were unfortunately 2 bugs that we preventing this use case from working correctly.

These bugs have been fixed in the EclipseLink 2.4.2 and 2.5.0 streams. These streams are currently in development, a nightly build can be downloaded from the following link (starting Feb 22, 2013):


FULL EXAMPLE

Below is a slightly more complicated model than the one given in your question that I'm going to use to demonstrate that everything now works correctly.

Foo

The Foo class has two properties of type List<Attribute>, Attribute is an interface. Both are annotated with @XmlElements which contain @XmlElement annotations that specify the concrete types. The attributeRefs property is also annotated with @XmlIDREF.

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Foo {

    @XmlElementWrapper(name="Attributes")
    @XmlElements({
        @XmlElement(name="AttributeFoo", type=AttributeJaxbDao.class),
        @XmlElement(name="AttributeBar", type=AttributeJaxbDao2.class)
      })
    List<Attribute> attributes = new ArrayList<Attribute>();;


    @XmlElementWrapper(name="AttributeRefs")
    @XmlElements({
      @XmlElement(name="AttributeRefFoo", type=AttributeJaxbDao.class),
      @XmlElement(name="AttributeRefBar", type=AttributeJaxbDao2.class)
    })
    @XmlIDREF
    List<Attribute> attributeRefs = new ArrayList<Attribute>();

}

Attribute

Attribute is just a very simple interface.

public interface Attribute {

}

AttributeJaxbDao

This is an implementation of Attribute that contains a field annotated with @XmlID that will be leveraged by the @XmlIDREF annotation.

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class AttributeJaxbDao implements Attribute {

    @XmlAttribute(name="id")  
    @XmlID
    String id;

    String name;

}

AttributeJaxbDao2

This is also an implementation of Attribute that has a field annotated with @XmlID.

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class AttributeJaxbDao2 implements Attribute {

    @XmlAttribute(name="id")  
    @XmlID
    String id;

    String name;

}

Demo

Below is some demo code that you can run to prove that everything works:

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Foo.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum14921547/input.xml");
        Foo foo = (Foo) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(foo, System.out);
    }

}

input.xml/Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo>
    <Attributes>
        <AttributeFoo id="a">
            <name>A</name>
        </AttributeFoo>
        <AttributeBar id="b">
            <name>B</name>
        </AttributeBar>
        <AttributeFoo id="c">
            <name>C</name>
        </AttributeFoo>
    </Attributes>
    <AttributeRefs>
        <AttributeRefFoo>a</AttributeRefFoo>
        <AttributeRefBar>b</AttributeRefBar>
        <AttributeRefFoo>c</AttributeRefFoo>
    </AttributeRefs>
</foo>

Upvotes: 2

Related Questions