diff --git a/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java b/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java index 70fc8a83e6..dacfb011ad 100644 --- a/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,9 +50,9 @@ public class ClassPathResource extends AbstractFileResolvingResource { /** - * Create a new ClassPathResource for ClassLoader usage. - * A leading slash will be removed, as the ClassLoader - * resource access methods will not accept it. + * Create a new {@code ClassPathResource} for {@code ClassLoader} usage. + * A leading slash will be removed, as the ClassLoader resource access + * methods will not accept it. *
The thread context class loader will be used for * loading the resource. * @param path the absolute path within the class path @@ -64,9 +64,9 @@ public class ClassPathResource extends AbstractFileResolvingResource { } /** - * Create a new ClassPathResource for ClassLoader usage. - * A leading slash will be removed, as the ClassLoader - * resource access methods will not accept it. + * Create a new {@code ClassPathResource} for {@code ClassLoader} usage. + * A leading slash will be removed, as the ClassLoader resource access + * methods will not accept it. * @param path the absolute path within the classpath * @param classLoader the class loader to load the resource with, * or {@code null} for the thread context class loader @@ -83,9 +83,9 @@ public class ClassPathResource extends AbstractFileResolvingResource { } /** - * Create a new ClassPathResource for Class usage. - * The path can be relative to the given class, - * or absolute within the classpath via a leading slash. + * Create a new {@code ClassPathResource} for {@code Class} usage. + * The path can be relative to the given class, or absolute within + * the classpath via a leading slash. * @param path relative or absolute path within the class path * @param clazz the class to load resources with * @see java.lang.Class#getResourceAsStream @@ -97,8 +97,8 @@ public class ClassPathResource extends AbstractFileResolvingResource { } /** - * Create a new ClassPathResource with optional ClassLoader and Class. - * Only for internal usage. + * Create a new {@code ClassPathResource} with optional {@code ClassLoader} + * and {@code Class}. Only for internal usage. * @param path relative or absolute path within the classpath * @param classLoader the class loader to load the resource with, if any * @param clazz the class to load resources with, if any @@ -109,6 +109,7 @@ public class ClassPathResource extends AbstractFileResolvingResource { this.clazz = clazz; } + /** * Return the path for this resource (as resource path within the class path). */ @@ -120,9 +121,10 @@ public class ClassPathResource extends AbstractFileResolvingResource { * Return the ClassLoader that this resource will be obtained from. */ public final ClassLoader getClassLoader() { - return (this.classLoader != null ? this.classLoader : this.clazz.getClassLoader()); + return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader); } + /** * This implementation checks for the resolution of a resource URL. * @see java.lang.ClassLoader#getResource(String) @@ -130,14 +132,23 @@ public class ClassPathResource extends AbstractFileResolvingResource { */ @Override public boolean exists() { - URL url; + return (resolveURL() != null); + } + + /** + * Resolves a URL for the underlying class path resource. + * @return the resolved URL, or {@code null} if not resolvable + */ + protected URL resolveURL() { if (this.clazz != null) { - url = this.clazz.getResource(this.path); + return this.clazz.getResource(this.path); + } + else if (this.classLoader != null) { + return this.classLoader.getResource(this.path); } else { - url = this.classLoader.getResource(this.path); + return ClassLoader.getSystemResource(this.path); } - return (url != null); } /** @@ -151,9 +162,12 @@ public class ClassPathResource extends AbstractFileResolvingResource { if (this.clazz != null) { is = this.clazz.getResourceAsStream(this.path); } - else { + else if (this.classLoader != null) { is = this.classLoader.getResourceAsStream(this.path); } + else { + is = ClassLoader.getSystemResourceAsStream(this.path); + } if (is == null) { throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist"); } @@ -161,19 +175,14 @@ public class ClassPathResource extends AbstractFileResolvingResource { } /** - * This implementation returns a URL for the underlying class path resource. + * This implementation returns a URL for the underlying class path resource, + * if available. * @see java.lang.ClassLoader#getResource(String) * @see java.lang.Class#getResource(String) */ @Override public URL getURL() throws IOException { - URL url; - if (this.clazz != null) { - url = this.clazz.getResource(this.path); - } - else { - url = this.classLoader.getResource(this.path); - } + URL url = resolveURL(); if (url == null) { throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist"); } diff --git a/spring-core/src/main/java/org/springframework/core/io/ResourceLoader.java b/spring-core/src/main/java/org/springframework/core/io/ResourceLoader.java index 958746178f..b753535ab0 100644 --- a/spring-core/src/main/java/org/springframework/core/io/ResourceLoader.java +++ b/spring-core/src/main/java/org/springframework/core/io/ResourceLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -70,7 +70,9 @@ public interface ResourceLoader { *
Clients which need to access the ClassLoader directly can do so
* in a uniform manner with the ResourceLoader, rather than relying
* on the thread context ClassLoader.
- * @return the ClassLoader (never {@code null})
+ * @return the ClassLoader (only {@code null} if even the system
+ * ClassLoader isn't accessible)
+ * @see org.springframework.util.ClassUtils#getDefaultClassLoader()
*/
ClassLoader getClassLoader();
diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
index 1def34100a..6eeef89270 100644
--- a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
+++ b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -229,7 +229,8 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
/**
* Return the ClassLoader that this pattern resolver works with
- * (never {@code null}).
+ * (only {@code null} if even the system ClassLoader isn't accessible).
+ * @see org.springframework.util.ClassUtils#getDefaultClassLoader()
*/
@Override
public ClassLoader getClassLoader() {
@@ -301,7 +302,8 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
if (path.startsWith("/")) {
path = path.substring(1);
}
- Enumeration Call this method if you intend to use the thread context ClassLoader
- * in a scenario where you absolutely need a non-null ClassLoader reference:
+ * in a scenario where you clearly prefer a non-null ClassLoader reference:
* for example, for class path resource loading (but not necessarily for
* {@code Class.forName}, which accepts a {@code null} ClassLoader
* reference as well).
- * @return the default ClassLoader (never {@code null})
+ * @return the default ClassLoader (only {@code null} if even the system
+ * ClassLoader isn't accessible)
* @see Thread#getContextClassLoader()
+ * @see ClassLoader#getSystemClassLoader()
*/
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
@@ -155,11 +157,20 @@ public abstract class ClassUtils {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
- // Cannot access thread context ClassLoader - falling back to system class loader...
+ // Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
+ if (cl == null) {
+ // getClassLoader() returning null indicates the bootstrap ClassLoader
+ try {
+ cl = ClassLoader.getSystemClassLoader();
+ }
+ catch (Throwable ex) {
+ // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
+ }
+ }
}
return cl;
}
@@ -185,7 +196,7 @@ public abstract class ClassUtils {
/**
* Replacement for {@code Class.forName()} that also returns Class instances
- * for primitives (e.g."int") and array class names (e.g. "String[]").
+ * for primitives (e.g. "int") and array class names (e.g. "String[]").
* Furthermore, it is also capable of resolving inner class names in Java source
* style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State").
* @param name the name of the Class
@@ -228,19 +239,19 @@ public abstract class ClassUtils {
return Array.newInstance(elementClass, 0).getClass();
}
- ClassLoader classLoaderToUse = classLoader;
- if (classLoaderToUse == null) {
- classLoaderToUse = getDefaultClassLoader();
+ ClassLoader clToUse = classLoader;
+ if (clToUse == null) {
+ clToUse = getDefaultClassLoader();
}
try {
- return classLoaderToUse.loadClass(name);
+ return (clToUse != null ? clToUse.loadClass(name) : Class.forName(name));
}
catch (ClassNotFoundException ex) {
int lastDotIndex = name.lastIndexOf('.');
if (lastDotIndex != -1) {
String innerClassName = name.substring(0, lastDotIndex) + '$' + name.substring(lastDotIndex + 1);
try {
- return classLoaderToUse.loadClass(innerClassName);
+ return (clToUse != null ? clToUse.loadClass(innerClassName) : Class.forName(innerClassName));
}
catch (ClassNotFoundException ex2) {
// swallow - let original exception get through
diff --git a/spring-core/src/main/java/org/springframework/util/ResourceUtils.java b/spring-core/src/main/java/org/springframework/util/ResourceUtils.java
index 8ab4f5bba5..54d07645b0 100644
--- a/spring-core/src/main/java/org/springframework/util/ResourceUtils.java
+++ b/spring-core/src/main/java/org/springframework/util/ResourceUtils.java
@@ -116,7 +116,8 @@ public abstract class ResourceUtils {
Assert.notNull(resourceLocation, "Resource location must not be null");
if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length());
- URL url = ClassUtils.getDefaultClassLoader().getResource(path);
+ ClassLoader cl = ClassUtils.getDefaultClassLoader();
+ URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
if (url == null) {
String description = "class path resource [" + path + "]";
throw new FileNotFoundException(
@@ -156,7 +157,8 @@ public abstract class ResourceUtils {
if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length());
String description = "class path resource [" + path + "]";
- URL url = ClassUtils.getDefaultClassLoader().getResource(path);
+ ClassLoader cl = ClassUtils.getDefaultClassLoader();
+ URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
if (url == null) {
throw new FileNotFoundException(
description + " cannot be resolved to absolute file path " +