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

Proper NoClassDefFoundError check against BeanUtils.instantiateClass

Issue: SPR-16369
上级 32b42799
...@@ -98,12 +98,18 @@ public abstract class BeanUtils { ...@@ -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 * <p>Note that this method tries to set the constructor accessible
* if given a non-accessible (that is, non-public) constructor. * 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 * @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 * @see Constructor#newInstance
*/ */
public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException { public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
...@@ -113,10 +119,7 @@ public abstract class BeanUtils { ...@@ -113,10 +119,7 @@ public abstract class BeanUtils {
} }
try { try {
Constructor<T> ctor = (KotlinDetector.isKotlinType(clazz) ? Constructor<T> ctor = (KotlinDetector.isKotlinType(clazz) ?
KotlinDelegate.findPrimaryConstructor(clazz) : clazz.getDeclaredConstructor()); KotlinDelegate.getPrimaryConstructor(clazz) : clazz.getDeclaredConstructor());
if (ctor == null) {
throw new BeanInstantiationException(clazz, "No default constructor found");
}
return instantiateClass(ctor); return instantiateClass(ctor);
} }
catch (NoSuchMethodException ex) { catch (NoSuchMethodException ex) {
...@@ -693,10 +696,26 @@ public abstract class BeanUtils { ...@@ -693,10 +696,26 @@ public abstract class BeanUtils {
private static class KotlinDelegate { 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 * @param clazz the {@link Class} of the Kotlin class
* @see <a href="http://kotlinlang.org/docs/reference/classes.html#constructors"> * @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 @Nullable
public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) { public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
...@@ -706,8 +725,10 @@ public abstract class BeanUtils { ...@@ -706,8 +725,10 @@ public abstract class BeanUtils {
return null; return null;
} }
Constructor<T> constructor = ReflectJvmMapping.getJavaConstructor(primaryCtor); Constructor<T> constructor = ReflectJvmMapping.getJavaConstructor(primaryCtor);
Assert.notNull(constructor, if (constructor == null) {
() -> "Failed to find Java constructor for Kotlin primary constructor: " + clazz.getName()); throw new IllegalStateException(
"Failed to find Java constructor for Kotlin primary constructor: " + clazz.getName());
}
return constructor; return constructor;
} }
catch (UnsupportedOperationException ex) { catch (UnsupportedOperationException ex) {
...@@ -718,7 +739,8 @@ public abstract class BeanUtils { ...@@ -718,7 +739,8 @@ public abstract class BeanUtils {
/** /**
* Instantiate a Kotlin class using the provided constructor. * Instantiate a Kotlin class using the provided constructor.
* @param ctor the constructor of the Kotlin class to instantiate * @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) public static <T> T instantiateClass(Constructor<T> ctor, Object... args)
throws IllegalAccessException, InvocationTargetException, InstantiationException { throws IllegalAccessException, InvocationTargetException, InstantiationException {
......
...@@ -28,6 +28,7 @@ import java.util.Set; ...@@ -28,6 +28,7 @@ import java.util.Set;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
...@@ -178,18 +179,25 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot ...@@ -178,18 +179,25 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
return listeners; return listeners;
} }
private List<TestExecutionListener> instantiateListeners(Collection<Class<? extends TestExecutionListener>> classesList) { private List<TestExecutionListener> instantiateListeners(Collection<Class<? extends TestExecutionListener>> classes) {
List<TestExecutionListener> listeners = new ArrayList<>(classesList.size()); List<TestExecutionListener> listeners = new ArrayList<>(classes.size());
for (Class<? extends TestExecutionListener> listenerClass : classesList) { for (Class<? extends TestExecutionListener> listenerClass : classes) {
try { try {
listeners.add(BeanUtils.instantiateClass(listenerClass)); listeners.add(BeanUtils.instantiateClass(listenerClass));
} }
catch (NoClassDefFoundError err) { catch (BeanInstantiationException ex) {
if (logger.isDebugEnabled()) { if (ex.getCause() instanceof NoClassDefFoundError) {
logger.debug(String.format("Could not instantiate TestExecutionListener [%s]. " + // TestExecutionListener not applicable due to a missing dependency
"Specify custom listener classes or make the default listener classes " + if (logger.isDebugEnabled()) {
"(and their required dependencies) available. Offending class: [%s]", logger.debug(String.format(
listenerClass.getName(), err.getMessage())); "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.
先完成此消息的编辑!
想要评论请 注册