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

EclipseLink/DesignDocs/217508

< EclipseLink‎ | DesignDocs
Revision as of 17:44, 29 February 2008 by Rick.barkhouse.oracle.com (Talk | contribs) (XMLContext's <code>primitivesByQName</code> Map)

Support for Root Elements representing Simple Types

ER 217508

Document History

Date Author Version Description & Notes
2008-02-01 Rick Barkhouse Initial Draft

Project overview

This project will add the ability for EclipseLink OX to unmarshal XML documents that have simple types as their root element. Instead of a "rich" top-level element representing a domain object (e.g. Employee, PurchaseOrder), the root element may be a simple primitive value.

Goals:

  • Allow the user to unmarshal XML documents that contain simple type root elements.

Concepts

The following concepts are used in this document:

  • Simple Type - one of the basic, "built-in" types available in XML Schema. These may represent basic Java primitives (such as xsd:boolean and xsd:float), or more robust types (xsd:hexBinary, xsd:dateTime, xsd:QName). XML Schema has two categories of simple types; Primitive Types (the most basic of data type), and Derived Types (other simple types that are defined in terms of primitive types).

XML Schema Primitive Data Types
string boolean decimal float double duration dateTime
time date gYearMonth gYear gMonthDay gDay gMonth
hexBinary base64Binary anyURI QName NOTATION
XML Schema Derived Data Types
normalizedString token language NMTOKEN NMTOKENS Name NCName
ID IDREF IDREFS ENTITY ENTITIES integer nonPositiveInteger
negativeInteger long int short byte nonNegativeInteger unsignedLong
unsignedInt unsignedShort unsignedByte positiveInteger

For more information see: http://www.w3.org/TR/xmlschema-2/#built-in-datatypes

Requirements

The requirements for this project are as follows:

  • Support unmarshalling of XML instance documents that contain Simple Type (both primitive and derived) root elements.
  • Support marshalling "primitive" Java objects to XML.
  • Ensure that the proper ConversionManager is used when converting XML to Java.
  • Ensure that the proper ClassLoader is used when converting values.


For example, the JAXB TCK uses the following types of test documents:

XML Schema - The schema contains a single element, a restriction (extension) of the base64Binary simple type:

<schema ...>
...
   <element name="NISTSchema-base64Binary-enumeration" type="nist:NISTSchema-base64Binary-enumeration-Type"/>
 
   <simpleType name="NISTSchema-base64Binary-enumeration-Type">
      <restriction base="base64Binary">
         <enumeration value="bHlsY2JmaXFjaW9ubmg="/>
      </restriction>
   </simpleType>
</schema>

XML Instance Document - The document contains a single element with value zGk=:

<NISTSchema-base64Binary-enumeration
    xmlns="NISTSchema-base64Binary-enumeration-NS"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="NISTSchema-base64Binary-enumeration-NS enumeration.xsd">zGk=</NISTSchema-base64Binary-enumeration>

Functionality

Schema (primitive.xsd):

...
   <element name="aSimpleValue" type="mySimpleType"/>
 
   <simpleType name="mySimpleType">
      <restriction base="double">
         <enumeration value="4"/>
         <enumeration value="8"/>
         <enumeration value="15"/>
         <enumeration value="16"/>
         <enumeration value="23"/>
         <enumeration value="42"/>
      </restriction>
   </simpleType>
...

Use Case 1: Root Element is a Primitive Simple Type

Instance Document (primitive-1.xml):

<?xml version="1.0"?>
 
<aSimpleValue>16</aSimpleValue>

EclipseLink Code:

import org.eclipse.persistence.oxm.XMLContext;
...
   MyProject proj = new MyProject();
   XMLContext ctx = new XMLContext(proj);
   Object o = ctx.createUnmarshaller().unmarshal(new File("primitive-1.xml"));
 
   System.out.println("OBJECT: " + o + " ("+ o.getClass() + ")");
...

Result:

OBJECT: 16.0 (class java.lang.Double)

Use Case 2: Unexpected Content

Instance Document (primitive-2.xml):

<?xml version="1.0"?>
 
<aSimpleValue>
   16
   <other>Something Else</other>
   Hello World!
</aSimpleValue>

Use Case 3: Element Type Doesn't Match Schema

Instance Document (primitive-3.xml):

<?xml version="1.0"?>
 
<aSimpleValue xsi:type="date">16</aSimpleValue>

Prototype

Following is an overview of the prototype implementation.

XMLContext's primitivesByQName Map

A HashMap is added to XMLContext to keep track of which user-defined types represent restrictions ("subclasses") of XML primitive types. The values of this map are instances of a new class, XMLDatatypeDescriptor, and keyed on the element's QName.

// org.eclipse.persistence.oxm.XMLDatatypeDescriptor
...
public class XMLDatatypeDescriptor {
   // Element's QName; also used as the key in XMLContext's primitivesByQName Map
   private QName qName;
 
   // Java class this element will be converted to
   private Class javaClass;
 
   // Element's XSD Type
   private QName schemaType;
 
   public XMLDatatypeDescriptor(QName aQName, Class aClass, QName aSchemaType) {
      ...
   }
 
   ...
}



This map is populated in one of three ways:

1. (SDO) When the user defines a schema using SDOXSDHelper.define():

// org.eclipse.persistence.sdo.helper.SDOTypesGenerator
 
private void addRootElementToDescriptor(SDOProperty p, String targetNamespace, String xsdName) {
   if (!p.getType().isDataType()) {
      ...
   } else {
      // This must be a primitive, so add to XMLContext's primitivesByQName map
      SDOXMLHelper helper = (SDOXMLHelper) ((SDOType)p.getType()).getHelperContext().getXMLHelper();
 
      QName qn = new QName(targetNamespace, xsdName);
      Class primitiveClass = p.getType().getInstanceClass();
      QName xsdTypeQN = ((SDOType)p.getType()).getXsdType();
 
      XMLDatatypeDescriptor wrapper = new XMLDatatypeDescriptor(qn, primitiveClass, xsdTypeQN); 
 
      helper.getXmlContext().getPrimitivesByQName().put(qn, wrapper);
}

2. (SDO) When the user specifies types directly, using SDOTypeHelper.defineOpenContentProperty():

// org.eclipse.persistence.sdo.helper.delegates.SDOTypeHelperDelegate
 
private void defineOpenContentProperty(String propertyUri, String propertyName, Property property) {
   if (propertyUri != null) {            
      ...
      XMLDescriptor aDescriptor = ((SDOType)property.getType()).getXmlDescriptor();
      ...
      if (aDescriptor != null) {
         ...
      } else {
         // This must be a primitive, so add to XMLContext's primitivesByQName map
         SDOXMLHelper helper = (SDOXMLHelper) ((SDOType)property.getType()).getHelperContext().getXMLHelper();
 
         Class primitiveClass = property.getType().getInstanceClass();
         QName xsdTypeQN = ((SDOType)property.getType()).getXsdType();
 
         XMLDatatypeDescriptor wrapper = new XMLDatatypeDescriptor(propertyQName, primitiveClass, xsdTypeQN); 
 
         helper.getXmlContext().getPrimitivesByQName().put(propertyQName, wrapper);
      }
   }
}

3. When the user explicitly adds primitive type information to XMLLogin.

Documentation

EclipseLink User Documentation should be updated to demonstrate how documents containing Simple Type root elements are supported.

Open Issues

Decisions

Issue # Owner Description / Notes

Future Considerations

Issue # Description / Notes Decision

Back to the top