diff --git a/spring-core/src/main/java/org/springframework/util/Assert.java b/spring-core/src/main/java/org/springframework/util/Assert.java index 959d29147b..1d7c477090 100644 --- a/spring-core/src/main/java/org/springframework/util/Assert.java +++ b/spring-core/src/main/java/org/springframework/util/Assert.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. You may obtain a copy of @@ -373,8 +373,8 @@ public abstract class Assert { public static void isAssignable(Class superType, Class subType, String message) { notNull(superType, "Type to check against must not be null"); if (subType == null || !superType.isAssignableFrom(subType)) { - throw new IllegalArgumentException((StringUtils.hasLength(message) ? message + " " : "") - + subType + " is not assignable to " + superType); + throw new IllegalArgumentException((StringUtils.hasLength(message) ? message + " " : "") + + subType + " is not assignable to " + superType); } } diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java index d8ae5a6611..6994c79821 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanUtils; import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextException; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.GenericTypeResolver; @@ -86,8 +87,8 @@ public abstract class AbstractContextLoader implements SmartContextLoader { */ @Override public void processContextConfiguration(ContextConfigurationAttributes configAttributes) { - String[] processedLocations = processLocations(configAttributes.getDeclaringClass(), - configAttributes.getLocations()); + String[] processedLocations = + processLocations(configAttributes.getDeclaringClass(), configAttributes.getLocations()); configAttributes.setLocations(processedLocations); } @@ -135,7 +136,9 @@ public abstract class AbstractContextLoader implements SmartContextLoader { @SuppressWarnings("unchecked") private void invokeApplicationContextInitializers(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) { - Set>> initializerClasses = mergedConfig.getContextInitializerClasses(); + + Set>> initializerClasses = + mergedConfig.getContextInitializerClasses(); if (initializerClasses.isEmpty()) { // no ApplicationContextInitializers have been declared -> nothing to do return; @@ -145,13 +148,15 @@ public abstract class AbstractContextLoader implements SmartContextLoader { Class contextClass = context.getClass(); for (Class> initializerClass : initializerClasses) { - Class initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass, - ApplicationContextInitializer.class); - Assert.isAssignable(initializerContextClass, contextClass, String.format( - "Could not add context initializer [%s] since its generic parameter [%s] " - + "is not assignable from the type of application context used by this " - + "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(), - contextClass.getName())); + Class initializerContextClass = + GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class); + if (initializerContextClass != null && !initializerContextClass.isInstance(context)) { + throw new ApplicationContextException(String.format( + "Could not apply context initializer [%s] since its generic parameter [%s] " + + "is not assignable from the type of application context used by this " + + "context loader: [%s]", initializerClass.getName(), initializerContextClass.getName(), + contextClass.getName())); + } initializerInstances.add((ApplicationContextInitializer) BeanUtils.instantiateClass(initializerClass)); } @@ -161,6 +166,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader { } } + // --- ContextLoader ------------------------------------------------------- /** @@ -171,7 +177,6 @@ public abstract class AbstractContextLoader implements SmartContextLoader { * and the configured {@linkplain #getResourceSuffixes() resource suffixes}; * otherwise, the supplied {@code locations} will be * {@linkplain #modifyLocations modified} if necessary and returned. - * * @param clazz the class with which the locations are associated: to be * used when generating default locations * @param locations the unmodified locations to use for loading the @@ -186,30 +191,26 @@ public abstract class AbstractContextLoader implements SmartContextLoader { */ @Override public final String[] processLocations(Class clazz, String... locations) { - return (ObjectUtils.isEmpty(locations) && isGenerateDefaultLocations()) ? generateDefaultLocations(clazz) - : modifyLocations(clazz, locations); + return (ObjectUtils.isEmpty(locations) && isGenerateDefaultLocations()) ? + generateDefaultLocations(clazz) : modifyLocations(clazz, locations); } /** * Generate the default classpath resource locations array based on the * supplied class. - * *

For example, if the supplied class is {@code com.example.MyTest}, * the generated locations will contain a single string with a value of * {@code "classpath:com/example/MyTest"}, where {@code } * is the value of the first configured * {@linkplain #getResourceSuffixes() resource suffix} for which the * generated location actually exists in the classpath. - * *

As of Spring 3.1, the implementation of this method adheres to the * contract defined in the {@link SmartContextLoader} SPI. Specifically, * this method will preemptively verify that the generated default * location actually exists. If it does not exist, this method will log a * warning and return an empty array. - * *

Subclasses can override this method to implement a different * default location generation strategy. - * * @param clazz the class for which the default locations are to be generated * @return an array of default application context resource locations * @since 2.5 @@ -224,23 +225,22 @@ public abstract class AbstractContextLoader implements SmartContextLoader { String resourcePath = ClassUtils.convertClassNameToResourcePath(clazz.getName()) + suffix; String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + resourcePath; ClassPathResource classPathResource = new ClassPathResource(resourcePath); - if (classPathResource.exists()) { if (logger.isInfoEnabled()) { logger.info(String.format("Detected default resource location \"%s\" for test class [%s]", - prefixedResourcePath, clazz.getName())); + prefixedResourcePath, clazz.getName())); } - return new String[] { prefixedResourcePath }; + return new String[] {prefixedResourcePath}; } else if (logger.isDebugEnabled()) { - logger.debug(String.format("Did not detect default resource location for test class [%s]: " - + "%s does not exist", clazz.getName(), classPathResource)); + logger.debug(String.format("Did not detect default resource location for test class [%s]: " + + "%s does not exist", clazz.getName(), classPathResource)); } } if (logger.isInfoEnabled()) { - logger.info(String.format("Could not detect default resource locations for test class [%s]: " - + "no resource found for suffixes %s.", clazz.getName(), ObjectUtils.nullSafeToString(suffixes))); + logger.info(String.format("Could not detect default resource locations for test class [%s]: " + + "no resource found for suffixes %s.", clazz.getName(), ObjectUtils.nullSafeToString(suffixes))); } return EMPTY_STRING_ARRAY; @@ -282,15 +282,26 @@ public abstract class AbstractContextLoader implements SmartContextLoader { } /** - * Get the suffix to append to {@link ApplicationContext} resource - * locations when detecting default locations. - * - *

Subclasses must provide an implementation of this method that - * returns a single suffix. Alternatively subclasses may provide a - * no-op implementation of this method and override - * {@link #getResourceSuffixes()} in order to provide multiple custom - * suffixes. - * + * Get the suffixes to append to {@link ApplicationContext} resource locations + * when detecting default locations. + *

The default implementation simply wraps the value returned by + * {@link #getResourceSuffix()} in a single-element array, but this + * can be overridden by subclasses in order to support multiple suffixes. + * @return the resource suffixes; never {@code null} or empty + * @since 4.1 + * @see #generateDefaultLocations(Class) + */ + protected String[] getResourceSuffixes() { + return new String[] {getResourceSuffix()}; + } + + /** + * Get the suffix to append to {@link ApplicationContext} resource locations + * when detecting default locations. + *

Subclasses must provide an implementation of this method that returns + * a single suffix. Alternatively subclasses may provide a no-op + * implementation of this method and override {@link #getResourceSuffixes()} + * in order to provide multiple custom suffixes. * @return the resource suffix; never {@code null} or empty * @since 2.5 * @see #generateDefaultLocations(Class) @@ -298,20 +309,4 @@ public abstract class AbstractContextLoader implements SmartContextLoader { */ protected abstract String getResourceSuffix(); - /** - * Get the suffixes to append to {@link ApplicationContext} resource - * locations when detecting default locations. - * - *

The default implementation simply wraps the value returned by - * {@link #getResourceSuffix()} in a single-element array, but this - * can be overridden by subclasses in order to support multiple suffixes. - * - * @return the resource suffixes; never {@code null} or empty - * @since 4.1 - * @see #generateDefaultLocations(Class) - */ - protected String[] getResourceSuffixes() { - return new String[] { getResourceSuffix() }; - } - } diff --git a/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java b/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java index 9da29a744d..595d2908c0 100644 --- a/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java +++ b/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -49,19 +49,18 @@ import org.springframework.util.StringUtils; * Performs the actual initialization work for the root application context. * Called by {@link ContextLoaderListener}. * - *

Looks for a {@link #CONTEXT_CLASS_PARAM "contextClass"} parameter - * at the {@code web.xml} context-param level to specify the context - * class type, falling back to the default of - * {@link org.springframework.web.context.support.XmlWebApplicationContext} + *

Looks for a {@link #CONTEXT_CLASS_PARAM "contextClass"} parameter at the + * {@code web.xml} context-param level to specify the context class type, falling + * back to {@link org.springframework.web.context.support.XmlWebApplicationContext} * if not found. With the default ContextLoader implementation, any context class - * specified needs to implement the ConfigurableWebApplicationContext interface. + * specified needs to implement the {@link ConfigurableWebApplicationContext} interface. * - *

Processes a {@link #CONFIG_LOCATION_PARAM "contextConfigLocation"} - * context-param and passes its value to the context instance, parsing it into - * potentially multiple file paths which can be separated by any number of - * commas and spaces, e.g. "WEB-INF/applicationContext1.xml, - * WEB-INF/applicationContext2.xml". Ant-style path patterns are supported as well, - * e.g. "WEB-INF/*Context.xml,WEB-INF/spring*.xml" or "WEB-INF/**/*Context.xml". + *

Processes a {@link #CONFIG_LOCATION_PARAM "contextConfigLocation"} context-param + * and passes its value to the context instance, parsing it into potentially multiple + * file paths which can be separated by any number of commas and spaces, e.g. + * "WEB-INF/applicationContext1.xml, WEB-INF/applicationContext2.xml". + * Ant-style path patterns are supported as well, e.g. + * "WEB-INF/*Context.xml,WEB-INF/spring*.xml" or "WEB-INF/**/*Context.xml". * If not explicitly specified, the context implementation is supposed to use a * default location (with XmlWebApplicationContext: "/WEB-INF/applicationContext.xml"). * @@ -70,10 +69,9 @@ import org.springframework.util.StringUtils; * Spring's default ApplicationContext implementations. This can be leveraged * to deliberately override certain bean definitions via an extra XML file. * - *

Above and beyond loading the root application context, this class - * can optionally load or obtain and hook up a shared parent context to - * the root application context. See the - * {@link #loadParentContext(ServletContext)} method for more information. + *

Above and beyond loading the root application context, this class can optionally + * load or obtain and hook up a shared parent context to the root application context. + * See the {@link #loadParentContext(ServletContext)} method for more information. * *

As of Spring 3.1, {@code ContextLoader} supports injecting the root web * application context via the {@link #ContextLoader(WebApplicationContext)} @@ -470,11 +468,11 @@ public class ContextLoader { for (Class> initializerClass : initializerClasses) { Class initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class); - if (initializerContextClass != null) { - Assert.isAssignable(initializerContextClass, wac.getClass(), String.format( - "Could not add context initializer [%s] since its generic parameter [%s] " + + if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) { + throw new ApplicationContextException(String.format( + "Could not apply context initializer [%s] since its generic parameter [%s] " + "is not assignable from the type of application context used by this " + - "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(), + "context loader: [%s]", initializerClass.getName(), initializerContextClass.getName(), wac.getClass().getName())); } this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass)); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java index 46ad584e28..5d7659f43d 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java @@ -43,7 +43,6 @@ import org.springframework.core.GenericTypeResolver; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.http.HttpMethod; -import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -740,17 +739,17 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic Class initializerClass = ClassUtils.forName(className, wac.getClassLoader()); Class initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class); - if (initializerContextClass != null) { - Assert.isAssignable(initializerContextClass, wac.getClass(), String.format( - "Could not add context initializer [%s] since its generic parameter [%s] " + + if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) { + throw new ApplicationContextException(String.format( + "Could not apply context initializer [%s] since its generic parameter [%s] " + "is not assignable from the type of application context used by this " + - "framework servlet [%s]: ", initializerClass.getName(), initializerContextClass.getName(), + "framework servlet: [%s]", initializerClass.getName(), initializerContextClass.getName(), wac.getClass().getName())); } return BeanUtils.instantiateClass(initializerClass, ApplicationContextInitializer.class); } - catch (Exception ex) { - throw new IllegalArgumentException(String.format("Could not instantiate class [%s] specified " + + catch (ClassNotFoundException ex) { + throw new ApplicationContextException(String.format("Could not load class [%s] specified " + "via 'contextInitializerClasses' init-param", className), ex); } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/context/ContextLoaderTests.java b/spring-webmvc/src/test/java/org/springframework/web/context/ContextLoaderTests.java index c54e84dc9e..55667bb347 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/context/ContextLoaderTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/context/ContextLoaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -225,7 +225,7 @@ public class ContextLoaderTests { listener.contextInitialized(new ServletContextEvent(sc)); fail("expected exception"); } - catch (IllegalArgumentException ex) { + catch (ApplicationContextException ex) { assertTrue(ex.getMessage().contains("not assignable")); } }