Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ImageIO.getImageWriter(reader) not working inside tomcat #16

Closed
danieledepetrini opened this issue Nov 5, 2013 · 6 comments
Closed

Comments

@danieledepetrini
Copy link

Hello Harald,

I wrote a basic test code that does work in a standalone test class:

public class Test
{

public static void main(String[] arg)
{
    try
    {
        ImageInputStream iis = ImageIO.createImageInputStream(new FileInputStream(arg[0]));
        Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
        if (!readers.hasNext())
            throw new IOException("can't decode this image inputstream");

        ImageReader reader = readers.next();
        ImageReadParam param = reader.getDefaultReadParam();
        reader.setInput(iis, true, true);
        BufferedImage img = reader.read(0, param);

        ImageWriter writer = ImageIO.getImageWriter(reader);

        if (writer == null)
            throw new IOException("can't find writer, reader provider: " + reader.getOriginatingProvider());

        System.out.println("Writer: " + writer.getClass());
    }
    catch (Throwable t)
    {
        t.printStackTrace();
    }
}

}

The same code doesn't work inside a tomcat webapp, writer is null so an exception is thrown.

I have:

  • added the listener as described in the guide
  • fixed class name typos inside JPEGImageWriterSpi (class names were not starting with "com"

I have verified with a test loop that the ImageWriter is loaded:

static
{
    System.out.println("ImageIO, looking for writers");

    Iterator<ImageWriter> ite = ImageIO.getImageWritersByFormatName("jpeg");

    while (ite.hasNext())
        System.out.println("ImageIO writer: " + ite.next().getClass());
}

And the result:

logs/catalina.out:ImageIO, looking for writers
logs/catalina.out:ImageIO writer: class com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageWriter
logs/catalina.out:ImageIO writer: class com.sun.imageio.plugins.jpeg.JPEGImageWriter

Any idea about why is not working just inside tomcat? How to debug further?

Thanks,

Daniele.

@haraldk
Copy link
Owner

haraldk commented Nov 5, 2013

I guess you have already tried, but if not, restart Tomcat. :-)
Just to make sure all old instances and classes are gone and the VM is fresh.

Are your using the same JRE for both Tomcat and the standalone app?

Other than that, it's quite hard to tell what's going on without access to the Tomcat server. I assume when you say "inside a tomcat webapp" you mean a Servlet or Filter? If not, please describe how...

My best suggestion is to use a debugger, and step through the code (both in Tomcat and the standalone app), to see what's going on, and look for any differences.

@haraldk
Copy link
Owner

haraldk commented Nov 5, 2013

Just a quick follow-up:

I looked at the source code for ImageIO.getImageWriter(ImageReader reader) and I don't think it can work in a servlet context.

It contains the following code (JDK 1.7.0u45 source):

    String[] writerNames = readerSpi.getImageWriterSpiNames();
    if (writerNames == null) {
        return null;
    }

    Class writerSpiClass = null;
    try {
        writerSpiClass = Class.forName(writerNames[0], true,
                                       ClassLoader.getSystemClassLoader()); // <-- This class loader is the culprit
    } catch (ClassNotFoundException e) {
        return null;
    }

For some reason (a bad one?) it uses the system class loader, and it will never have access to the web app local classes/JARs.

You should probably file a bug against the Java class libraries on this.

The workaround is to manually look it up, using code similar to what ImageIO uses, but use the context class loader (Thread.currentThread().getContextClassLoader()) instead, to have access to web app local classes.

Alternatively, add JARs to Tomcats shared or common libs folder, that might help.

@haraldk haraldk closed this as completed Nov 5, 2013
@haraldk haraldk reopened this Nov 5, 2013
@danieledepetrini
Copy link
Author

Using the context class loader in a custom method solved the issue, thanks! It look like a JDK issue, but opening bugs with them is like tilting at windmills :-)

jessieZZZZ pushed a commit to jessieZZZZ/TwelveMonkeys that referenced this issue Jul 6, 2017
@kkofler
Copy link

kkofler commented Aug 30, 2017

If, like me, you are still stumbling upon this old issue, and wonder what the best fix/workaround is these days:

  • You want to use the com.twelvemonkeys.servlet.image.IIOProviderContextListener (that is documented on the https://haraldk.github.io/TwelveMonkeys/ front page under "Deploying the plugins in a web app").
  • To use this in a Maven project, you need this additional dependency:
    <dependency>
      <groupId>com.twelvemonkeys.servlet</groupId>
      <artifactId>servlet</artifactId>
      <version>3.3.2</version>
    </dependency>
  • To use it in a Spring Boot project without a web.xml file, you want to add the following line to the onStartup method in your SpringBootServletInitializer subclass:
servletContext.addListener(IIOProviderContextListener.class);

of course with the following import:

import com.twelvemonkeys.servlet.image.IIOProviderContextListener;

With this, the standard ImageIO classes just work and you do not have to manually load any classes.

I hope this helps.

@stephanie-dm
Copy link

It would be great if @kkofler 's solution could be added to the documentation, because I think it costs people some time to find this...

@haraldk
Copy link
Owner

haraldk commented Apr 26, 2021

@stephanie-dm It certainly can! 😀

Why not create a PR against README.md, and add the details about the dependency and Spring boot in the relevant section?

--
Harald K

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants