apache/shenyu · error · UnsupportedOperationException

@ShenyuClient please use it on the interface.

Error message

@ShenyuClient please use it on the interface. 

What it means

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.

Solutions

  1. Extract the client methods into an interface annotated with @ShenyuClient and have the class implement it.
  2. Pass the interface Class to ShenyuClientFactoryBean/createProxy, not the implementation class.
  3. If using generics, ensure the resolved type parameter is the interface (check with apiClass.isInterface() in your own code first).

Example fix

// before
@ShenyuClient(name = "order")
public class OrderClient { @Get("/order") OrderDTO get(); }
// after
@ShenyuClient(name = "order")
public interface OrderClient { @Get("/order") OrderDTO get(); }
Defensive patterns

Strategy: validation

Validate before calling

if (!apiClass.isInterface()) {
    throw new IllegalArgumentException("@ShenyuClient target must be an interface: " + apiClass.getName());
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/2429aa068bf8e1ef. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/proxy/ShenyuClientProxyFactory.java:48

 */
public final class ShenyuClientProxyFactory {

    /**
     * PROXY_CACHE.
     */
    private static final ConcurrentMap<Class<?>, Object> PROXY_CACHE = new ConcurrentHashMap<>();

    /**
     * createProxy.
     *
     * @param apiClass apiClass
     * @param applicationContext applicationContext
     * @param shenyuClientFactoryBean shenyuClientFactoryBean
     * @return {@link Object}
     */
    public static Object createProxy(final Class<?> apiClass, final ApplicationContext applicationContext, final ShenyuClientFactoryBean shenyuClientFactoryBean) {
        if (!apiClass.isInterface()) {
            throw new UnsupportedOperationException("@ShenyuClient please use it on the interface. " + apiClass.getName());
        }

        if (PROXY_CACHE.containsKey(apiClass)) {
            return PROXY_CACHE.get(apiClass);
        }

        synchronized (apiClass) {
            Object proxy = Proxy.newProxyInstance(apiClass.getClassLoader(),
                    new Class<?>[]{apiClass},
                    new ShenyuClientInvocationHandler(apiClass, applicationContext, shenyuClientFactoryBean));
            PROXY_CACHE.put(apiClass, proxy);
        }
        return PROXY_CACHE.get(apiClass);
    }

}

View on GitHub (pinned to 567142e072)