baomidou/mybatis-plus · error · MybatisPlusException
Unsupported proxy type for Groovy lambda extraction: {}. Exp
Error message
Unsupported proxy type for Groovy lambda extraction: {}. Expected a Groovy ConvertedClosure handler exposing getDelegate(). What it means
GroovyLambdaMeta extracts the instantiated method/owner from a Groovy closure used as a lambda (e.g. in QueryWrapper lambdas under Groovy). It expects the closure to be a JDK Proxy whose InvocationHandler is a Groovy ConvertedClosure exposing getDelegate(). If handler.getClass().getMethod("getDelegate") throws NoSuchMethodException, mybatis-plus reports MybatisPlusException('Unsupported proxy type for Groovy lambda extraction: <handler class>').
Source
Thrown at mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/support/GroovyLambdaMeta.java:50
* @since 3.5.12
*/
public class GroovyLambdaMeta implements LambdaMeta {
private final Class<?> clazz;
private final String name;
public GroovyLambdaMeta(Proxy func) {
InvocationHandler handler = Proxy.getInvocationHandler(func);
try {
Method getDelegate = handler.getClass().getMethod("getDelegate");
Object delegate = getDelegate.invoke(handler);
Method getMethod = delegate.getClass().getMethod("getMethod");
this.name = (String) getMethod.invoke(delegate);
Method getOwner = delegate.getClass().getMethod("getOwner");
Object owner = getOwner.invoke(delegate);
this.clazz = (owner instanceof Class) ? (Class<?>) owner : owner.getClass();
} catch (NoSuchMethodException e) {
throw new MybatisPlusException("Unsupported proxy type for Groovy lambda extraction: "
+ handler.getClass().getName()
+ ". Expected a Groovy ConvertedClosure handler exposing getDelegate().", e);
} catch (Exception e) {
throw new MybatisPlusException("Failed to extract Groovy lambda meta from proxy handler: "
+ handler.getClass().getName(), e);
}
}
@Override
public String getImplMethodName() {
return name;
}
@Override
public Class<?> getInstantiatedClass() {
return clazz;
}
View on GitHub (pinned to bf67d90747)
Solutions
- Align Groovy versions with what the mybatis-plus release supports (check the release notes for Groovy support matrix).
- Avoid Groovy closure syntax in wrapper APIs: use the string/column-name wrappers (QueryWrapper.eq("col", val)) or explicit SFunction from Java.
- If you build custom proxies around closures, ensure the handler exposes getDelegate()/getMethod()/getOwner() like ConvertedClosure does.
- Upgrade mybatis-plus — Groovy lambda extraction robustness improved across 3.5.x patches.
Example fix
// before (Groovy): closure routed to GroovyLambdaMeta with unsupported handler
wrapper.eq({ it.name }, 'bob') // may explode on Groovy internals
// after: use column-name wrappers under Groovy
wrapper.eq('name', 'bob') Defensive patterns
Strategy: validation
Validate before calling
Object handler = Proxy.getInvocationHandler(func);
boolean groovyConvertible = false;
try {
handler.getClass().getMethod("getDelegate");
groovyConvertible = true;
} catch (NoSuchMethodException ignored) { }
if (!groovyConvertible) { /* use column-name wrappers instead */ } Type guard
static boolean isGroovyConvertedClosure(Object func) {
if (!(func instanceof Proxy)) return false;
try {
Proxy.getInvocationHandler(func).getClass().getMethod("getDelegate");
return true;
} catch (NoSuchMethodException e) {
return false;
}
} Try / catch
try {
wrapper.eq(SFunctionCast.toSFunction(closure), value);
} catch (MybatisPlusException e) {
// fall back to column-name condition when Groovy lambda extraction is unsupported
wrapper.eq("column_name", value);
} Prevention
- In Groovy code, prefer string-column wrapper conditions over closure syntax.
- Keep Groovy and mybatis-plus versions aligned with the compatibility matrix.
When it happens
Trigger: Using lambda QueryWrapper/LambdaQueryWrapper syntax inside Groovy code where the 'lambda' the framework receives is a plain Groovy Closure wrapped by a proxy whose invocation handler is not ConvertedClosure (or a different Groovy version's internal layout). The reflective contract on Groovy internals no longer holds.
Common situations: Groovy version upgrades that change closure proxy internals (MethodClosure vs ConvertedClosure handling); Grape/Groovy 4 vs 3 differences; passing a method reference or custom proxy where a true ConvertedClosure is expected; non-Groovy proxies routed into the Groovy branch of lambda resolution.
Related errors
- Failed to extract Groovy lambda meta from proxy handler: {}
- Failed to create a new Configuration instance.
- Unable to find a usable constructor for %s
- Unable to retrieve the mapperInterface and sqlSession proper
- There is neither 'privateLookupIn(Class, Lookup)' nor 'Looku
AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14).
Data as JSON: /api/errors/3b6d876887e63219.
Report an issue: GitHub.