Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "User:Rick.barkhouse.oracle.com/Test1"

Line 77: Line 77:
  
 
Next, we define our virtual mappings in an EclipseLink OXM file.  Any property encountered in this file that does not have a corresponding Java attribute will be considered a virtual property and will be accessed through the virtual access methods.
 
Next, we define our virtual mappings in an EclipseLink OXM file.  Any property encountered in this file that does not have a corresponding Java attribute will be considered a virtual property and will be accessed through the virtual access methods.
 +
 +
 +
== Config Options ==
 +
 +
 +
=== Specifying Alternate Accessor Methods ===
 +
 +
To use different method names as your extensions accessors, specify them using the <tt>getMethodName</tt> and <tt>setMethodName</tt> attributes on <tt>@XmlExtensible</tt>:
 +
 +
<div style="width:700px">
 +
<source lang="java">
 +
@XmlRootElement
 +
@XmlVirtualAccessMethods(getMethod = "getCustomProps", setMethod = "putCustomProps")
 +
@XmlAccessorType(AccessType.FIELD)
 +
public class Customer {
 +
 +
  @XmlAttribute
 +
  private int id;
 +
 +
  private String name;
 +
 +
  @XmlTransient
 +
  private Map<String, Object> extensions;
 +
 +
  public Object getCustomProps(String name) {
 +
      if (extensions == null) {
 +
        extensions = new HashMap<String, Object>();
 +
      }
 +
      return extensions.get(name);
 +
  }
 +
 +
  public void putCustomProps(String name, Object value) {
 +
      if (extensions == null) {
 +
        extensions = new HashMap<String, Object>();
 +
      }
 +
      extensions.put(name, value);
 +
  }
 +
 +
}
 +
</source>
 +
</div>
 +
 +
In OXM:
 +
 +
<div style="width:800px">
 +
<source lang="xml">
 +
...
 +
<java-types>
 +
  <java-type name="Customer">
 +
      <xml-virtual-access-methods get-method="getCustomProps" set-method="putCustomProps" />
 +
      <java-attributes>
 +
        <xml-attribute java-attribute="id" type="java.lang.Integer" />
 +
        <xml-element java-attribute="name" type="java.lang.String" />
 +
      </java-attributes>
 +
  </java-type>
 +
...
 +
</source>
 +
</div>
 +
 +
 +
=== Schema Generation Options ===
 +
 +
If the user generates an XML Schema from the <tt>JAXBContext</tt> after virtual properties have been added, then the resulting schema will obviously be different from any Schema that may have been used to generate the initial domain objects.
 +
 +
To configure how these new properties should appear in future generated schemas, use the <tt>schema</tt> attribute on <tt>@XmlVirtualAccessMethods</tt>.
 +
 +
 +
'''Virtual Properties as individual Nodes'''
 +
 +
This is EclipseLink's default behaviour, or can be specified explicitly as an override as follows:
 +
 +
<div style="width:700px">
 +
<source lang="java">
 +
@XmlRootElement
 +
@XmlVirtualAccessMethods(schema = XmlVirtualAccessMethodsSchema.NODES)
 +
@XmlAccessorType(AccessType.FIELD)
 +
public class Customer {
 +
 +
  ...
 +
</source>
 +
</div>
 +
 +
For example:
 +
 +
Original <tt>Customer</tt> Schema:
 +
 +
<div style="width:700px">
 +
<source lang="xml">
 +
<xs:schema ...>
 +
 +
    <xs:element name="customer">
 +
        <xs:complexType>
 +
            <xs:sequence>
 +
                <xs:element name="first-name" type="xs:string" />
 +
                <xs:element name="last-name" type="xs:string" />
 +
            </xs:sequence>
 +
        </xs:complexType>
 +
    </xs:element>
 +
 +
</xs:schema>
 +
</source>
 +
</div>
 +
 +
Generated Schema after adding <tt>middle-initial</tt> and <tt>phone-number</tt>:
 +
 +
<div style="width:700px">
 +
<source lang="xml">
 +
<xs:schema ...>
 +
 +
    <xs:element name="customer">
 +
        <xs:complexType>
 +
            <xs:sequence>
 +
                <xs:element name="first-name" type="xs:string" />
 +
                <xs:element name="last-name" type="xs:string" />
 +
                <xs:element name="middle-initial" type="xs:string" />
 +
                <xs:element name="phone-number" type="xs:string" />
 +
            </xs:sequence>
 +
        </xs:complexType>
 +
    </xs:element>
 +
 +
</xs:schema>
 +
</source>
 +
</div>
 +
 +
 +
'''Virtual Properties in an <any> Element'''
 +
 +
EclipseLink can also use an <tt><any></tt> element to hold all of the virtual properties in one node:
 +
 +
<div style="width:700px">
 +
<source lang="java">
 +
@XmlRootElement
 +
@XmlVirtualAccessMethods(schema = XmlVirtualAccessMethodsSchema.ANY)
 +
@XmlAccessorType(AccessType.FIELD)
 +
public class Customer {
 +
 +
  ...
 +
</source>
 +
</div>
 +
 +
Taking the example from above, a newly generated schema using this approach would look like:
 +
 +
<div style="width:700px">
 +
<source lang="xml">
 +
<xs:schema ...>
 +
 +
    <xs:element name="customer">
 +
        <xs:complexType>
 +
            <xs:sequence>
 +
                <xs:element name="first-name" type="xs:string" />
 +
                <xs:element name="last-name" type="xs:string" />
 +
                <xs:any minOccurs="0" />
 +
            </xs:sequence>
 +
        </xs:complexType>
 +
    </xs:element>
 +
 +
</xs:schema>
 +
</source>
 +
</div>
  
  

Revision as of 11:07, 21 June 2011

EclipseLink MOXy

Eclipselink-logo.gif
EclipseLink
Website
Download
Community
Mailing ListForumsIRCmattermost
Issues
OpenHelp WantedBug Day
Contribute
Browse Source

Virtual Access Methods

In addition to the standard JAXB access methods (public member, field, property, etc.), EclipseLink MOXy 2.3 introduces the concept of virtual properties and virtual access methods, which instead rely on special get() and set() methods to maintain mapping data. For example, you might want to use a HashMap as the underlying structure to hold data for certain mappings. The mappings that use virtual method access must be defined in EclipseLink OXM metadata.

In order to add virtual properties to an entity:

  • the Java class must be marked with an @XmlVirtualAccessMethods annotation, or <xml-virtual-access-methods> element in OXM
  • the Java class must contain getter and setter methods to access virtual property values
    • public Object get(String propertyName)
    • public void set(String propertyName, Object value)
    • method names are configurable but must have the same method signatures as above


Idea.png
By default, EclipseLink will look for methods named "set" and "get". To customize accessor method names, see Specifying Alternate Accessor Methods.


Example

For this example we will use the following Employee class. In addition to some conventional JAXB mappings, we also specify that this class contains virtual access methods by including the @XmlVirtualAccessMethods annotation.

Using Annotations

@XmlRootElement
@XmlVirtualAccessMethods
@XmlAccessorType(AccessType.PROPERTY)
public class Customer {
 
   private int id;
 
   private String name;
 
   private Map<String, Object> extensions = new HashMap<String, Object>();
 
   public Object get(String name) {
      return extensions.get(name);
   }
 
   public void set(String name, Object value) {
      extensions.put(name, value);
   }
 
   @XmlAttribute
   public int getId() {
   ...
 
}

Using EclipseLink OXM

Virtual Access Methods can be specified in OXM as follows:

...
<java-types>
   <java-type name="Customer">
      <xml-virtual-access-methods />
      <java-attributes>
         <xml-attribute java-attribute="id" type="java.lang.Integer" />
         <xml-element java-attribute="name" type="java.lang.String" />
      </java-attributes>
   </java-type>
...

Next, we define our virtual mappings in an EclipseLink OXM file. Any property encountered in this file that does not have a corresponding Java attribute will be considered a virtual property and will be accessed through the virtual access methods.


Config Options

Specifying Alternate Accessor Methods

To use different method names as your extensions accessors, specify them using the getMethodName and setMethodName attributes on @XmlExtensible:

@XmlRootElement
@XmlVirtualAccessMethods(getMethod = "getCustomProps", setMethod = "putCustomProps")
@XmlAccessorType(AccessType.FIELD)
public class Customer {
 
   @XmlAttribute
   private int id;
 
   private String name;
 
   @XmlTransient
   private Map<String, Object> extensions;
 
   public Object getCustomProps(String name) {
      if (extensions == null) {
         extensions = new HashMap<String, Object>();
      }
      return extensions.get(name);
   }
 
   public void putCustomProps(String name, Object value) {
      if (extensions == null) {
         extensions = new HashMap<String, Object>();
      }
      extensions.put(name, value);
   }
 
}

In OXM:

...
<java-types>
   <java-type name="Customer">
      <xml-virtual-access-methods get-method="getCustomProps" set-method="putCustomProps" />
      <java-attributes>
         <xml-attribute java-attribute="id" type="java.lang.Integer" />
         <xml-element java-attribute="name" type="java.lang.String" />
      </java-attributes>
   </java-type>
...


Schema Generation Options

If the user generates an XML Schema from the JAXBContext after virtual properties have been added, then the resulting schema will obviously be different from any Schema that may have been used to generate the initial domain objects.

To configure how these new properties should appear in future generated schemas, use the schema attribute on @XmlVirtualAccessMethods.


Virtual Properties as individual Nodes

This is EclipseLink's default behaviour, or can be specified explicitly as an override as follows:

@XmlRootElement
@XmlVirtualAccessMethods(schema = XmlVirtualAccessMethodsSchema.NODES)
@XmlAccessorType(AccessType.FIELD)
public class Customer {
 
   ...

For example:

Original Customer Schema:

<xs:schema ...>
 
    <xs:element name="customer">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="first-name" type="xs:string" />
                <xs:element name="last-name" type="xs:string" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
 
</xs:schema>

Generated Schema after adding middle-initial and phone-number:

<xs:schema ...>
 
    <xs:element name="customer">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="first-name" type="xs:string" />
                <xs:element name="last-name" type="xs:string" />
                <xs:element name="middle-initial" type="xs:string" />
                <xs:element name="phone-number" type="xs:string" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
 
</xs:schema>


Virtual Properties in an <any> Element

EclipseLink can also use an <any> element to hold all of the virtual properties in one node:

@XmlRootElement
@XmlVirtualAccessMethods(schema = XmlVirtualAccessMethodsSchema.ANY)
@XmlAccessorType(AccessType.FIELD)
public class Customer {
 
   ...

Taking the example from above, a newly generated schema using this approach would look like:

<xs:schema ...>
 
    <xs:element name="customer">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="first-name" type="xs:string" />
                <xs:element name="last-name" type="xs:string" />
                <xs:any minOccurs="0" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
 
</xs:schema>


XmlAccessorType and XmlTransient

If you are using an @XmlAccessorType other than AccessType.PROPERTY, you will need to mark your virtual properties Map attribute to be @XmlTransient, to prevent the Map itself from being bound to XML.

@XmlRootElement
@XmlVirtualAccessMethods
@XmlAccessorType(AccessType.FIELD)
public class Customer {
 
   @XmlTransient
   private Map<String, Object> extensions;
   ...

Back to the top