From 7c57541d503574bcf350cef9c459797d87899929 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 18 Dec 2013 09:55:06 -0800 Subject: [PATCH] Filter duplicates from SpringFactories loading Filter duplicate class names when loading spring.factories files. The prevents errors if -source jars are included on the classpath. fixes gh-161 --- ...EnableAutoConfigurationImportSelector.java | 7 +++-- .../boot/SpringApplication.java | 30 ++++++++++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelector.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelector.java index f7ee1c83ed..004eee48b3 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelector.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelector.java @@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedHashSet; import java.util.List; import org.springframework.beans.factory.BeanClassLoaderAware; @@ -53,10 +54,10 @@ class EnableAutoConfigurationImportSelector implements DeferredImportSelector, .getAnnotationAttributes(EnableAutoConfiguration.class.getName(), true)); - // Find all possible auto configuration classes - List factories = new ArrayList( + // Find all possible auto configuration classes, filtering duplicates + List factories = new ArrayList(new LinkedHashSet( SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, - this.beanClassLoader)); + this.beanClassLoader))); // Remove those specifically disabled factories.removeAll(Arrays.asList(attributes.getStringArray("exclude"))); diff --git a/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index 141df9708b..8848afb081 100644 --- a/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -49,6 +49,7 @@ import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.GenericTypeResolver; +import org.springframework.core.OrderComparator; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.env.CommandLinePropertySource; import org.springframework.core.env.CompositePropertySource; @@ -232,11 +233,32 @@ public class SpringApplication { * {@link SpringFactoriesLoader}. Subclasses can override this method to modify * default initializers if necessary. */ - @SuppressWarnings({ "rawtypes", "unchecked" }) protected Collection> getSpringFactoriesApplicationContextInitializers() { - return (Collection) SpringFactoriesLoader.loadFactories( - ApplicationContextInitializer.class, - SpringApplication.class.getClassLoader()); + ClassLoader classLoader = SpringApplication.class.getClassLoader(); + + // Use names and ensure unique to protect against duplicates + Set names = new LinkedHashSet( + SpringFactoriesLoader.loadFactoryNames( + ApplicationContextInitializer.class, classLoader)); + List> factories = new ArrayList>( + names.size()); + + // Create instances from the names + for (String name : names) { + try { + Class instanceClass = ClassUtils.forName(name, classLoader); + Assert.isAssignable(ApplicationContextInitializer.class, instanceClass); + factories.add((ApplicationContextInitializer) instanceClass + .newInstance()); + } + catch (Throwable ex) { + throw new IllegalArgumentException( + "Cannot instantiate ApplicationContextInitializer : " + name, ex); + } + } + + OrderComparator.sort(factories); + return factories; } private Class deduceMainApplicationClass() {