Description
In working with a library that required extension of an SAM type to add a function binding, I thought of using @Category to soften the integration. What I found is that the implicit this parameter that is passed to the constructor of an anon. inner class is being transformed from the containing class to the category class due to the application of the @Category transform.
Below I have boiled it down to the fewest moving parts I can. LibraryContext is the type that needs functions bound to it and the interface for doing so is LibraryFunction which requires constructor params so I cannot use SAM Closure coercion. My first take was to create Factory.Binder to get the details out of the way. That resulted in the cast exception below. When I converted Binder to define static methods with a first param of LibraryContext all is well.
So I thought I would raise the issue that anon. inners and @Category are not currently compatible.
Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'scripts.LibraryContext@6a28ffa4' with class 'scripts.LibraryContext' to class 'scripts.Factory$Binder' org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'scripts.LibraryContext@6a28ffa4' with class 'scripts.LibraryContext' to class 'scripts.Factory$Binder' at scripts.Factory$Binder.bindStringFunction(CategoryTransform.groovy:18) at scripts.Factory$_create_closure1.doCall(CategoryTransform.groovy:10) at scripts.Factory$_create_closure1.doCall(CategoryTransform.groovy) at scripts.Factory.create(CategoryTransform.groovy:9) at scripts.Factory$create.call(Unknown Source) at scripts.CategoryTransform.run(CategoryTransform.groovy:42)
package scripts class Factory { private Factory() {} static LibraryContext create() { LibraryContext context = new LibraryContext() use (Binder) { context.bindStringFunction('', { String[] strings -> '' }) } return context } @Category(LibraryContext) private static class Binder { void bindStringFunction(String name, java.util.function.Function<String[], String> func) { def stringFunction = new LibarayFunction(name, 0) { // cast exception here due to implicit first param of "this" @Override String compute(String... args) { func.apply(args) } } this.bind(name, stringFunction) } } } class LibraryContext { void bind(String name, Object value) { } } abstract class LibarayFunction { LibarayFunction(String name, int argc) { } abstract String compute(String... argv); } Factory.create()