¿Cuál es la diferencia entre Class.getResource () y ClassLoader.getResource ()?

Me pregunto cuál es la diferencia entre Class.getResource() y ClassLoader.getResource() ?

editar: Especialmente quiero saber si hay algún almacenamiento en caché involucrado en el nivel de archivo / directorio. Como en “¿los listados de directorios están almacenados en caché en la versión Class?”

AFAIK lo siguiente esencialmente debería hacer lo mismo, pero no lo son:

 getClass().getResource() getClass().getClassLoader().getResource() 

Descubrí esto cuando jugueteaba con algún código de generación de informes que crea un nuevo archivo en WEB-INF/classes/ desde un archivo existente en ese directorio. Al usar el método de Class, pude encontrar los archivos que estaban allí en la implementación usando getClass().getResource() , pero cuando getClass().getResource() de recuperar el archivo recién creado, recibí un objeto nulo. La navegación por el directorio muestra claramente que el nuevo archivo está allí. Los nombres de archivo fueron precedidos por una barra inclinada como en “/myFile.txt”.

La versión ClassLoader de getResource() por otro lado, encontró el archivo generado. A partir de esta experiencia, parece que hay algún tipo de almacenamiento en caché de la lista de directorios en curso. Estoy en lo correcto, y si es así, ¿dónde está esto documentado?

De los documentos de API en Class.getResource()

Encuentra un recurso con un nombre de stack. Las reglas para buscar recursos asociados con una clase dada son implementadas por el cargador de clase de definición de la clase. Este método delega en el cargador de clases de este objeto. Si este objeto fue cargado por el cargador de clases de arranque, el método se delega en ClassLoader.getSystemResource (java.lang.String).

Para mí, esto dice “Class.getResource realmente está llamando a getResource () de su propio cargador de clases. Lo cual sería lo mismo que hacer getClass().getClassLoader().getResource() . Pero obviamente no es así. ¿Podría alguien darme alguna información sobre este asunto?

Para responder a la pregunta de si hay algún almacenamiento en caché.

Investigué más este punto ejecutando una aplicación Java autónoma que cargó continuamente un archivo desde el disco utilizando el método getResourceAsStream ClassLoader. Pude editar el archivo y los cambios se reflejaron de inmediato, es decir, el archivo se volvió a cargar desde el disco sin almacenamiento en caché.

Sin embargo: estoy trabajando en un proyecto con varios módulos Maven y proyectos web que tienen dependencias entre ellos. Estoy usando IntelliJ como mi IDE para comstackr y ejecutar proyectos web.

Noté que lo anterior parecía no ser cierto, la razón es que el archivo que estaba cargando ahora está procesado en un contenedor y se implementó en el proyecto web dependiente. Solo me di cuenta de esto después de intentar cambiar el archivo en mi carpeta de destino, pero fue en vano. Esto hizo que pareciera que estaba pasando el almacenamiento en caché.

Class.getResource puede tomar un nombre de recurso “relativo”, que se trata en relación con el paquete de la clase. Alternativamente, puede especificar un nombre de recurso “absoluto” utilizando una barra diagonal. Las rutas de recursos de ClassLoader siempre se consideran absolutas.

Entonces los siguientes son básicamente equivalentes:

 foo.bar.Baz.class.getResource("xyz.txt"); foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt"); 

Y también lo son (pero son diferentes de los anteriores):

 foo.bar.Baz.class.getResource("/data/xyz.txt"); foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt"); 

La primera llamada busca en relación con el archivo .class , mientras que la última busca en relación con la raíz de la ruta de clase.

Para depurar problemas como ese, imprimo la URL:

 System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") ); 

Tuve que buscarlo en las especificaciones:

  • Class.getResource (recurso de cadena)

  • ClassLoader.getResource (recurso de cadena)

Class getResource () – la documentación establece la diferencia:

Este método delega la llamada a su cargador de clases, después de realizar estos cambios en el nombre del recurso: si el nombre del recurso comienza con “/”, no se modifica; de lo contrario, el nombre del paquete se antepone al nombre del recurso después de convertir “.” a “/”. Si este objeto fue cargado por el cargador de arranque, la llamada se delega a ClassLoader.getSystemResource.

Todas estas respuestas aquí, así como las respuestas en esta pregunta , sugieren que la carga de URL absolutas, como “/foo/bar.properties”, es tratada de la misma manera por class.getResourceAsStream(String) y class.getClassLoader().getResourceAsStream(String) Este NO es el caso, al menos no en mi configuración / versión de Tomcat (actualmente 7.0.40).

 MyClass.class.getResourceAsStream("/foo/bar.properties"); // works! MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work! 

Lo siento, no tengo ninguna explicación satisfactoria, pero supongo que Tomcat hace trucos sucios y su magia negra con los cargadores de clases y causa la diferencia. Siempre utilicé class.getResourceAsStream(String) en el pasado y no he tenido ningún problema.

PD: también publiqué esto aquí

Class.getResources recuperaría el recurso mediante el cargador de clases que carga el objeto. Mientras que ClassLoader.getResource recuperaría el recurso utilizando el cargador de clases especificado.

Intenté leer desde input1.txt que estaba dentro de uno de mis paquetes junto con la clase que intentaba leerlo.

Los siguientes trabajos:

 String fileName = FileTransferClient.class.getResource("input1.txt").getPath(); System.out.println(fileName); BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName)); 

La parte más importante era llamar a getPath() si desea el nombre de ruta correcto en formato de cadena. NO UTILIZAR toString() porque agregará un texto de formato adicional que TOTALMENTE MEJORARÁ el nombre del archivo (puede probarlo y ver la impresión).

Pasé 2 horas depurando esto … 🙁