CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework--spring-oxm

Spring Object/XML Marshalling support providing generic interfaces for converting Java objects to XML and vice versa

Overview
Eval results
Files

mime-support.mddocs/

MIME Attachment Support

MIME attachment support enables optimized handling of binary data in XML through MIME attachments using MTOM (Message Transmission Optimization Mechanism), XOP (XML-binary Optimized Packaging), or SwA (SOAP with Attachments) protocols.

Core Interfaces

MimeMarshaller

Extended marshaller interface that supports MIME attachments during marshalling.

public interface MimeMarshaller extends Marshaller {
    /**
     * Marshals the object graph with the given root into the provided Result,
     * writing binary data to a MimeContainer.
     * @param graph the root of the object graph to marshal
     * @param result the result to marshal to
     * @param mimeContainer the MIME container to write extracted binary content to
     * @throws XmlMappingException if the given object cannot be marshalled to the result
     * @throws IOException if an I/O exception occurs
     */
    void marshal(Object graph, Result result, @Nullable MimeContainer mimeContainer) 
        throws XmlMappingException, IOException;
}

MimeUnmarshaller

Extended unmarshaller interface that supports MIME attachments during unmarshalling.

public interface MimeUnmarshaller extends Unmarshaller {
    /**
     * Unmarshals the given provided Source into an object graph,
     * reading binary attachments from a MimeContainer.
     * @param source the source to marshal from
     * @param mimeContainer the MIME container to read extracted binary content from
     * @return the object graph
     * @throws XmlMappingException if the given source cannot be mapped to an object
     * @throws IOException if an I/O Exception occurs
     */
    Object unmarshal(Source source, @Nullable MimeContainer mimeContainer) 
        throws XmlMappingException, IOException;
}

MimeContainer

Container interface for managing MIME attachments and XOP packages.

public interface MimeContainer {
    /**
     * Indicate whether this container is a XOP package.
     * @return true when the constraints specified in XOP Documents are met
     */
    boolean isXopPackage();

    /**
     * Turn this message into a XOP package.
     * @return true when the message actually is a XOP package
     */
    boolean convertToXopPackage();

    /**
     * Add the given data handler as an attachment to this container.
     * @param contentId the content id of the attachment
     * @param dataHandler the data handler containing the data of the attachment
     */
    void addAttachment(String contentId, DataHandler dataHandler);

    /**
     * Return the attachment with the given content id, or null if not found.
     * @param contentId the content id
     * @return the attachment, as a data handler
     */
    @Nullable
    DataHandler getAttachment(String contentId);
}

Usage Examples

Basic MIME Marshalling

import org.springframework.oxm.mime.MimeMarshaller;
import org.springframework.oxm.mime.MimeContainer;
import jakarta.activation.DataHandler;
import jakarta.activation.ByteArrayDataSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;

// Assuming you have a MimeMarshaller implementation (like Jaxb2Marshaller)
MimeMarshaller mimeMarshaller = // ... get mime marshaller

// Create a MimeContainer implementation
MimeContainer mimeContainer = new MimeContainer() {
    private Map<String, DataHandler> attachments = new HashMap<>();
    private boolean isXop = false;
    
    @Override
    public boolean isXopPackage() { return isXop; }
    
    @Override
    public boolean convertToXopPackage() {
        isXop = true;
        return true;
    }
    
    @Override
    public void addAttachment(String contentId, DataHandler dataHandler) {
        attachments.put(contentId, dataHandler);
    }
    
    @Override
    public DataHandler getAttachment(String contentId) {
        return attachments.get(contentId);
    }
};

// Object with binary data
DocumentWithAttachment document = new DocumentWithAttachment();
document.setTitle("My Document");
document.setContent("Document content");
document.setBinaryData(new byte[]{ /* large binary data */ });

// Marshal with MIME container
StringWriter writer = new StringWriter();
mimeMarshaller.marshal(document, new StreamResult(writer), mimeContainer);

// The XML will contain references to attachments
String xml = writer.toString();
// Binary data is stored in mimeContainer attachments

MIME Unmarshalling

import org.springframework.oxm.mime.MimeUnmarshaller;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;

// Assuming you have the XML and populated MimeContainer from marshalling
String xmlWithReferences = // ... XML with attachment references
MimeContainer populatedContainer = // ... container with attachments

MimeUnmarshaller mimeUnmarshaller = // ... get mime unmarshaller

// Unmarshal with MIME container
StringReader reader = new StringReader(xmlWithReferences);
DocumentWithAttachment document = (DocumentWithAttachment) 
    mimeUnmarshaller.unmarshal(new StreamSource(reader), populatedContainer);

// Binary data is restored from attachments
byte[] binaryData = document.getBinaryData();

JAXB with MIME Support

The Jaxb2Marshaller implements both MimeMarshaller and MimeUnmarshaller:

import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlMimeType;
import jakarta.activation.DataHandler;

// JAXB class with MIME type annotation
@XmlRootElement
public class DocumentWithImage {
    private String title;
    
    @XmlMimeType("image/jpeg")
    private DataHandler imageData;
    
    // getters and setters...
}

// Configure JAXB marshaller for MIME support
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(DocumentWithImage.class);
marshaller.setMtomEnabled(true); // Enable MTOM support
marshaller.afterPropertiesSet();

