web-dev-qa-db-fra.com

Comportement étrange de Class.getResource () et ClassLoader.getResource () dans un pot exécutable

Je comprends de Quelle est la différence entre Class.getResource () et ClassLoader.getResource ()? et de son propre code, que

getClass().getResource("/path/image.png")

est identique à

getClass().getClassLoader().getResource("path/image.png")

La publication Impossible de lire une image dans le fichier jar montre un problème où l'utilisation

getClass().getClassLoader().getResource("path/image.png")

dans un fichier jar exécutable renvoie null, tandis que

getClass().getResource("/path/image.png")

renvoie l'URL correcte.

Since Class.getResource() délègue à ClassLoader.getResource() après avoir supprimé la barre oblique, je m'attendrais à ce que ces appels soient identiques, mais évidemment ils ne le sont pas dans ce cas. Même lorsqu'un chargeur de classe spécial est attaché à la classe particulière, il doit toujours être le même pour chaque appel, ce qui entraîne à nouveau le même comportement.

Donc, la question est: y a-t-il des circonstances évidentes dans lesquelles le code suivant retourne null pour le premier appel mais l'URL appropriée pour le deuxième appel?

package com.example;

import Java.net.URL;

public class ResourceTest {

   public void run() {
      URL iconUrl1 = getClass().getClassLoader().getResource("path/image.png");
      System.out.println("ClassLoader.getResource(\"path/image.png\"): " + iconUrl1);

      URL iconUrl2 = getClass().getResource("/path/image.png");
      System.out.println("Class.getResource(\"/path/image.png\"): " + iconUrl2);
   }

   public static void main(String[] args) {
      ResourceTest app = new ResourceTest();
      app.run();
   }
}
34
Andreas Fester

Je pensais que cette question avait déjà été posée et a répondu!

getClass().getResource() recherche par rapport au fichier .class tandis que getClass().getClassLoader().getResource() recherche par rapport à la racine du chemin de classe.

S'il y a un SSCCE ici, je ne comprends pas pourquoi il ne le fait pas

1) Affichez l'organisation du répertoire dans le .jar et ...

2) Prendre en considération le package

Q: Qu'est-ce (le cas échéant) qui n'a pas déjà été répondu par Quelle est la différence entre Class.getResource () et ClassLoader.getResource ()? (et les liens qu'il cite)?

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

Je ne sais toujours pas ce qui n'est pas clair, mais cet exemple pourrait aider:

/*
  SAMPLE OUTPUT:
  ClassLoader.getResource(/subdir/readme.txt): NULL
  Class.getResource(/subdir/readme.txt): SUCCESS

  ClassLoader.getResource(subdir/readme.txt): SUCCESS
  Class.getResource(subdir/readme.txt): NULL
 */
package com.so.resourcetest;

import Java.net.URL;

public class ResourceTest {

    public static void main(String[] args) {
        ResourceTest app = new ResourceTest ();
    }

    public ResourceTest () {
        doClassLoaderGetResource ("/subdir/readme.txt");
        doClassGetResource ("/subdir/readme.txt");
        doClassLoaderGetResource ("subdir/readme.txt");
        doClassGetResource ("subdir/readme.txt");
    }

    private void doClassLoaderGetResource (String sPath) {
        URL url  = getClass().getClassLoader().getResource(sPath);
        if (url == null)
            System.out.println("ClassLoader.getResource(" + sPath + "): NULL");
        else
            System.out.println("ClassLoader.getResource(" + sPath + "): SUCCESS");
    }

    private void doClassGetResource (String sPath) {
        URL url  = getClass().getResource(sPath);
        if (url == null)
            System.out.println("Class.getResource(" + sPath + "): NULL");
        else
            System.out.println("Class.getResource(" + sPath + "): SUCCESS");
    }
}

Voici l'arborescence de répertoires correspondante. Il se trouve que c'est un projet Eclipse, mais les répertoires sont les mêmes, que ce soit Eclipse, Netbeans ... ou un fichier .jar:

C:.
├───.settings
├───bin
│   ├───com
│   │   └───so
│   │       └───resourcetest
│   └───subdir
└───src
    ├───com
    │   └───so
    │       └───resourcetest
    └───subdir

Le fichier en cours d'ouverture est "subdir/readme.txt"


ADDENDA 11/9/12:

Salut -

J'ai copié votre code textuellement depuis github, recompilé et relancé:

ClassLoader.getResource(/subdir/readme.txt): NULL
Class.getResource(/subdir/readme.txt): SUCCESS
ClassLoader.getResource(subdir/readme.txt): SUCCESS
Class.getResource(subdir/readme.txt): NULL

Si c'est pas la sortie que vous obtenez ... Je suis déconcerté.

Pour tout ce que ça vaut, je cours:

  • Eclipse Indigo (cela ne devrait pas avoir d'importance)

  • Exécution à l'intérieur de IDE (peu importe que ce soit un système de fichiers ou .jar, à l'intérieur ou à l'extérieur d'un IDE)

  • Mon JRE est de 1,6 (si quoi que ce soit, c'est probablement le biggie)

Désolé, nous n'avons pas réussi à résoudre ce que je pensais était un problème simple :(


ADDENDA 21/11/12 (Andreas):

Puisqu'il n'y a eu aucune activité récente sur cette question, je voudrais résumer ce que nous avons constaté:

  • D'après notre compréhension commune, la réponse à la question ci-dessus est: "Non, il n'est pas possible que Class.getResource("/path/image.png") renvoie une URL valide, tandis que ClassLoader.getResource("path/image.png") renvoie null ":
    • Nous savons parfaitement la différence entre ClassLoader.getResource () et Class.getResource ()
    • Nos échantillons de sortie correspondent, pour "SUCCESS" et pour "null"
    • Les sorties d'échantillons correspondent à ce que nous attendons
    • Conclusion: Soit nous avons supervisé quelque chose, soit quelque chose de différent a fait fonctionner la "solution" décrite dans la question liée. Je pense que nous ne pouvons pas actuellement prouver l'un ou l'autre.
39
paulsm4