提交 21457667 编写于 作者: J Juergen Hoeller

Proper NoClassDefFoundError check against BeanUtils.instantiateClass

Issue: SPR-16369
上级 32b42799
......@@ -98,12 +98,18 @@ public abstract class BeanUtils {
}
/**
* Instantiate a class using its no-arg constructor.
* Instantiate a class using its 'primary' constructor (for Kotlin classes,
* potentially having default arguments declared) or its default constructor
* (for regular Java classes, expecting a standard no-arg setup).
* <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 clazz the class to instantiate
* @return the new instance
* @throws BeanInstantiationException if the bean cannot be instantiated
* @throws BeanInstantiationException if the bean cannot be instantiated.
* The cause may notably indicate a {@link NoSuchMethodException} if no
* primary/default constructor was found - or an exception thrown from
* the constructor invocation attempt, including a runtime-generated
* {@link NoClassDefFoundError} in case of an unresolvable dependency.
* @see Constructor#newInstance
*/
public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
......@@ -113,10 +119,7 @@ public abstract class BeanUtils {
}
try {
Constructor<T> ctor = (KotlinDetector.isKotlinType(clazz) ?
KotlinDelegate.findPrimaryConstructor(clazz) : clazz.getDeclaredConstructor());
if (ctor == null) {
throw new BeanInstantiationException(clazz, "No default constructor found");
}
KotlinDelegate.getPrimaryConstructor(clazz) : clazz.getDeclaredConstructor());
return instantiateClass(ctor);
}
catch (NoSuchMethodException ex) {
......@@ -693,10 +696,26 @@ public abstract class BeanUtils {
private static class KotlinDelegate {
/**
* Return the Java constructor corresponding to the Kotlin primary constructor if any.
* Determine the Java constructor corresponding to the Kotlin primary constructor.
* @param clazz the {@link Class} of the Kotlin class
* @throws NoSuchMethodException if no such constructor found
* @since 5.0.3
* @see #findPrimaryConstructor
* @see Class#getDeclaredConstructor
*/
public static <T> Constructor<T> getPrimaryConstructor(Class<T> clazz) throws NoSuchMethodException {
Constructor<T> ctor = findPrimaryConstructor(clazz);
if (ctor == null) {
throw new NoSuchMethodException();
}
return ctor;
}
/**
* Retrieve the Java constructor corresponding to the Kotlin primary constructor, if any.
* @param clazz the {@link Class} of the Kotlin class
* @see <a href="http://kotlinlang.org/docs/reference/classes.html#constructors">
* http://kotlinlang.org/docs/reference/classes.html#constructors</a>
* http://kotlinlang.org/docs/reference/classes.html#constructors</a>
*/
@Nullable
public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
......@@ -706,8 +725,10 @@ public abstract class BeanUtils {
return null;
}
Constructor<T> constructor = ReflectJvmMapping.getJavaConstructor(primaryCtor);
Assert.notNull(constructor,
() -> "Failed to find Java constructor for Kotlin primary constructor: " + clazz.getName());
if (constructor == null) {
throw new IllegalStateException(
"Failed to find Java constructor for Kotlin primary constructor: " + clazz.getName());
}
return constructor;
}
catch (UnsupportedOperationException ex) {
......@@ -718,7 +739,8 @@ public abstract class BeanUtils {
/**
* Instantiate a Kotlin class using the provided constructor.
* @param ctor the constructor of the Kotlin class to instantiate
* @param args the constructor arguments to apply (use null for unspecified parameter if needed)
* @param args the constructor arguments to apply
* (use {@code null} for unspecified parameter if needed)
*/
public static <T> T instantiateClass(Constructor<T> ctor, Object... args)
throws IllegalAccessException, InvocationTargetException, InstantiationException {
......
......@@ -28,6 +28,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeanUtils;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.AnnotationUtils;
......@@ -178,18 +179,25 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
return listeners;
}
private List<TestExecutionListener> instantiateListeners(Collection<Class<? extends TestExecutionListener>> classesList) {
List<TestExecutionListener> listeners = new ArrayList<>(classesList.size());
for (Class<? extends TestExecutionListener> listenerClass : classesList) {
private List<TestExecutionListener> instantiateListeners(Collection<Class<? extends TestExecutionListener>> classes) {
List<TestExecutionListener> listeners = new ArrayList<>(classes.size());
for (Class<? extends TestExecutionListener> listenerClass : classes) {
try {
listeners.add(BeanUtils.instantiateClass(listenerClass));
}
catch (NoClassDefFoundError err) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Could not instantiate TestExecutionListener [%s]. " +
"Specify custom listener classes or make the default listener classes " +
"(and their required dependencies) available. Offending class: [%s]",
listenerClass.getName(), err.getMessage()));
catch (BeanInstantiationException ex) {
if (ex.getCause() instanceof NoClassDefFoundError) {
// TestExecutionListener not applicable due to a missing dependency
if (logger.isDebugEnabled()) {
logger.debug(String.format(
"Skipping candidate TestExecutionListener [%s] due to a missing dependency. " +
"Specify custom listener classes or make the default listener classes " +
"and their required dependencies available. Offending class: [%s]",
listenerClass.getName(), ex.getCause().getMessage()));
}
}
else {
throw ex;
}
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册