Jaxb, Web Services, and binary data

Source: Internet
Author: User

JAXB, Web Services, and Binary Data
When an instance of a class is used with a Web Service, the JAX-WS implementation can choose to handle fields/properties that hold binary data as SOAP attachment. an attachment is a means to send the data outside of the XML message, this is done as an optimization since binary data encoded as a xs: base64Binary string cocould be quite large. JAXB offers a couple of annotations to control this behaviour:

@ Xmlinebinarydata
This specifies that the binary data for this field/property must be written to the XML document as xs: base64Binary and not sent as an attachment.
@ XmlMimeType
For properties of type java. awt. Image or javax. xml. transform. Source, this annotation allows the mime type to be specified that will be used for encoding the data as bytes.

Java Model

The following class will be used as the domain model for this example. it has various properties for representing binary data. property "c" has been annotated with @ xmlinebinarydata to prevent that data from being treated as an attachment, and property "d" has been annotated with @ XmlMimeType to specify that the Image shoshould be encoded as a JPEG.

Package blog. attachments;

Import java. awt. Image;

Import javax. xml. bind. annotation. xmlinebinarydata;
Import javax. xml. bind. annotation. XmlMimeType;
Import javax. xml. bind. annotation. XmlRootElement;

@ XmlRootElement
Public class Root {

Private byte [];
Private byte [] B;
Private byte [] c;
Private Image d;

Public byte [] getA (){
Return;
}

Public void setA (byte [] foo ){
This. a = foo;
}

Public byte [] getB (){
Return B;
}

Public void setB (byte [] bar ){
This. B = bar;
}

@ Xmlinebinarydata
Public byte [] getC (){
Return c;
}

Public void setC (byte [] c ){
This. c = c;
}

@ XmlMimeType ("image/jpeg ")
Public Image getD (){
Return d;
}

Public void setD (Image d ){
This. d = d;
}

}

Web Service Layer

When a JAX-WS implementation leverages attachments the XML payload will look similar to the following. some data will be stored alled as xs: base64Binary and other data will be stored alled as an identifier that will serve as a reference to the attachment.

<Root>
<A>
<Xop: Include
Href = "cid: 1"
Xmlns: xop = "http://www.w3.org/2004/08/xop/include"/>
</A>
<B> QkFS </B>
<C> SEVMTE8gV09STEQ = </c>
<D>
<Xop: Include
Href = "cid: 2"
Xmlns: xop = "http://www.w3.org/2004/08/xop/include"/>
</D>
</Root>

A JAX-WS provider achieves this by leveraging jaxb's attachmentmarshaller and attachmentunmarshaller mechanisms. you do not need to write any code to make this happen. the following code is provided to give you a behind the scenes look.

Example attachmentmarshaller

A JAX-WS provider that wants to leverage attachments registers an implementation of javax. XML. BIND. attachment. attachmentmarshaller on the jaxb extends aller. the implementation is specific to the JAX-WS provider, but below is a sample of how it might look. A JAX-WS provider can choose when to handle binary data as an attachment, in the Implementation below any candidate byte [] of size greater than 10 will be treated as an attachment.

Package blog. attachments;

Import java. util. arraylist;
Import java. util. List;

Import javax. Activation. datahandler;
Import javax. xml. bind. attachment. attachmentallaller;

Public class exampleattachmentextends aller extends attachmentimplements aller {

Private static final int THRESHOLD = 10;

Private List <Attachment> attachments = new ArrayList <Attachment> ();

Public List <Attachment> getAttachments (){
Return attachments;
}

@ Override
Public String addMtomAttachment (DataHandler data, String elementNamespace, String elementLocalName ){
Return null;
}

@ Override
Public String addmtomattachment (byte [] data, int offset, int length, string mimetype, string elementnamespace, string elementlocalname ){
If (data. Length <threshold ){
Return NULL;
}
Int id = attachments. Size () + 1;
Attachments. Add (new attachment (data, offset, length ));
Return "CID:" + String. valueof (ID );
}

@ Override
Public String addswarefattachment (datahandler data ){
Return NULL;
}

@ Override
Public boolean isXOPPackage (){
Return true;
}

Public static class Attachment {

Private byte [] data;
Private int offset;
Private int length;

Public Attachment (byte [] data, int offset, int length ){
This. data = data;
This. offset = offset;
This. length = length;
}

Public byte [] getdata (){
Return data;
}

Public int getoffset (){
Return offset;
}

Public int getlength (){
Return length;
}

}

}

Example attachmentunmarshaller

If a JAX-WS provider is leveraging attachments, then an implementation of javax. xml. bind. attachment. attachmentUnmarshaller must be specified on the JAXB Unmarshaller. again the implementations is specific to the JAX-WS provider. A sample implementation is shown below:

Package blog. attachments;

Import java. io. ByteArrayInputStream;
Import java. io. IOException;
Import java. io. InputStream;
Import java. io. OutputStream;
Import java. util. HashMap;
Import java. util. Map;

Import javax. activation. DataHandler;
Import javax. activation. DataSource;
Import javax. xml. bind. attachment. AttachmentUnmarshaller;

Public class ExampleAttachmentUnmarshaller extends AttachmentUnmarshaller {

Private Map <String, byte []> attachments = new HashMap <String, byte []> ();

Public Map <String, byte []> getAttachments (){
Return attachments;
}

@ Override
Public DataHandler getAttachmentAsDataHandler (String cid ){
Byte [] bytes = attachments. get (cid );
Return new DataHandler (new ByteArrayDataSource (bytes ));
}

@ Override
Public byte [] getAttachmentAsByteArray (String cid ){
Return attachments. get (cid );
}

@ Override
Public boolean isXOPPackage (){
Return true;
}

Private static class ByteArrayDataSource implements DataSource {

Private byte [] bytes;

Public ByteArrayDataSource (byte [] bytes ){
This. bytes = bytes;
}

Public String getContentType (){
Return "application/octet-stream ";
}

Public inputstream getinputstream () throws ioexception {
Return new bytearrayinputstream (bytes );
}

Public String getname (){
Return NULL;
}

Public outputstream getoutputstream () throws ioexception {
Return NULL;
}

}

}