// Create document with image
DocumentWithImage doc = new DocumentWithImage();
doc.setTitle("Document with Image");

// Create DataHandler for image
byte[] imageBytes = // ... load image data
DataHandler imageHandler = new DataHandler(
    new ByteArrayDataSource(imageBytes, "image/jpeg")
);
doc.setImageData(imageHandler);

// Marshal with MIME container
MimeContainer container = // ... your container implementation
StringWriter writer = new StringWriter();
marshaller.marshal(doc, new StreamResult(writer), container);

XOP Package Handling

// Working with XOP packages
MimeContainer container = // ... your container

// Check if container supports XOP
if (!container.isXopPackage()) {
    // Convert to XOP package for optimized binary handling
    boolean converted = container.convertToXopPackage();
    if (converted) {
        System.out.println("Container converted to XOP package");
    }
}

// Add binary data as attachment
byte[] binaryData = // ... your binary data
DataHandler dataHandler = new DataHandler(
    new ByteArrayDataSource(binaryData, "application/octet-stream")
);
container.addAttachment("binary-content-1", dataHandler);

Custom MimeContainer Implementation

import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

public class SimpleMimeContainer implements MimeContainer {
    private final Map<String, DataHandler> attachments = new ConcurrentHashMap<>();
    private volatile boolean isXopPackage = false;
    
    @Override
    public boolean isXopPackage() {
        return isXopPackage;
    }
    
    @Override
    public boolean convertToXopPackage() {
        this.isXopPackage = true;
        return true;
    }
    
    @Override
    public void addAttachment(String contentId, DataHandler dataHandler) {
        if (contentId == null || dataHandler == null) {
            throw new IllegalArgumentException("ContentId and DataHandler cannot be null");
        }
        attachments.put(contentId, dataHandler);
    }
    
    @Override
    public DataHandler getAttachment(String contentId) {
        return attachments.get(contentId);
    }
    
    // Additional utility methods
    public Set<String> getAttachmentIds() {
        return attachments.keySet();
    }
    
    public int getAttachmentCount() {
        return attachments.size();
    }
    
    public void clearAttachments() {
        attachments.clear();
    }
}

JAXB MIME Annotations

When using JAXB with MIME support, use these annotations:

import jakarta.xml.bind.annotation.*;
import jakarta.activation.DataHandler;
import java.awt.Image;

@XmlRootElement
public class MultimediaDocument {
    
    @XmlElement
    private String title;
    
    // Binary data as DataHandler with MIME type
    @XmlMimeType("image/jpeg")
    private DataHandler photo;
    
    // Binary data as byte array
    @XmlMimeType("application/pdf")
    private byte[] pdfContent;
    
    // Image data
    @XmlMimeType("image/png")
    private Image diagram;
    
    // getters and setters...
}

MTOM Configuration

Message Transmission Optimization Mechanism (MTOM) configuration:

import org.springframework.oxm.jaxb.Jaxb2Marshaller;

Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(MultimediaDocument.class);

// Enable MTOM for optimized binary transfer
marshaller.setMtomEnabled(true);

// Configure attachment marshaller/unmarshaller if needed
marshaller.setAttachmentMarshaller(customAttachmentMarshaller);
marshaller.setAttachmentUnmarshaller(customAttachmentUnmarshaller);

marshaller.afterPropertiesSet();

Error Handling

try {
    MimeContainer container = new SimpleMimeContainer();
    DocumentWithAttachment doc = new DocumentWithAttachment();
    
    StringWriter writer = new StringWriter();
    mimeMarshaller.marshal(doc, new StreamResult(writer), container);
    
} catch (XmlMappingException e) {
    System.err.println("MIME marshalling failed: " + e.getMessage());
    
    // Check for specific MIME-related errors
    Throwable cause = e.getCause();
    if (cause instanceof jakarta.xml.bind.MarshalException) {
        System.err.println("JAXB marshalling error: " + cause.getMessage());
    }
}

Required Imports

import org.springframework.oxm.mime.MimeMarshaller;
import org.springframework.oxm.mime.MimeUnmarshaller;
import org.springframework.oxm.mime.MimeContainer;
import org.springframework.oxm.XmlMappingException;

import jakarta.activation.DataHandler;
import jakarta.activation.DataSource;
import jakarta.activation.ByteArrayDataSource;
import jakarta.xml.bind.annotation.XmlMimeType;
import jakarta.xml.bind.attachment.AttachmentMarshaller;
import jakarta.xml.bind.attachment.AttachmentUnmarshaller;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

Best Practices

  1. Use MTOM for large binary data: Enable MTOM when dealing with large binary attachments
  2. Content-ID management: Use meaningful content IDs for attachments
  3. Memory considerations: Be aware that large attachments are held in memory
  4. Security: Validate attachment content types and sizes
  5. Cleanup: Properly dispose of DataHandler resources when done
  6. XOP package conversion: Convert to XOP packages for better optimization when dealing with multiple binary attachments

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework--spring-oxm

docs

core-marshalling.md

index.md

jaxb-implementation.md

mime-support.md

support-utilities.md

xstream-implementation.md

tile.json