May 5, 2011

Schema to Java: @XmlMimeType & @XmlInlineBinaryData

In a previous post I described the impact of the @XmlInlineBinaryData and @XmlMimeType annotations in a JAX-WS environment where binary data may be sent as attachments.  One of the comments I received on that post was how to have those annotations generated onto your classes when starting from an XML schema.  In this post I will address that question.


Java Model

Below is the type of Java model we are trying to generate.  The accessors have been omitted to save space.

package com.example;

import java.awt.Image;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlInlineBinaryData;
import javax.xml.bind.annotation.XmlMimeType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"a","b","c","d"})
@XmlRootElement(name = "root")
public class Root {

    protected byte[] a;

    protected byte[] b;

    @XmlInlineBinaryData
    protected byte[] c;

    @XmlMimeType("image/jpeg")
    protected Image d;

}

XML Schema

Below is the XML schema we will be starting with.

<?xml version="1.0"?>
<xsd:schema 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns="http://www.example.com"
    targetNamespace="http://www.example.com">
    <xsd:element name="root">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="a"
                    minOccurs="0"
                    type="xsd:base64Binary"/>
                <xsd:element name="b"
                    minOccurs="0"
                    type="xsd:base64Binary"/>
                <xsd:element name="c"
                    minOccurs="0"
                    type="xsd:base64Binary"/>
                <xsd:element name="d"
                    minOccurs="0"
                    type="xsd:base64Binary"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

If we generate Java classes from the above schema the resulting class will look like (accessors have been omitted to save space):

package com.example;

import java.awt.Image;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlInlineBinaryData;
import javax.xml.bind.annotation.XmlMimeType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"a","b","c","d"})
@XmlRootElement(name = "root")
public class Root {

    protected byte[] a;

    protected byte[] b;

    protected byte[] c;

    protected byte[] d;

}

@XmlMimeType and Image

To generate our d field to be of type Image annotated with @XmlMimeType we specify the xmime:expectedContentTypes attribute on the d element.

<?xml version="1.0"?>
<xsd:schema 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xmime="http://www.w3.org/2005/05/xmlmime" 
    xmlns="http://www.example.com"
    targetNamespace="http://www.example.com">
    <xsd:element name="root">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="a" 
                    minOccurs="0"
                    type="xsd:base64Binary"/>
                <xsd:element name="b" 
                    minOccurs="0"
                    type="xsd:base64Binary"/>
                <xsd:element name="c"
                    minOccurs="0"
                    type="xsd:base64Binary"/>
                <xsd:element name="d" 
                    minOccurs="0"
                    type="xsd:base64Binary" 
                    xmime:expectedContentTypes="image/jpeg"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

Now when we generate our class it will look like:

package com.example;

import java.awt.Image;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlInlineBinaryData;
import javax.xml.bind.annotation.XmlMimeType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"a","b","c","d"})
@XmlRootElement(name = "root")
public class Root {

    protected byte[] a;

    protected byte[] b;

    protected byte[] c;

    @XmlMimeType("image/jpeg")
    protected Image d;

}

@XmlInlineBinaryData

To generate the @XmlInlineBinaryData annotation we need to customize our XML schema.  This can either be done inline, or as below with a JAXB bindings file:

Bindings File (bindings.xml)

<jxb:bindings 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    version="2.1">

    <jxb:bindings schemaLocation="binary.xsd">
        <jxb:bindings node="//xsd:element[@name='root']/xsd:complexType/xsd:sequence/xsd:element[@name='c']">
            <jxb:inlineBinaryData/>
        </jxb:bindings>
    </jxb:bindings>

</jxb:bindings>


The bindings file is passed as a parameter to the XJC call:

xjc -d out -b bindings.xml binary.xsd

The resulting Java class will be:

package com.example;

import java.awt.Image;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlInlineBinaryData;
import javax.xml.bind.annotation.XmlMimeType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"a","b","c","d"})
@XmlRootElement(name = "root")
public class Root {

    protected byte[] a;

    protected byte[] b;

    @XmlInlineBinaryData
    protected byte[] c;

    @XmlMimeType("image/jpeg")
    protected Image d;

}


Further Reading

If you enjoyed this post, then you may also be interested in:

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.