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

@@ -18,7 +18,9 @@ package org.springframework.beans;
import java.beans.PropertyChangeEvent;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.PrivilegedActionException;
import java.util.ArrayList;
@@ -890,14 +892,16 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
return CollectionFactory.createMap(type, (keyDesc != null ? keyDesc.getType() : null), 16);
}
else {
return BeanUtils.instantiate(type);
Constructor<?> ctor = type.getDeclaredConstructor();
if (Modifier.isPrivate(ctor.getModifiers())) {
throw new IllegalAccessException("Auto-growing not allowed with private constructor: " + ctor);
}
return BeanUtils.instantiateClass(ctor);
}
}
catch (Exception ex) {
// TODO: Root cause exception context is lost here; just exception message preserved.
// Should we throw another exception type that preserves context instead?
catch (Throwable ex) {
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name,
"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path: " + ex);
"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path", ex);
}
}

View File

@@ -63,12 +63,14 @@ public abstract class BeanUtils {
/**
* Convenience method to instantiate a class using its no-arg constructor.
* As this method doesn't try to load classes by name, it should avoid
* class-loading issues.
* @param clazz class to instantiate
* @return the new instance
* @throws BeanInstantiationException if the bean cannot be instantiated
* @deprecated as of Spring 5.0, following the deprecation of
* {@link Class#newInstance()} in JDK 9
* @see Class#newInstance()
*/
@Deprecated
public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
Assert.notNull(clazz, "Class must not be null");
if (clazz.isInterface()) {
@@ -87,13 +89,12 @@ public abstract class BeanUtils {
/**
* Instantiate a class using its no-arg constructor.
* As this method doesn't try to load classes by name, it should avoid
* class-loading issues.
* <p>Note that this method tries to set the constructor accessible
* if given a non-accessible (that is, non-public) constructor.
* @param clazz class to instantiate
* @return the new instance
* @throws BeanInstantiationException if the bean cannot be instantiated
* @see Constructor#newInstance
*/
public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
Assert.notNull(clazz, "Class must not be null");
@@ -111,17 +112,15 @@ public abstract class BeanUtils {
/**
* Instantiate a class using its no-arg constructor and return the new instance
* as the specified assignable type.
* <p>Useful in cases where
* the type of the class to instantiate (clazz) is not available, but the type
* desired (assignableTo) is known.
* <p>As this method doesn't try to load classes by name, it should avoid
* class-loading issues.
* <p>Note that this method tries to set the constructor accessible
* if given a non-accessible (that is, non-public) constructor.
* <p>Useful in cases where the type of the class to instantiate (clazz) is not
* available, but the type desired (assignableTo) is known.
* <p>Note that this method tries to set the constructor accessible if given a
* non-accessible (that is, non-public) constructor.
* @param clazz class to instantiate
* @param assignableTo type that clazz must be assignableTo
* @return the new instance
* @throws BeanInstantiationException if the bean cannot be instantiated
* @see Constructor#newInstance
*/
@SuppressWarnings("unchecked")
public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) throws BeanInstantiationException {
@@ -131,14 +130,13 @@ public abstract class BeanUtils {
/**
* Convenience method to instantiate a class using the given constructor.
* As this method doesn't try to load classes by name, it should avoid
* class-loading issues.
* <p>Note that this method tries to set the constructor accessible
* if given a non-accessible (that is, non-public) constructor.
* <p>Note that this method tries to set the constructor accessible if given a
* non-accessible (that is, non-public) constructor.
* @param ctor the constructor to instantiate
* @param args the constructor arguments to apply
* @return the new instance
* @throws BeanInstantiationException if the bean cannot be instantiated
* @see Constructor#newInstance
*/
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");

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.
@@ -24,6 +24,7 @@ package org.springframework.beans;
* spouse property of the target object has a null value.
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
@SuppressWarnings("serial")
public class NullValueInNestedPathException extends InvalidPropertyException {
@@ -47,4 +48,16 @@ public class NullValueInNestedPathException extends InvalidPropertyException {
super(beanClass, propertyName, msg);
}
/**
* Create a new NullValueInNestedPathException.
* @param beanClass the offending bean class
* @param propertyName the offending property
* @param msg the detail message
* @param cause the root cause
* @since 4.3.2
*/
public NullValueInNestedPathException(Class<?> beanClass, String propertyName, String msg, Throwable cause) {
super(beanClass, propertyName, msg, cause);
}
}

View File

@@ -36,6 +36,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.ClassUtils;
import org.springframework.util.NumberUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
@@ -543,7 +544,8 @@ class TypeConverterDelegate {
convertedCopy = CollectionFactory.createApproximateCollection(original, original.size());
}
else {
convertedCopy = (Collection<Object>) requiredType.newInstance();
convertedCopy = (Collection<Object>)
ReflectionUtils.accessibleConstructor(requiredType).newInstance();
}
}
catch (Throwable ex) {
@@ -625,7 +627,8 @@ class TypeConverterDelegate {
convertedCopy = CollectionFactory.createApproximateMap(original, original.size());
}
else {
convertedCopy = (Map<Object, Object>) requiredType.newInstance();
convertedCopy = (Map<Object, Object>)
ReflectionUtils.accessibleConstructor(requiredType).newInstance();
}
}
catch (Throwable ex) {

View File

@@ -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.
@@ -115,7 +115,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
if (ctor == null) {
instance = BeanUtils.instantiate(subclass);
instance = BeanUtils.instantiateClass(subclass);
}
else {
try {

View File

@@ -81,7 +81,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Exception ex) {
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}

View File

@@ -25,6 +25,8 @@ import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.springframework.util.ReflectionUtils;
/**
* Property editor for Collections, converting any source Collection
* to a given target Collection type.
@@ -152,11 +154,11 @@ public class CustomCollectionEditor extends PropertyEditorSupport {
protected Collection<Object> createCollection(Class<? extends Collection> collectionType, int initialCapacity) {
if (!collectionType.isInterface()) {
try {
return collectionType.newInstance();
return ReflectionUtils.accessibleConstructor(collectionType).newInstance();
}
catch (Exception ex) {
catch (Throwable ex) {
throw new IllegalArgumentException(
"Could not instantiate collection class [" + collectionType.getName() + "]: " + ex.getMessage());
"Could not instantiate collection class: " + collectionType.getName(), ex);
}
}
else if (List.class == collectionType) {

View File

@@ -22,6 +22,8 @@ import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.springframework.util.ReflectionUtils;
/**
* Property editor for Maps, converting any source Map
* to a given target Map type.
@@ -130,11 +132,11 @@ public class CustomMapEditor extends PropertyEditorSupport {
protected Map<Object, Object> createMap(Class<? extends Map> mapType, int initialCapacity) {
if (!mapType.isInterface()) {
try {
return mapType.newInstance();
return ReflectionUtils.accessibleConstructor(mapType).newInstance();
}
catch (Exception ex) {
catch (Throwable ex) {
throw new IllegalArgumentException(
"Could not instantiate map class [" + mapType.getName() + "]: " + ex.getMessage());
"Could not instantiate map class: " + mapType.getName(), ex);
}
}
else if (SortedMap.class == mapType) {