简体   繁体   中英

JAXB and Inheritance with external custom bindings

I'm currently trying to model the Spring LDAP Filters in my XML schema. This involves polymorphic types, which can be arbitrarily nested:

<andFilter>
  <notFilter>
     <equalsFilter name="mail" value="asfd@example.com" />
  </notFilter>
  <likeFilter name="mail" value="asdf*" />
</andFilter>

This is how I'm defining the above filters in my xsd (I actually have some intermediate abstract types defined, but left them out for simplicity):

<xsd:complexType name="baseFilterType" abstract="true" />
<xsd:element name="filter" type="tns:baseFilterType" />

<xsd:complexType name="andFilterType">
  <xsd:sequence>
    <xsd:element ref="tns:filter" minOccurs="1" maxOccurs="unbounded" />
  </xsd:sequence>
</xsd:complexType>
<xsd:element name="andFilter" type="tns:andFilterType" substitutionGroup="tns:filter" />

<xsd:complexType name="notFilterType">
  <xsd:sequence>
    <xsd:element ref="tns:filter" />
  </xsd:sequence>
</xsd:complexType>
<xsd:element name="notFilter" type="tns:notFilterType" substitutionGroup="tns:filter" />

<xsd:complexType name="likeFilterType">
  <xsd:sequence>
    <xsd:element ref="tns:attributeName" />
    <xsd:element ref="tns:value" />
  </xsd:sequence>
</xsd:complexType>
<xsd:element name="likeFilter" type="tns:likeFilterType" substitutionGroup="tns:filter" />

<xsd:complexType name="equalsFilterType">
  <xsd:sequence>
    <xsd:element ref="tns:attributeName" />
    <xsd:element ref="tns:value" />
  </xsd:sequence>
</xsd:complexType>
<xsd:element name="equalsFilter" type="tns:equalsFilterType" substitutionGroup="tns:filter" />

I've extended each of the filter classes with some custom behavior (to implement the visitor pattern), but I can't figure out how to have JAXB bind to those instead of JAXBElement<? extends BaseFilterType> JAXBElement<? extends BaseFilterType> that's used throughout the generated classes.

The JAXB model classes are generated at build time, and so I can't modify them directly -- I must use external custom bindings for any customizations . I've tried the implClass and baseClass customizations but haven't been able to figure out how to do it.

Can anyone help?

Edit: I'm using Spring's Jaxb2Marshaller with contextPaths set for marshalling and unmarshalling. I expected this to utilize ObjectFactory for object instantiation, but that doesn't seem to be the case.

Edit 2: The filter elements are referenced by the top-level element as well as by each other, like:

<xsd:element name="GetAttributesRequest">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element ref="filter:filter" />
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

So, the GetAttributesRequest object will be marked with @XmlRootElement while the filter classes themselves will not be. However, even the top-level GetAttributesRequest object isn't being instantiated by ObjectFactory ...

Edit :

Solution used by question author :

I ended up using JAXB binding customizations to make the ObjectFactory produce instances of my classes, and then set the com.sun.xml.internal.bind.ObjectFactory (note the internal) unmarshaller property on Spring's Jaxb2Marshaller to force it to use the factory.


Original answer :

Yes, it's possible to add behaviors to the generated classes. You want to have a look at the related documentation

Here's a simple example from the documentation :

JAXB Generated Code

package org.acme.foo;

@XmlRootElement
class Person {
  private String name;

  public String getName() { return name; }
  public void setName(String) { this.name=name; }
}

@XmlRegistry
class ObjectFactory {
  Person createPerson() { ... }
}

Extended class

package org.acme.foo.impl;

class PersonEx extends Person {
  @Override
  public void setName(String name) {
    if(name.length()<3) throw new IllegalArgumentException();
    super.setName(name);
  }
}

@XmlRegistry
class ObjectFactoryEx extends ObjectFactory {
  @Override
  Person createPerson() {
    return new PersonEx();
  }
}

Example of Unmarshalling

Unmarshaller u = context.createUnmarshaller();
u.setProperty("com.sun.xml.bind.ObjectFactory",new ObjectFactoryEx());
PersonEx p = (PersonEx)u.unmarshal(new StringReader("<person />"));

More info here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM