Wednesday, January 7, 2009

What does Java 6 have against image/png?

In mapping from filenames to mime types, I've typically used Java Activation Framework's MimetypeFileTypeMap.  Leaving aside the fact that the code for this class (and possibly most of JAF) is pretty old and ugly, it mostly works.  Today, however, we discovered that it was giving us application/octet-stream for a ".png" file, and I decided to dig a little deeper.


I started by reading the docs, and checking the mimetypes.default included in activation-1.1.jar/META-INF, which seems to include png and PNG.  I turned on just enough logging for JAF to spit out what files it was loading and what information it got from each:

@Test
public void testPng() {
System.setProperty( "javax.activation.debug", "true" );
Logger logger = Logger.getLogger( "javax.activation" );
logger.setLevel( Level.FINEST );
logger.addHandler( new ConsoleHandler() );
MimetypesFileTypeMap map = new MimetypesFileTypeMap();
Assert.assertEquals( "image/png", map.getContentType( "myImage.png" ) );
}
That told me that JAF could only find the mimetypes.default, but that it believed png wasn't in the file:


MimetypesFileTypeMap: load HOME
MimetypesFileTypeMap: load SYS
MimetypesFileTypeMap: load JAR
MimetypesFileTypeMap: !anyLoaded
MimetypesFileTypeMap: not loading mime types file: /META-INF/mime.types
MimetypesFileTypeMap: load DEF
Added: MIMETypeEntry: text/html, html
Added: MIMETypeEntry: text/html, htm
Added: MIMETypeEntry: text/html, HTML
Added: MIMETypeEntry: text/html, HTM
Added: MIMETypeEntry: text/plain, txt
Added: MIMETypeEntry: text/plain, text
Added: MIMETypeEntry: text/plain, TXT
Added: MIMETypeEntry: text/plain, TEXT
Added: MIMETypeEntry: image/gif, gif
Added: MIMETypeEntry: image/gif, GIF
Added: MIMETypeEntry: image/ief, ief
Added: MIMETypeEntry: image/jpeg, jpeg
Added: MIMETypeEntry: image/jpeg, jpg
Added: MIMETypeEntry: image/jpeg, jpe
Added: MIMETypeEntry: image/jpeg, JPG
Added: MIMETypeEntry: image/tiff, tiff
Added: MIMETypeEntry: image/tiff, tif
Added: MIMETypeEntry: image/x-xwindowdump, xwd
Added: MIMETypeEntry: application/postscript, ai
Added: MIMETypeEntry: application/postscript, eps
Added: MIMETypeEntry: application/postscript, ps
Added: MIMETypeEntry: application/rtf, rtf
Added: MIMETypeEntry: application/x-tex, tex
Added: MIMETypeEntry: application/x-texinfo, texinfo
Added: MIMETypeEntry: application/x-texinfo, texi
Added: MIMETypeEntry: application/x-troff, t
Added: MIMETypeEntry: application/x-troff, tr
Added: MIMETypeEntry: application/x-troff, roff
Added: MIMETypeEntry: audio/basic, au
Added: MIMETypeEntry: audio/midi, midi
Added: MIMETypeEntry: audio/midi, mid
Added: MIMETypeEntry: audio/x-aifc, aifc
Added: MIMETypeEntry: audio/x-aiff, aif
Added: MIMETypeEntry: audio/x-aiff, aiff
Added: MIMETypeEntry: audio/x-mpeg, mpeg
Added: MIMETypeEntry: audio/x-mpeg, mpg
Added: MIMETypeEntry: audio/x-wav, wav
Added: MIMETypeEntry: video/mpeg, mpeg
Added: MIMETypeEntry: video/mpeg, mpg
Added: MIMETypeEntry: video/mpeg, mpe
Added: MIMETypeEntry: video/quicktime, qt
Added: MIMETypeEntry: video/quicktime, mov
Added: MIMETypeEntry: video/x-msvideo, avi
MimetypesFileTypeMap: successfully loaded mime types file: /META-INF/mimetypes.default
That implied to me that there was another mimetypes.default available, which a quick classloader test shows to be true:

@Test
public void testDefaultResource() throws IOException {
System.out.println( "Displaying default resources: " );
int index = 1;
Enumeration resources = Thread.currentThread().getContextClassLoader().getResources( "META-INF/mimetypes.default" );
while( resources.hasMoreElements() ) {
URL item = resources.nextElement();
System.out.printf( "\t%d: %s\n", index++, item );
}
System.out.println( "Done printing resources." );
}
Turns out, the other mimetypes.default is coming from Java 6 (update 4) resources.jar, which inexplicably doesn't include an image/png content type:


Displaying default resources:
1: jar:file:.../jre1.6.0_04/lib/resources.jar!/META-INF/mimetypes.default
2: jar:file:.../m2_repo/javax/activation/activation/1.1/activation-1.1.jar!/META-INF/mimetypes.default
Done printing resources.

Since activation 1.1's been out for a long time, I can't think of a good reason why image/png would be missing from a relatively modern JRE.

As always, in order to hedge against running into this again and help anyone else who might hit the same issue, thought it was worth writing down.

3 comments:

Anonymous said...

Thanks from Germany for writing this down!

Niklas said...

Thanks! Saved me a lot of time!

Grégory Oliver said...

The solution is to declare your own mimetype file :

Programmatically added entries to the MimetypesFileTypeMap instance.
The file .mime.types in the user's home directory.
The file /lib/mime.types.
The file or resources named META-INF/mime.types.
The file or resource named META-INF/mimetypes.default (usually found only in the activation.jar file).

source : http://www.rgagnon.com/javadetails/java-0487.html