Revise duplicate filtering in SpringFactoriesLoader

This commit ensures that the static cache in SpringFactoriesLoader
contains unmodifiable lists of unique names of factory implementations.

See gh-24985
This commit is contained in:
Sam Brannen 2020-04-29 14:05:14 +02:00
parent a378480faf
commit 5abca033d0
1 changed files with 10 additions and 11 deletions

View File

@ -22,11 +22,10 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.stream.Collectors;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -71,7 +70,7 @@ public final class SpringFactoriesLoader {
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class); private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
private static final Map<ClassLoader, Map<String, Set<String>>> cache = new ConcurrentReferenceHashMap<>(); private static final Map<ClassLoader, Map<String, List<String>>> cache = new ConcurrentReferenceHashMap<>();
private SpringFactoriesLoader() { private SpringFactoriesLoader() {
@ -126,15 +125,11 @@ public final class SpringFactoriesLoader {
*/ */
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName(); String factoryTypeName = factoryType.getName();
Set<String> factoryNames = loadSpringFactories(classLoader).get(factoryTypeName); return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
if (factoryNames == null || factoryNames.isEmpty()) {
return Collections.emptyList();
}
return Collections.unmodifiableList(new ArrayList<>(factoryNames));
} }
private static Map<String, Set<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
Map<String, Set<String>> result = cache.get(classLoader); Map<String, List<String>> result = cache.get(classLoader);
if (result != null) { if (result != null) {
return result; return result;
} }
@ -153,11 +148,15 @@ public final class SpringFactoriesLoader {
String[] factoryImplementationNames = String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue()); StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) { for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new LinkedHashSet<String>()) result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim()); .add(factoryImplementationName.trim());
} }
} }
} }
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result); cache.put(classLoader, result);
} }
catch (IOException ex) { catch (IOException ex) {