{"id":"f979ee65dba2eb13","repo":"spring-projects/spring-framework","slug":"specified-class-ifc-getname-must-be-an-inter","errorCode":null,"errorMessage":"Specified class [{ifc.getName()}] must be an interface","messagePattern":"Specified class \\[(.+?)\\] must be an interface","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java","lineNumber":102,"sourceCode":"\t * Create a DefaultIntroductionAdvisor for the given advice.\n\t * @param advice the Advice to apply\n\t * @param ifc the interface to introduce\n\t */\n\tpublic DefaultIntroductionAdvisor(DynamicIntroductionAdvice advice, Class<?> ifc) {\n\t\tAssert.notNull(advice, \"Advice must not be null\");\n\t\tthis.advice = advice;\n\t\taddInterface(ifc);\n\t}\n\n\n\t/**\n\t * Add the specified interface to the list of interfaces to introduce.\n\t * @param ifc the interface to introduce\n\t */\n\tpublic void addInterface(Class<?> ifc) {\n\t\tAssert.notNull(ifc, \"Interface must not be null\");\n\t\tif (!ifc.isInterface()) {\n\t\t\tthrow new IllegalArgumentException(\"Specified class [\" + ifc.getName() + \"] must be an interface\");\n\t\t}\n\t\tthis.interfaces.add(ifc);\n\t}\n\n\t@Override\n\tpublic Class<?>[] getInterfaces() {\n\t\treturn ClassUtils.toClassArray(this.interfaces);\n\t}\n\n\t@Override\n\tpublic void validateInterfaces() throws IllegalArgumentException {\n\t\tfor (Class<?> ifc : this.interfaces) {\n\t\t\tif (this.advice instanceof DynamicIntroductionAdvice dynamicIntroductionAdvice &&\n\t\t\t\t\t!dynamicIntroductionAdvice.implementsInterface(ifc)) {\n\t\t\t\tthrow new IllegalArgumentException(\"DynamicIntroductionAdvice [\" + this.advice + \"] \" +\n\t\t\t\t\t\t\"does not implement interface [\" + ifc.getName() + \"] specified for introduction\");\n\t\t\t}\n\t\t}","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java#L84-L120","documentation":"DefaultIntroductionAdvisor.addInterface throws IllegalArgumentException when the Class passed is not an interface. Spring AOP introductions can only add interfaces to a proxy (the proxy then implements them and dispatches to the advice); introducing a concrete class has no meaning and is rejected.","triggerScenarios":"Calling advisor.addInterface(MyImpl.class) or new DefaultIntroductionAdvisor(advice, MyImpl.class) where MyImpl is a concrete class rather than an interface.","commonSituations":"Confusing the mixin implementation class with the interface it implements; passing defaultImplType where interfaceType is expected; refactoring an interface into a class.","solutions":["Pass the interface type (e.g. Lockable.class), not the implementation class.","Guard with Class.isInterface() before calling addInterface.","Use DelegatePerTargetObjectIntroductionInterceptor(implType, interfaceType) keeping the two distinct."],"exampleFix":"// before\nadvisor.addInterface(LockableImpl.class); // concrete class -> error 117\n\n// after\nadvisor.addInterface(Lockable.class); // the interface","handlingStrategy":"type-guard","validationCode":"if (!ifc.isInterface()) {\n    throw new IllegalArgumentException(ifc.getName() + \" is not an interface\");\n}","typeGuard":"boolean isIntroductionInterface(Class<?> ifc) {\n    return ifc != null && ifc.isInterface();\n}","tryCatchPattern":null,"preventionTips":["Always pass the interface, not its implementation, to addInterface.","Keep DelegatePerTargetObjectIntroductionInterceptor's defaultImplType/interfaceType distinct.","Add a type guard in any code that wires introductions dynamically."],"tags":["spring-aop","introduction","type-validation","interface"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}