I have a data source that has switched from base64 embedded image data to XOP image data. I'm using Java/JAXB to unmarshal the data and can't find any good sources describing how it's done. All references seem to describe doing this with SOAP messages which seem to take care of some of the heavy lifting for you.
In my case, the data is coming in effectively as a string that needs to be unmarshalled into objects created by JAXB. Since the new messages start with
Mime-Version: 1.0
Content-Type: multipart/related; start-info="text/xml"; type="application/xop+xml";
start="<-963165769043289641.1400077877224@xxxxxyyyyyy.ca>";
boundary="----=_Part_0_-338193320.1400077877317"
obviously it won't unmarshal the data as XML as it doesn't look like XML (no data allowed before prolog).
Can this be done with JAXB? The creation of the object from the schema seems to work fine and creates what looks like a proper object (it creates an Include element). I've tried creating an AttachmentUnmarshaller manually but it hasn't helped ... the incoming data is still not recognized as XML. I feel like I'm missing a fundamental step but can't find any good references or examples.
Any help would be greatly appreciated.
Below is an approach that might help.
Below is roughly what you are going to be processing:
MIME-Version: 1.0
Content-Type: Multipart/Related;boundary=MIME_boundary;
...
--MIME_boundary
Content-Type: application/xop+xml;
...
<soap:Envelope ...
<soap:Body>...
<foo>
<photo xmlmime:contentType='image/png'>
<xop:Include xmlns:xop='http://www.w3.org/2004/08/xop/include'
href='cid:http://example.org/me.jpeg'/></m:photo>
...
--MIME_boundary
Content-Type: image/png
Content-Transfer-Encoding: binary
Content-ID: <http://example.org/me.png>
// binary octets for png
Demo
The code below assumes you have processed the message to do the following:
import java.io.File;
import javax.xml.bind.*;
public class Demo {
private static String base64 = "/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5/ooooA//2Q==";
public static void main(String[] args) throws Exception {
// Create the JAXBContext & Unmarshaller
JAXBContext jc = JAXBContext.newInstance(Foo.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
// Create a custom AttachementUnmarshaller. Populate the Map
// AttachmentUnmarshaller with the attachments keyed on the cid.
MyAttachmentUnmarshaller attachmentUnmarshaller = new MyAttachmentUnmarshaller();
attachmentUnmarshaller.getAttachments().put("cid:http://example.org/me.jpeg", DatatypeConverter.parseBase64Binary(base64));
// Set the AttachmentUnmarshaller on the Unmarshaller
unmarshaller.setAttachmentUnmarshaller(attachmentUnmarshaller);
// Unmarshal the XML piece
File xml = new File("src/forum24407360/input.xml");
Foo foo = (Foo) unmarshaller.unmarshal(xml);
}
}
MyAttachmentUnmarshaller
Below is what the AttachmentUnmarshaller
looks like. An AttachmentUnmarshaller
is passed in the cid and is responsible for returning the corresponding binary data. In a JAX-WS environment this is handled automatically for you, but there is nothing preventing you from doing it manually. You can find more information about it here: What's the most standard Java way to store raw binary data along with XML?.
import java.io.*;
import java.util.*;
import javax.activation.*;
import javax.xml.bind.attachment.AttachmentUnmarshaller;
public class MyAttachmentUnmarshaller 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;
}
}
}
<foo>
<image>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:http://example.org/me.jpeg"/>
</image>
</foo>