spring-projects/spring-framework · error · BeanInstantiationException

Specified class is an interface

Error message

Specified class is an interface

What it means

Thrown as BeanInstantiationException by the deprecated BeanUtils.instantiate(Class) at BeanUtils.java:102 when the supplied class is an interface (clazz.isInterface() == true). The method itself is deprecated because it delegates to the deprecated Class.newInstance(); prefer instantiateClass(Class). There is no underlying cause because the JVM cannot instantiate an interface at all.

Solutions

  1. Switch to the non-deprecated BeanUtils.instantiateClass(Class) and pass a concrete class.
  2. Provide a concrete implementation class instead of the interface type.
  3. If you must support interface-based lookup, resolve the implementation (e.g. via @Component scan or a ServiceLoader) before instantiation.
  4. Validate !clazz.isInterface() before calling instantiate.

Example fix

// before (deprecated)
Runnable r = BeanUtils.instantiate(Runnable.class); // interface

// after
Runnable r = BeanUtils.instantiateClass(MyRunnableImpl.class);
Defensive patterns

Strategy: validation

Validate before calling

if (!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) {
    BeanUtils.instantiate(clazz); // legacy path
}

Type guard

static boolean instantiableLegacy(Class<?> c) {
    return !c.isInterface() && !Modifier.isAbstract(c.getModifiers())
        && !c.isPrimitive() && !c.isArray();
}

Try / catch

try {
    BeanUtils.instantiate(clazz);
} catch (BeanInstantiationException ex) {
    if ("Specified class is an interface".equals(ex.getMessage())) {
        // resolve a concrete impl or skip
    } else throw ex;
}

Prevention

When it happens

Trigger: Calling BeanUtils.instantiate(SomeInterface.class) (or any code path that still uses the deprecated instantiate) where the Class argument is java.lang.Runnable, a repository/service interface, Map, etc. The isInterface() guard rejects it before any newInstance() attempt.

Common situations: Migrating legacy code that used Class.newInstance(); passing a Class loaded from config that resolves to an interface; reflection over plugin descriptors where the extension point is an interface; accidental wiring of an interface class instead of its implementation.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/d4687a7a6af8bdce. Report an issue: GitHub.

Appendix: source

Thrown at spring-beans/src/main/java/org/springframework/beans/BeanUtils.java:102

			double.class, 0D,
			char.class, '\0');

	private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent();


	/**
	 * Convenience method to instantiate a class using its no-arg constructor.
	 * @param clazz class to instantiate
	 * @return the new instance
	 * @throws BeanInstantiationException if the bean cannot be instantiated
	 * @see Class#newInstance()
	 * @deprecated following the deprecation of {@link Class#newInstance()} in JDK 9
	 */
	@Deprecated(since = "5.0")
	public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
		Assert.notNull(clazz, "Class must not be null");
		if (clazz.isInterface()) {
			throw new BeanInstantiationException(clazz, "Specified class is an interface");
		}
		try {
			return clazz.newInstance();
		}
		catch (InstantiationException ex) {
			throw new BeanInstantiationException(clazz, "Is it an abstract class?", ex);
		}
		catch (IllegalAccessException ex) {
			throw new BeanInstantiationException(clazz, "Is the constructor accessible?", ex);
		}
	}

	/**
	 * 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.

View on GitHub (pinned to 69bf83ad71)