Search code examples
javamime-typesdatahandler

How to add "text/plain" MIME type to DataHandler


I have been struggling with getting this test to work for awhile, the relevant code executes fine in production my assumption is that it has some additional configuration, lots of searching seems to be related specifically to email handling and additional libraries, I don't want to include anything else, what am I missing to link DataHandler to a relevant way of handling "text/plain" ?

Expected result: DataHandler allows me to stream the input "Value" back into a result.

Reproduce issue with this code:

import java.io.IOException;
import java.io.InputStream;

import javax.activation.CommandInfo;
import javax.activation.CommandMap;
import javax.activation.DataHandler;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class DataHandlerTest {

    @Before
    public void setUp() throws Exception {
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void test() throws IOException {

        printDefaultCommandMap();
        DataHandler dh = new DataHandler("Value", "text/plain");
        System.out.println("DataHandler commands:");
        printDataHandlerCommands(dh);
        dh.setCommandMap(CommandMap.getDefaultCommandMap());
        System.out.println("DataHandler commands:");
        printDataHandlerCommands(dh);

        final InputStream in = dh.getInputStream();
        String result = new String(IOUtils.toByteArray(in));

        System.out.println("Returned String: " + result);
    }

    private void printDataHandlerCommands(DataHandler dh) {

        CommandInfo[] infos = dh.getAllCommands();
        printCommands(infos);
    }

    private void printDefaultCommandMap() {

        CommandMap currentMap = CommandMap.getDefaultCommandMap();
        String[] mimeTypes = currentMap.getMimeTypes();

        System.out.println("Found " + mimeTypes.length + " MIME types.");
        for (String mimeType : mimeTypes) {
            System.out.println("Commands for: " + mimeType);
            printCommands(currentMap.getAllCommands(mimeType));
        }
    }

    private void printCommands(CommandInfo[] infos) {

        for (CommandInfo info : infos) {
            System.out.println("   Command Class: " +info.getCommandClass());
            System.out.println("   Command Name: " + info.getCommandName());
        }
    }
}

Exception:

javax.activation.UnsupportedDataTypeException: no object DCH for MIME type text/plain at javax.activation.DataHandler.getInputStream(DataHandler.java:249)

Help much appreciated, I hope this is a well formed question!

========================

Update 25th February

I have found if i know I stored a String in DataHandler, then I can cast the result to String and return the object that was stored, example:

@Test
public void testGetWithoutStream() throws IOException {

    String inputString = "Value";
    DataHandler dh = new DataHandler(inputString, "text/plain");

    String rawResult = (String) dh.getContent();
    assertEquals(inputString, rawResult);
}

But the code under test uses an InputStream, so my 'real' tests still fail when executed locally. Continuing my investigation and still hoping for someone's assistance/guidance on this one...


Solution

  • Answering my own question for anyone's future reference.

    All credit goes to: https://community.oracle.com/thread/1675030?start=0

    The principle here is that you need to provide DataHandler a factory that contains a DataContentHandler that will behave as you would like it to for your MIME type, setting this is via a static method that seems to affect all DataHandler instances.

    I declared a new class (SystemDataHandlerConfigurator), which has a single public method that creates my factory and provides it the static DataHandler.setDataContentHandlerFactory() function.

    My tests now work correctly if I do this before they run:

    SystemDataHandlerConfigurator configurator = new SystemDataHandlerConfigurator();
    configurator.setupCustomDataContentHandlers();
    

    SystemDataHandlerConfigurator

    import java.io.IOException;
    import javax.activation.*;
    
    public class SystemDataHandlerConfigurator {
    
        public void setupCustomDataContentHandlers() {
    
            DataHandler.setDataContentHandlerFactory(new CustomDCHFactory());
        }
    
        private class CustomDCHFactory implements DataContentHandlerFactory {
    
            @Override
            public DataContentHandler createDataContentHandler(String mimeType) {
    
                return new BinaryDataHandler();
            }
        }
    
        private class BinaryDataHandler implements DataContentHandler {
    
            /** Creates a new instance of BinaryDataHandler */
            public BinaryDataHandler() {
    
            }
    
            /** This is the key, it just returns the data uninterpreted. */
            public Object getContent(javax.activation.DataSource dataSource) throws java.io.IOException {
    
                    return dataSource.getInputStream();
            }
    
            public Object getTransferData(java.awt.datatransfer.DataFlavor dataFlavor, 
                                 javax.activation.DataSource dataSource) 
                                  throws java.awt.datatransfer.UnsupportedFlavorException, 
           java.io.IOException {
    
                    return null;
            }
    
            public java.awt.datatransfer.DataFlavor[] getTransferDataFlavors() {
    
                return new java.awt.datatransfer.DataFlavor[0];
            }
    
            public void writeTo(Object obj, String mimeType, java.io.OutputStream outputStream) 
             throws java.io.IOException {
    
                    if (mimeType == "text/plain") {
                        byte[] stringByte = (byte[]) ((String) obj).getBytes("UTF-8");
                        outputStream.write(stringByte);
                    }
                    else {
                        throw new IOException("Unsupported Data Type: " + mimeType);
                    }
            }
        }  
    }