Proper NoClassDefFoundError check against BeanUtils.instantiateClass
Issue: SPR-16369
This commit is contained in:
parent
32b4279929
commit
214576673a
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue