Consistently use constructor-based instantiation instead of Class.newInstance / BeanUtils.instantiate

Issue: SPR-14486
This commit is contained in:
Juergen Hoeller
2016-07-19 19:21:06 +02:00
parent b3253ca5e2
commit aaac199e8b
54 changed files with 285 additions and 242 deletions

View File

@@ -38,6 +38,7 @@ import java.util.TreeSet;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils;
/**
* Factory for collections that is aware of Java 5, Java 6, and Spring
@@ -201,9 +202,9 @@ public abstract class CollectionFactory {
throw new IllegalArgumentException("Unsupported Collection type: " + collectionType.getName());
}
try {
return (Collection<E>) collectionType.newInstance();
return (Collection<E>) ReflectionUtils.accessibleConstructor(collectionType).newInstance();
}
catch (Exception ex) {
catch (Throwable ex) {
throw new IllegalArgumentException(
"Could not instantiate Collection type: " + collectionType.getName(), ex);
}
@@ -316,9 +317,9 @@ public abstract class CollectionFactory {
throw new IllegalArgumentException("Unsupported Map type: " + mapType.getName());
}
try {
return (Map<K, V>) mapType.newInstance();
return (Map<K, V>) ReflectionUtils.accessibleConstructor(mapType).newInstance();
}
catch (Exception ex) {
catch (Throwable ex) {
throw new IllegalArgumentException("Could not instantiate Map type: " + mapType.getName(), ex);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 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.
@@ -101,7 +101,7 @@ public class ConfigurableObjectInputStream extends ObjectInputStream {
}
}
try {
return Proxy.getProxyClass(this.classLoader, resolvedInterfaces);
return ClassUtils.createCompositeInterface(resolvedInterfaces, this.classLoader);
}
catch (IllegalArgumentException ex) {
throw new ClassNotFoundException(null, ex);
@@ -117,7 +117,7 @@ public class ConfigurableObjectInputStream extends ObjectInputStream {
for (int i = 0; i < interfaces.length; i++) {
resolvedInterfaces[i] = resolveFallbackIfPossible(interfaces[i], ex);
}
return Proxy.getProxyClass(getFallbackClassLoader(), resolvedInterfaces);
return ClassUtils.createCompositeInterface(resolvedInterfaces, getFallbackClassLoader());
}
}
}

View File

@@ -17,7 +17,6 @@
package org.springframework.core.io.support;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
@@ -134,12 +133,10 @@ public abstract class SpringFactoriesLoader {
throw new IllegalArgumentException(
"Class [" + instanceClassName + "] is not assignable to [" + factoryClass.getName() + "]");
}
Constructor<?> constructor = instanceClass.getDeclaredConstructor();
ReflectionUtils.makeAccessible(constructor);
return (T) constructor.newInstance();
return (T) ReflectionUtils.accessibleConstructor(instanceClass).newInstance();
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate factory class: " + factoryClass.getName(), ex);
throw new IllegalArgumentException("Unable to instantiate factory class: " + factoryClass.getName(), ex);
}
}

View File

@@ -17,6 +17,7 @@
package org.springframework.util;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
@@ -264,13 +265,16 @@ public class AutoPopulatingList<E> implements List<E>, Serializable {
public ElementInstantiationException(String msg) {
super(msg);
}
public ElementInstantiationException(String message, Throwable cause) {
super(message, cause);
}
}
/**
* Reflective implementation of the ElementFactory interface,
* using {@code Class.newInstance()} on a given element class.
* @see Class#newInstance()
* Reflective implementation of the ElementFactory interface, using
* {@code Class.getDeclaredConstructor().newInstance()} on a given element class.
*/
private static class ReflectiveElementFactory<E> implements ElementFactory<E>, Serializable {
@@ -286,15 +290,23 @@ public class AutoPopulatingList<E> implements List<E>, Serializable {
@Override
public E createElement(int index) {
try {
return this.elementClass.newInstance();
return ReflectionUtils.accessibleConstructor(this.elementClass).newInstance();
}
catch (NoSuchMethodException ex) {
throw new ElementInstantiationException(
"No default constructor on element class: " + this.elementClass.getName(), ex);
}
catch (InstantiationException ex) {
throw new ElementInstantiationException("Unable to instantiate element class [" +
this.elementClass.getName() + "]. Root cause is " + ex);
throw new ElementInstantiationException(
"Unable to instantiate element class: " + this.elementClass.getName(), ex);
}
catch (IllegalAccessException ex) {
throw new ElementInstantiationException("Cannot access element class [" +
this.elementClass.getName() + "]. Root cause is " + ex);
throw new ElementInstantiationException(
"Could not access element constructor: " + this.elementClass.getName(), ex);
}
catch (InvocationTargetException ex) {
throw new ElementInstantiationException(
"Failed to invoke element constructor: " + this.elementClass.getName(), ex.getTargetException());
}
}
}

View File

@@ -1156,6 +1156,7 @@ public abstract class ClassUtils {
* @return the merged interface as Class
* @see java.lang.reflect.Proxy#getProxyClass
*/
@SuppressWarnings("deprecation")
public static Class<?> createCompositeInterface(Class<?>[] interfaces, ClassLoader classLoader) {
Assert.notEmpty(interfaces, "Interfaces must not be empty");
Assert.notNull(classLoader, "ClassLoader must not be null");

View File

@@ -476,6 +476,22 @@ public abstract class ReflectionUtils {
}
}
/**
* Obtain an accessible constructor for the given class and parameters.
* @param clazz the clazz to check
* @param parameterTypes the parameter types of the desired constructor
* @return the constructor reference
* @throws NoSuchMethodException if no such constructor exists
* @since 5.0
*/
public static <T> Constructor<T> accessibleConstructor(Class<T> clazz, Class<?>... parameterTypes)
throws NoSuchMethodException {
Constructor<T> ctor = clazz.getDeclaredConstructor(parameterTypes);
makeAccessible(ctor);
return ctor;
}
/**
* Perform the given callback operation on all matching methods of the given
* class, as locally declared or equivalent thereof (such as default methods