{"record":{"id":"a0f04e0e766d0785","repo":"apache/shenyu","slug":"extension-clazz-clazz-without-spi-annotation","errorCode":null,"errorMessage":"extension clazz (clazz) without @SPI Annotation","messagePattern":"extension clazz \\(clazz\\) without @SPI Annotation","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"shenyu-spi/src/main/java/org/apache/shenyu/spi/ExtensionLoader.java","lineNumber":100,"sourceCode":"    }\n    \n    /**\n     * Gets extension loader.\n     *\n     * @param <T>   the type parameter\n     * @param clazz the clazz\n     * @param cl    the cl\n     * @return the extension loader.\n     */\n    public static <T> ExtensionLoader<T> getExtensionLoader(final Class<T> clazz, final ClassLoader cl) {\n        \n        Objects.requireNonNull(clazz, \"extension clazz is null\");\n        \n        if (!clazz.isInterface()) {\n            throw new IllegalArgumentException(\"extension clazz (\" + clazz + \") is not interface!\");\n        }\n        if (!clazz.isAnnotationPresent(SPI.class)) {\n            throw new IllegalArgumentException(\"extension clazz (\" + clazz + \") without @\" + SPI.class + \" Annotation\");\n        }\n        ExtensionLoader<T> extensionLoader = (ExtensionLoader<T>) LOADERS.get(clazz);\n        if (Objects.nonNull(extensionLoader)) {\n            return extensionLoader;\n        }\n        LOADERS.putIfAbsent(clazz, new ExtensionLoader<>(clazz, cl));\n        return (ExtensionLoader<T>) LOADERS.get(clazz);\n    }\n    \n    /**\n     * Gets extension loader.\n     *\n     * @param <T>   the type parameter\n     * @param clazz the clazz\n     * @return the extension loader\n     */\n    public static <T> ExtensionLoader<T> getExtensionLoader(final Class<T> clazz) {\n        return getExtensionLoader(clazz, ExtensionLoader.class.getClassLoader());","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-spi/src/main/java/org/apache/shenyu/spi/ExtensionLoader.java#L82-L118","documentation":"getExtensionLoader requires the extension interface to carry the @SPI annotation, which marks it as an extension point (optionally with a default value like @SPI(\"roundRobin\")). This IllegalArgumentException is thrown when the class is a valid interface but lacks @SPI. The annotation is what tells the framework which implementation name is the default.","triggerScenarios":"Calling ExtensionLoader.getExtensionLoader(SomeInterface.class) where SomeInterface is an interface but is not annotated with @SPI.","commonSituations":"Writing a brand-new SPI interface and forgetting the @SPI annotation; passing a plain third-party interface (e.g. a JDK or Spring interface) to the ShenYu SPI loader; annotation removed during refactoring.","solutions":["Add @SPI to the interface declaration","Optionally specify a default: @SPI(\"defaultImplName\")","Confirm you are using org.apache.shenyu.spi.SPI, not another annotation with the same simple name"],"exampleFix":"// before\npublic interface LoadBalance { String select(...); }\n// after\n@SPI(\"roundRobin\")\npublic interface LoadBalance { String select(...); }","handlingStrategy":"validation","validationCode":"if (!LoadBalance.class.isAnnotationPresent(org.apache.shenyu.spi.SPI.class)) { throw new IllegalStateException(\"LoadBalance must be @SPI-annotated\"); }","typeGuard":null,"tryCatchPattern":"try { ExtensionLoader.getExtensionLoader(iface); } catch (IllegalArgumentException e) { log.error(\"Missing @SPI on {}: {}\", iface, e.getMessage()); }","preventionTips":["Annotate every interface you intend to load via ShenYu SPI with @SPI","Add an architecture/unit test asserting @SPI presence on interfaces in the spi package","Import the correct SPI annotation package (org.apache.shenyu.spi.SPI)"],"tags":["spi","java","annotation"],"backgroundTag":"missing-required-annotation","analyzedSha":"567142e07261b3e615ae8850b30f4421f455cc5d","analyzedAt":"2026-09-12T10:08:21.293Z","contentChangedAt":"2026-09-12T10:08:21.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}