Why is getResourceAsStream returning null?

こ雲淡風輕ζ 提交于 2019-12-11 15:24:09

问题


I have an image inside my jar which I am trying to load, but getResourceAsStream() always returns null.

Directory structure:

com/thesimpzone/watch_pugs/watch_pugs/{all my class files}
META-INF/MANIFEST.MF
resources/generic/mouse.png

Content.java:

public abstract class Content {

    protected Map<String, BufferedImage> images = new HashMap<String, BufferedImage>();

    protected String prefix;

    public Content(String prefix){
        this.prefix = prefix;
    }

    protected void loadImage(String name){
        System.out.println(name);
        System.out.println(prefix);
        String path = (prefix + name);
        System.out.println(path);
        String identifier = name.substring(0, name.lastIndexOf("."));
        try{
            InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
            images.put(identifier, ImageIO.read(in));
        }catch(IOException | ClassCastException e){
            throw new RuntimeException("Image " + identifier + " at " + path + " could not be loaded.");
        }
    }
    [...]
}

GenericContent.java:

public class GenericContent extends Content {

    public GenericContent(){
        super("resources/generic/");
        this.loadContent();
    }

    @Override
    public void loadContent() {
        loadImage("mouse.png");
    }

}

StackTrace:

mouse.png
resources/generic/
resources/generic/mouse.png
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: input == null!
    at javax.imageio.ImageIO.read(ImageIO.java:1348)
    at com.thesimpzone.watch_pugs.watch_pugs.content.Content.loadImage(Content.java:29)
    at com.thesimpzone.watch_pugs.watch_pugs.content.GenericContent.loadContent(GenericContent.java:17)
    at com.thesimpzone.watch_pugs.watch_pugs.content.GenericContent.<init>(GenericContent.java:12)
    at com.thesimpzone.watch_pugs.watch_pugs.Canvas.<init>(Canvas.java:45)
    at com.thesimpzone.watch_pugs.watch_pugs.Framework.<init>(Framework.java:75)
    at com.thesimpzone.watch_pugs.watch_pugs.Window.<init>(Window.java:50)
    at com.thesimpzone.watch_pugs.watch_pugs.Window.<init>(Window.java:26)
    at com.thesimpzone.watch_pugs.watch_pugs.Window$1.run(Window.java:60)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:744)
    at java.awt.EventQueue.access$400(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:697)
    at java.awt.EventQueue$3.run(EventQueue.java:691)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:714)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

I have no idea why the classloader can't find the image. I have looked in the compiled jar and the file is there, and opens fine in paint so the file is OK. I have tried various ClassLoader variations, including getSystemClassLoader(), getClassLoader(), and Content.class.getClassLoader(); and also getResourceAsStream(path) instead of getResource(path).openStream(). I have tried with and without the leading '/' on the prefix, so I'm all out of ideas and Google isn't helping. Also, it seems like what I'm doing to define 'prefix' is very awkward and so if there is a better way I would be glad if someone showed me how.

Thanks.


回答1:


It is all about relative vs absolute packages when calling getResourceAsStream(), you looking for something relative to whatever package Content is at as the root.

there are no "directories" on the classpath, especially inside .jar files, only packages

The best thing to use is Thread.currentThread().getContextClassloader().getResourceAsStream() with a fully qualified package without the leading /.

The reason this is best is because inside of application containers, they usually have multiple classloaders and this way you don't have to care which one your resource is loaded from.

In your case:

Thread.currentThread().getContextClassloader().getResourceAsStream("resources/generic/mouse.png");

If you still get an error with this approach your .jar isn't built like you think it is or if you are getting this from inside an IDE you probably aren't copying the contents resource/generic/ into the classpath.

Personally I always use the form:

Thread.currentThread().getContextClassLoader().getResourceAsStream("path/to/resource/file.ext"); as it always works from where ever you call it and whatever classloader you are in, and it is explicit about where it is looking to find what it is looking for.



来源:https://stackoverflow.com/questions/26327430/why-is-getresourceasstream-returning-null

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!