添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
  • 1 Support for Root Elements representing Datatypes
  • 2 Document History
  • 3 Project overview
  • 4 Concepts
  • 5 Requirements
  • 6 Functionality
  • 6.1 Use Case 1: Root Element is a Datatype
  • 6.2 Use Case 2: Element Type Doesn't Match Schema
  • 6.3 Use Case 3: Unexpected Content
  • 6.4 Use Case 4: Datatype is a Union
  • 7 Prototype
  • 7.1 XMLDatatypeDescriptor
  • 7.2 XMLContext's datatypesByQName Map
  • 7.3 Project Metadata
  • 8 Documentation
  • 9 Open Issues
  • 10 Decisions
  • 11 Future Considerations
  • Support for Root Elements representing Datatypes

    ER 217508

    Document History

    Author Version Description & Notes 2008-02-01 Rick Barkhouse Initial draft. 2008-02-29 Rick Barkhouse Added prototype information.

    Project overview

    This project will add the ability for EclipseLink MOXy to unmarshal XML documents that have datatypes 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 datatype value, such as String or Byte[] .

    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 gYearMonth gYear gMonthDay gMonth hexBinary base64Binary anyURI QName NOTATION

    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 ( myDatatypeSchema.xsd ): <element name = "aValue" type = "myDatatype" /> <simpleType name = "myDatatype" > <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 Datatype

    Instance Document ( instance-1.xml ):

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

    EclipseLink Code:

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

    Result:

    OBJECT: 16.0 (class java.lang.Double)

    Use Case 2: Element Type Doesn't Match Schema

    Instance Document (instance-2.xml):

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

    Use Case 3: Unexpected Content

    Instance Document (instance-3.xml):

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

    Use Case 4: Datatype is a Union

    Instance Document (instance-4.xml):

    <?xml version="1.0"?>

    Prototype

    Following is an overview of the prototype implementation.

    XMLDatatypeDescriptor

    The information required to work with primitive data types is encapsulated in a new class, XMLDatatypeDescriptor. This is far less complicated than the other types of Eclipselink descriptors, storing only the following data:

    • the element's QName
    • the element's XSD schema type (also a QName)
    • the Java class that the value will be converted into
    // org.eclipse.persistence.oxm.XMLDatatypeDescriptor
    public class XMLDatatypeDescriptor {
       // Element's QName; also used as the key in XMLContext's datatypesByQName Map
       private QName qName;
       // Java class this element will be converted to
       private Class javaClass;
       // Element's XSD Type
       private QName schemaType;
    

    XMLContext's datatypesByQName Map

    A hash map 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 XMLDatatypeDescriptors, keyed on the element's QName.

    // org.eclipse.persistence.oxm.XMLContext
    public class XMLContext {
        private Map<QName, XMLDatatypeDescriptor> datatypesByQName;
    

    During unmarshal operations, if the QName of the element being unmarshalled is present in datatypesByQName, a new XMLRootRecord is created. XMLRootRecord is a SAX ContentHandler, and control will be passed to it to unmarshal the primitive element:

    // org.eclipse.persistence.internal.oxm.record.SAXUnmarshallerHandler
    public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
       XMLDescriptor xmlDescriptor = xmlContext.getDescriptor(rootQName);
       if (null == xmlDescriptor) {
          // Check to see if there is an XMLDatatypeDescriptor for this QName
          XMLDatatypeDescriptor wrapper = (XMLDatatypeDescriptor) xmlContext.getDatatypesByQName().get(rootQName);
          if (wrapper != null) {
                XMLRootRecord rootRecord = new XMLRootRecord(wrapper.getJavaClass(), this, wrapper.getSchemaType());
                rootRecord.setSession((AbstractSession) xmlContext.getSession(wrapper));
                rootRecord.startElement(namespaceURI, localName, qName, atts);
                xmlReader.setContentHandler(rootRecord);
                return;
    

    This map is populated in one of three ways:

    1. (SDO) When the user defines a schema using SDOXSDHelper.define(), a new XMLDatatypeDescriptor will be created and put into the map during type generation:

    // 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().getDatatypesByQName().put(qn, wrapper);
    

    2. (SDO) When the user specifies types directly, using SDOTypeHelper.define(), a new XMLDatatypeDescriptor will be put into the map in 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().getDatatypesByQName().put(propertyQName, wrapper);
    

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

    XMLLogin xmlLogin = new XMLLogin();
    Project oxmProject = new Project(xmlLogin);
    QName qname = new QName("myBase64Binary-NS", "myBase64Binary"); 
    XMLDatatypeDescriptor desc = new XMLDatatypeDescriptor(qname, Byte[].class, XMLConstants.BASE_64_BINARY_QNAME);
    xmlLogin.addXMLDatatypeDescriptor(desc);
    XMLContext xmlContext = new XMLContext(oxmProject);
    

    Project Metadata

    XMLDatatypeDescriptors are persisted to XML as part of the XMLLogin element, and are accessed through the public API on XMLLogin shown above. An example of a project containing primitive information:

    <?xml version="1.0" encoding="UTF-8"?>
    <eclipselink:object-persistence version="Eclipse Persistence Services - 1.0 (Build SNAPSHOT - 20080227)" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:eclipselink="http://xmlns.oracle.com/ias/xsds/eclipselink">
       <eclipselink:name>My OXM Project</eclipselink:name>
       <eclipselink:login xsi:type="eclipselink:xml-login">
          <eclipselink:platform-class>org.eclipse.persistence.oxm.platform.SAXPlatform</eclipselink:platform-class>
          <eclipselink:user-name></eclipselink:user-name>
          <eclipselink:password></eclipselink:password>
          <eclipselink:datatype-descriptors>
             <eclipselink:datatype-descriptor>
                <eclipselink:java-class>java.lang.Float</eclipselink:java-class>
                <eclipselink:schema-type>{http://www.w3.org/2001/XMLSchema}float</eclipselink:schema-type>
                <eclipselink:qname>{myFloat-NS}myFloat</eclipselink:qname>
             </eclipselink:datatype-descriptor>
          </eclipselink:datatype-descriptors>
       </eclipselink:login>
    </eclipselink:object-persistence>

    Documentation

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

    Open Issues

    Issue # Owner Description / Notes

    Decisions

    Issue # Description / Notes Decision

    Future Considerations