DEMO code

The following example was too red by an answer I gave on Stack Overflow (feel free To up vote ). it covers how to leverage jaxb's attachmentmarshaller & attachmentunmarshaller to produce a message in the following format:

[Xml_length] [XML] [attach1_length] [attach1]... [attachn_length] [attachn]

While this example is unique to a special use case, it does demonstrate jaxb's attachment mechanic without requiring a JAX-WS provider.

Demo

Package blog. attachments;

Import java. AWT. image. bufferedimage;
Import java. Io. fileinputstream;
Import java. Io. fileoutputstream;
Import javax. xml. Bind. jaxbcontext;

Public class demo {

Public static void main (string [] ARGs) throws exception {
Jaxbcontext JC = jaxbcontext. newinstance (root. Class );

Root = New Root ();
Root. Seta ("Hello world". getbytes ());
Root. SETB ("bar". getbytes ());
Root. SETC ("Hello world". getbytes ());
Root. setd (New bufferedimage (10, 10, bufferedimage. type_int_rgb ));

Messagewriter writer = new messagewriter (JC );
Fileoutputstream outstream = new fileoutputstream ("message. xml ");
Writer. Write (root, outstream );
Outstream. Close ();

MessageReader reader = new MessageReader (jc );
FileInputStream inStream = new FileInputStream ("message. xml ");
Root root2 = (Root) reader. read (inStream );
InStream. close ();
System. out. println (new String (root2.getA ()));
System. out. println (new String (root2.getB ()));
System. out. println (new String (root2.getC ()));
System. out. println (root2.getD ());
}

}

MessageWriter

Package blog. attachments;

Import java. io. ByteArrayOutputStream;
Import java. io. ObjectOutputStream;
Import java. io. OutputStream;

Import javax. xml. bind. JAXBContext;
Import javax. xml. bind. Marshaller;

Import blog. attachments. ExampleAttachmentMarshaller. Attachment;

Public class MessageWriter {

Private JAXBContext jaxbContext;

Public MessageWriter (JAXBContext jaxbContext ){
This. jaxbContext = jaxbContext;
}

/**
* Write the message in the following format:
* [Xml_length] [xml] [attach1_length] [attach1]... [attachN_length] [attachN]
*/
Public void write (Object object, OutputStream stream ){
Try {
Extends aller extends aller = jaxbContext. createMarshaller ();
Extends aller. setProperty (extends aller. JAXB_FRAGMENT, true );
Exampleattachmentimplements aller attachmentimplements aller = new exampleattachmentimplements aller ();
Extends aller. setAttachmentMarshaller (attachmentMarshaller );
ByteArrayOutputStream xmlStream = new ByteArrayOutputStream ();
Marshaller. Marshal (object, xmlstream );
Byte [] xml = xmlstream. tobytearray ();
Xmlstream. Close ();

Objectoutputstream messagestream = new objectoutputstream (Stream );

Messagestream. writeint (XML. Length); // [xml_length]
Messagestream. Write (XML); // [XML]

For (Attachment attachment: attachmentmarshaller. getattachments ()){
Messagestream. writeint (attachment. getlength (); // [attachx_length]
Messagestream. Write (attachment. getdata (), attachment. getoffset (), attachment. getlength (); // [attachx]
}

Messagestream. Flush ();
} Catch (exception e ){
Throw new runtimeexception (E );
}
}

}

Messagereader

Package blog. attachments;

Import java. io. ByteArrayInputStream;
Import java. io. InputStream;
Import java. io. ObjectInputStream;

Import javax. xml. bind. JAXBContext;
Import javax. xml. bind. Unmarshaller;

Public class MessageReader {

Private JAXBContext jaxbContext;

Public MessageReader (JAXBContext jaxbContext ){
This. jaxbContext = jaxbContext;
}

/**
* Read the message from the following format:
* [Xml_length] [xml] [attach1_length] [attach1]... [attachN_length] [attachN]
*/
Public Object read (InputStream stream ){
Try {
Objectinputstream inputstream = new objectinputstream (Stream );
Int xmllength = inputstream. readint (); // [xml_length]

Byte [] xmlin = new byte [xmllength];
Inputstream. Read (xmlin); // [XML]

Exampleattachmentunmarshaller attachmentunmarshaller = new exampleattachmentunmarshaller ();
Int id = 1;
While (inputstream. Available ()> 0 ){
Int length = inputStream. readInt (); // [attachX_length]
Byte [] data = new byte [length]; // [attachX]
InputStream. read (data );
AttachmentUnmarshaller. getAttachments (). put ("cid:" + String. valueOf (id ++), data );
}

Unmarshaller unmarshaller = jaxbContext. createUnmarshaller ();
Unmarshaller. setAttachmentUnmarshaller (attachmentUnmarshaller );
ByteArrayInputStream byteInputStream = new ByteArrayInputStream (xmlIn );
Object object = unmarshaller. unmarshal (byteInputStream );
ByteInputStream. close ();
InputStream. close ();
Return object;
} Catch (Exception e ){
Throw new RuntimeException (e );
}
}

}

Article transferred from: http://blog.bdoughan.com/2011/03/jaxb-web-services-and-binary-data.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.