Fix regression in ClassPathResource descriptions
ClassPathResource.getDescription() now returns consistent, meaningful results for all variants of ClassPathResource's constructors. Issue: SPR-9413
This commit is contained in:
		
							parent
							
								
									500a4dd995
								
							
						
					
					
						commit
						b50f6e19a6
					
				|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2010 the original author or authors. |  * Copyright 2002-2012 the original author or authors. | ||||||
|  * |  * | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with the License. |  * you may not use this file except in compliance with the License. | ||||||
|  | @ -35,6 +35,7 @@ import org.springframework.util.StringUtils; | ||||||
|  * Always supports resolution as URL. |  * Always supports resolution as URL. | ||||||
|  * |  * | ||||||
|  * @author Juergen Hoeller |  * @author Juergen Hoeller | ||||||
|  |  * @author Sam Brannen | ||||||
|  * @since 28.12.2003 |  * @since 28.12.2003 | ||||||
|  * @see java.lang.ClassLoader#getResourceAsStream(String) |  * @see java.lang.ClassLoader#getResourceAsStream(String) | ||||||
|  * @see java.lang.Class#getResourceAsStream(String) |  * @see java.lang.Class#getResourceAsStream(String) | ||||||
|  | @ -108,7 +109,6 @@ public class ClassPathResource extends AbstractFileResolvingResource { | ||||||
| 		this.clazz = clazz; | 		this.clazz = clazz; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Return the path for this resource (as resource path within the class path). | 	 * Return the path for this resource (as resource path within the class path). | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -123,7 +123,6 @@ public class ClassPathResource extends AbstractFileResolvingResource { | ||||||
| 		return (this.classLoader != null ? this.classLoader : this.clazz.getClassLoader()); | 		return (this.classLoader != null ? this.classLoader : this.clazz.getClassLoader()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	/** | 	/** | ||||||
| 	 * This implementation checks for the resolution of a resource URL. | 	 * This implementation checks for the resolution of a resource URL. | ||||||
| 	 * @see java.lang.ClassLoader#getResource(String) | 	 * @see java.lang.ClassLoader#getResource(String) | ||||||
|  | @ -155,8 +154,7 @@ public class ClassPathResource extends AbstractFileResolvingResource { | ||||||
| 			is = this.classLoader.getResourceAsStream(this.path); | 			is = this.classLoader.getResourceAsStream(this.path); | ||||||
| 		} | 		} | ||||||
| 		if (is == null) { | 		if (is == null) { | ||||||
| 			throw new FileNotFoundException( | 			throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist"); | ||||||
| 					getDescription() + " cannot be opened because it does not exist"); |  | ||||||
| 		} | 		} | ||||||
| 		return is; | 		return is; | ||||||
| 	} | 	} | ||||||
|  | @ -176,8 +174,7 @@ public class ClassPathResource extends AbstractFileResolvingResource { | ||||||
| 			url = this.classLoader.getResource(this.path); | 			url = this.classLoader.getResource(this.path); | ||||||
| 		} | 		} | ||||||
| 		if (url == null) { | 		if (url == null) { | ||||||
| 			throw new FileNotFoundException( | 			throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist"); | ||||||
| 					getDescription() + " cannot be resolved to URL because it does not exist"); |  | ||||||
| 		} | 		} | ||||||
| 		return url; | 		return url; | ||||||
| 	} | 	} | ||||||
|  | @ -209,17 +206,22 @@ public class ClassPathResource extends AbstractFileResolvingResource { | ||||||
| 	public String getDescription() { | 	public String getDescription() { | ||||||
| 		StringBuilder builder = new StringBuilder("class path resource ["); | 		StringBuilder builder = new StringBuilder("class path resource ["); | ||||||
| 
 | 
 | ||||||
| 		if (this.clazz != null) { | 		String pathToUse = path; | ||||||
|  | 
 | ||||||
|  | 		if (this.clazz != null && !pathToUse.startsWith("/")) { | ||||||
| 			builder.append(ClassUtils.classPackageAsResourcePath(this.clazz)); | 			builder.append(ClassUtils.classPackageAsResourcePath(this.clazz)); | ||||||
| 			builder.append('/'); | 			builder.append('/'); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		builder.append(this.path); | 		if (pathToUse.startsWith("/")) { | ||||||
|  | 			pathToUse = pathToUse.substring(1); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		builder.append(pathToUse); | ||||||
| 		builder.append(']'); | 		builder.append(']'); | ||||||
| 		return builder.toString(); | 		return builder.toString(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	/** | 	/** | ||||||
| 	 * This implementation compares the underlying class path locations. | 	 * This implementation compares the underlying class path locations. | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -230,9 +232,9 @@ public class ClassPathResource extends AbstractFileResolvingResource { | ||||||
| 		} | 		} | ||||||
| 		if (obj instanceof ClassPathResource) { | 		if (obj instanceof ClassPathResource) { | ||||||
| 			ClassPathResource otherRes = (ClassPathResource) obj; | 			ClassPathResource otherRes = (ClassPathResource) obj; | ||||||
| 			return (this.path.equals(otherRes.path) && | 			return (this.path.equals(otherRes.path) | ||||||
| 					ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) && | 					&& ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) && ObjectUtils.nullSafeEquals( | ||||||
| 					ObjectUtils.nullSafeEquals(this.clazz, otherRes.clazz)); | 				this.clazz, otherRes.clazz)); | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2010 the original author or authors. |  * Copyright 2002-2012 the original author or authors. | ||||||
|  * |  * | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with the License. |  * you may not use this file except in compliance with the License. | ||||||
|  | @ -17,24 +17,59 @@ | ||||||
| package org.springframework.core.io; | package org.springframework.core.io; | ||||||
| 
 | 
 | ||||||
| import static org.hamcrest.CoreMatchers.instanceOf; | import static org.hamcrest.CoreMatchers.instanceOf; | ||||||
|  | import static org.junit.Assert.assertEquals; | ||||||
| import static org.junit.Assert.assertThat; | import static org.junit.Assert.assertThat; | ||||||
|  | import static org.junit.Assert.assertTrue; | ||||||
| import static org.junit.Assert.fail; | import static org.junit.Assert.fail; | ||||||
| import static org.junit.internal.matchers.StringContains.containsString; | import static org.junit.internal.matchers.StringContains.containsString; | ||||||
| 
 | 
 | ||||||
| import java.io.FileNotFoundException; | import java.io.FileNotFoundException; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
|  | import java.util.regex.Matcher; | ||||||
|  | import java.util.regex.Pattern; | ||||||
| 
 | 
 | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Unit tests cornering bug SPR-6888. |  * Unit tests that serve as regression tests for the bugs described in SPR-6888 | ||||||
|  |  * and SPR-9413. | ||||||
|  * |  * | ||||||
|  * @author Chris Beams |  * @author Chris Beams | ||||||
|  |  * @author Sam Brannen | ||||||
|  */ |  */ | ||||||
| public class ClassPathResourceTests { | public class ClassPathResourceTests { | ||||||
|  | 
 | ||||||
| 	private static final String PACKAGE_PATH = "org/springframework/core/io"; | 	private static final String PACKAGE_PATH = "org/springframework/core/io"; | ||||||
| 	private static final String RESOURCE_NAME = "notexist.xml"; | 	private static final String NONEXISTENT_RESOURCE_NAME = "nonexistent.xml"; | ||||||
| 	private static final String FQ_RESOURCE_PATH = PACKAGE_PATH + '/' + RESOURCE_NAME; | 	private static final String FQ_RESOURCE_PATH = PACKAGE_PATH + '/' + NONEXISTENT_RESOURCE_NAME; | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Absolute path version of {@link #FQ_RESOURCE_PATH}. | ||||||
|  | 	 */ | ||||||
|  | 	private static final String FQ_RESOURCE_PATH_WITH_LEADING_SLASH = '/' + FQ_RESOURCE_PATH; | ||||||
|  | 
 | ||||||
|  | 	private static final Pattern DESCRIPTION_PATTERN = Pattern.compile("^class path resource \\[(.+?)\\]$"); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	private void assertDescriptionContainsExpectedPath(ClassPathResource resource, String expectedPath) { | ||||||
|  | 		Matcher matcher = DESCRIPTION_PATTERN.matcher(resource.getDescription()); | ||||||
|  | 		assertTrue(matcher.matches()); | ||||||
|  | 		assertEquals(1, matcher.groupCount()); | ||||||
|  | 		String match = matcher.group(1); | ||||||
|  | 
 | ||||||
|  | 		assertEquals(expectedPath, match); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private void assertExceptionContainsFullyQualifiedPath(ClassPathResource resource) { | ||||||
|  | 		try { | ||||||
|  | 			resource.getInputStream(); | ||||||
|  | 			fail("FileNotFoundException expected for resource: " + resource); | ||||||
|  | 		} | ||||||
|  | 		catch (IOException ex) { | ||||||
|  | 			assertThat(ex, instanceOf(FileNotFoundException.class)); | ||||||
|  | 			assertThat(ex.getMessage(), containsString(FQ_RESOURCE_PATH)); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void stringConstructorRaisesExceptionWithFullyQualifiedPath() { | 	public void stringConstructorRaisesExceptionWithFullyQualifiedPath() { | ||||||
|  | @ -43,21 +78,48 @@ public class ClassPathResourceTests { | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void classLiteralConstructorRaisesExceptionWithFullyQualifiedPath() { | 	public void classLiteralConstructorRaisesExceptionWithFullyQualifiedPath() { | ||||||
| 		assertExceptionContainsFullyQualifiedPath(new ClassPathResource(RESOURCE_NAME, this.getClass())); | 		assertExceptionContainsFullyQualifiedPath(new ClassPathResource(NONEXISTENT_RESOURCE_NAME, this.getClass())); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void classLoaderConstructorRaisesExceptionWithFullyQualifiedPath() { | 	public void classLoaderConstructorRaisesExceptionWithFullyQualifiedPath() { | ||||||
| 		assertExceptionContainsFullyQualifiedPath(new ClassPathResource(FQ_RESOURCE_PATH, this.getClass().getClassLoader())); | 		assertExceptionContainsFullyQualifiedPath(new ClassPathResource(FQ_RESOURCE_PATH, | ||||||
|  | 			this.getClass().getClassLoader())); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private void assertExceptionContainsFullyQualifiedPath(ClassPathResource resource) { | 	@Test | ||||||
| 		try { | 	public void getDescriptionWithStringConstructor() { | ||||||
| 			resource.getInputStream(); | 		assertDescriptionContainsExpectedPath(new ClassPathResource(FQ_RESOURCE_PATH), FQ_RESOURCE_PATH); | ||||||
| 			fail("FileNotFoundException expected for resource: " + resource); |  | ||||||
| 		} catch (IOException ex) { |  | ||||||
| 			assertThat(ex, instanceOf(FileNotFoundException.class)); |  | ||||||
| 			assertThat(ex.getMessage(), containsString(FQ_RESOURCE_PATH)); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void getDescriptionWithStringConstructorAndLeadingSlash() { | ||||||
|  | 		assertDescriptionContainsExpectedPath(new ClassPathResource(FQ_RESOURCE_PATH_WITH_LEADING_SLASH), | ||||||
|  | 			FQ_RESOURCE_PATH); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void getDescriptionWithClassLiteralConstructor() { | ||||||
|  | 		assertDescriptionContainsExpectedPath(new ClassPathResource(NONEXISTENT_RESOURCE_NAME, this.getClass()), | ||||||
|  | 			FQ_RESOURCE_PATH); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void getDescriptionWithClassLiteralConstructorAndLeadingSlash() { | ||||||
|  | 		assertDescriptionContainsExpectedPath( | ||||||
|  | 			new ClassPathResource(FQ_RESOURCE_PATH_WITH_LEADING_SLASH, this.getClass()), FQ_RESOURCE_PATH); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void getDescriptionWithClassLoaderConstructor() { | ||||||
|  | 		assertDescriptionContainsExpectedPath( | ||||||
|  | 			new ClassPathResource(FQ_RESOURCE_PATH, this.getClass().getClassLoader()), FQ_RESOURCE_PATH); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void getDescriptionWithClassLoaderConstructorAndLeadingSlash() { | ||||||
|  | 		assertDescriptionContainsExpectedPath(new ClassPathResource(FQ_RESOURCE_PATH_WITH_LEADING_SLASH, | ||||||
|  | 			this.getClass().getClassLoader()), FQ_RESOURCE_PATH); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue