{"record":{"id":"2429aa068bf8e1ef","repo":"apache/shenyu","slug":"shenyuclient-please-use-it-on-the-interface","errorCode":null,"errorMessage":"@ShenyuClient please use it on the interface. ","messagePattern":"@ShenyuClient please use it on the interface\\. ","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/proxy/ShenyuClientProxyFactory.java","lineNumber":48,"sourceCode":" */\npublic final class ShenyuClientProxyFactory {\n\n    /**\n     * PROXY_CACHE.\n     */\n    private static final ConcurrentMap<Class<?>, Object> PROXY_CACHE = new ConcurrentHashMap<>();\n\n    /**\n     * createProxy.\n     *\n     * @param apiClass apiClass\n     * @param applicationContext applicationContext\n     * @param shenyuClientFactoryBean shenyuClientFactoryBean\n     * @return {@link Object}\n     */\n    public static Object createProxy(final Class<?> apiClass, final ApplicationContext applicationContext, final ShenyuClientFactoryBean shenyuClientFactoryBean) {\n        if (!apiClass.isInterface()) {\n            throw new UnsupportedOperationException(\"@ShenyuClient please use it on the interface. \" + apiClass.getName());\n        }\n\n        if (PROXY_CACHE.containsKey(apiClass)) {\n            return PROXY_CACHE.get(apiClass);\n        }\n\n        synchronized (apiClass) {\n            Object proxy = Proxy.newProxyInstance(apiClass.getClassLoader(),\n                    new Class<?>[]{apiClass},\n                    new ShenyuClientInvocationHandler(apiClass, applicationContext, shenyuClientFactoryBean));\n            PROXY_CACHE.put(apiClass, proxy);\n        }\n        return PROXY_CACHE.get(apiClass);\n    }\n\n}\n","sourceCodeStart":30,"sourceCodeEnd":65,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/proxy/ShenyuClientProxyFactory.java#L30-L65","documentation":"ShenyuClientProxyFactory.createProxy() builds a JDK dynamic proxy, which can only implement interfaces. It checks apiClass.isInterface() first and throws UnsupportedOperationException when a concrete class is passed, reminding users that @ShenyuClient must be placed on an interface.","triggerScenarios":"Passing a concrete class to createProxy / the factory bean — e.g. annotating a class with @ShenyuClient, or programmatically registering ShenyuClientFactoryBean with a class type instead of an interface.","commonSituations":"Coming from other HTTP client frameworks that allow classes; refactoring merged interface into a class; generic type resolution returning the implementation class instead of the interface; misconfigured Class<T> parameter.","solutions":["Extract the client methods into an interface annotated with @ShenyuClient and have the class implement it.","Pass the interface Class to ShenyuClientFactoryBean/createProxy, not the implementation class.","If using generics, ensure the resolved type parameter is the interface (check with apiClass.isInterface() in your own code first)."],"exampleFix":"// before\n@ShenyuClient(name = \"order\")\npublic class OrderClient { @Get(\"/order\") OrderDTO get(); }\n// after\n@ShenyuClient(name = \"order\")\npublic interface OrderClient { @Get(\"/order\") OrderDTO get(); }","handlingStrategy":"validation","validationCode":"if (!apiClass.isInterface()) {\n    throw new IllegalArgumentException(\"@ShenyuClient target must be an interface: \" + apiClass.getName());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Define clients only as interfaces annotated with @ShenyuClient.","Pass interface Class tokens to ShenyuClientFactoryBean, never implementations.","Check generic type resolution returns the interface when building clients reflectively."],"tags":["proxy","api-misuse","startup"],"backgroundTag":"invalid-argument-value","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"}