we've been encountering a strange compiler error when making special use of generics in GWT RPC service parameters. I've tried to boil it down to an example that you can find here as a ready-to-fail Eclipse project: https://drive.google.com/file/d/0BzPFwCC87Ht6VVVoQ0hjY3BoREU/view?usp=sharing
Compiling module gwt.generics.bug.Gwt_generics_bug
Computing all possible rebind results for 'gwt.generics.bug.client.GreetingService'
Rebinding gwt.generics.bug.client.GreetingService
Invoking generator com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator
[ERROR] Generator 'com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator' threw an exception while rebinding 'gwt.generics.bug.client.GreetingService'
java.lang.ArrayIndexOutOfBoundsException: 1
at com.google.gwt.user.rebind.rpc.TypeParameterExposureComputer.getFlowInfo(TypeParameterExposureComputer.java:420)
at com.google.gwt.user.rebind.rpc.TypeParameterExposureComputer.access$200(TypeParameterExposureComputer.java:40)
at com.google.gwt.user.rebind.rpc.TypeParameterExposureComputer$TypeParameterFlowInfo.getFlowInfo(TypeParameterExposureComputer.java:322)
at com.google.gwt.user.rebind.rpc.TypeParameterExposureComputer$TypeParameterFlowInfo.recordCausesExposure(TypeParameterExposureComputer.java:329)
at com.google.gwt.user.rebind.rpc.TypeParameterExposureComputer$TypeParameterFlowInfo.computeIndirectExposureCauses(TypeParameterExposureComputer.java:269)
at com.google.gwt.user.rebind.rpc.TypeParameterExposureComputer$TypeParameterFlowInfo.initializeExposure(TypeParameterExposureComputer.java:195)
at com.google.gwt.user.rebind.rpc.TypeParameterExposureComputer$TypeParameterFlowInfo.updateFlowInfo(TypeParameterExposureComputer.java:169)
at com.google.gwt.user.rebind.rpc.TypeParameterExposureComputer.computeTypeParameterExposure(TypeParameterExposureComputer.java:398)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.getFlowInfo(SerializableTypeOracleBuilder.java:1373)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.getTypeParameterExposure(SerializableTypeOracleBuilder.java:1006)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.checkTypeArgument(SerializableTypeOracleBuilder.java:1330)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.checkSubtype(SerializableTypeOracleBuilder.java:1176)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.checkSubtypes(SerializableTypeOracleBuilder.java:1262)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.computeTypeInstantiability(SerializableTypeOracleBuilder.java:994)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.checkTypeArgument(SerializableTypeOracleBuilder.java:1337)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.checkSubtype(SerializableTypeOracleBuilder.java:1176)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.checkSubtypes(SerializableTypeOracleBuilder.java:1262)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.computeTypeInstantiability(SerializableTypeOracleBuilder.java:994)
at com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder.build(SerializableTypeOracleBuilder.java:792)
at com.google.gwt.user.rebind.rpc.ProxyCreator.create(ProxyCreator.java:324)
at com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator.generateIncrementally(ServiceInterfaceProxyGenerator.java:67)
at com.google.gwt.dev.javac.StandardGeneratorContext.runGeneratorIncrementally(StandardGeneratorContext.java:754)
at com.google.gwt.dev.cfg.RuleGenerateWith.realize(RuleGenerateWith.java:160)
at com.google.gwt.dev.shell.StandardRebindOracle$Rebinder.rebind(StandardRebindOracle.java:79)
at com.google.gwt.dev.shell.StandardRebindOracle.rebind(StandardRebindOracle.java:276)
at com.google.gwt.dev.shell.StandardRebindOracle.rebind(StandardRebindOracle.java:265)
at com.google.gwt.dev.DistillerRebindPermutationOracle.getAllPossibleRebindAnswers(DistillerRebindPermutationOracle.java:87)
at com.google.gwt.dev.jjs.impl.UnifyAst$UnifyVisitor.createStaticRebindExpression(UnifyAst.java:485)
at com.google.gwt.dev.jjs.impl.UnifyAst$UnifyVisitor.createRebindExpression(UnifyAst.java:443)
at com.google.gwt.dev.jjs.impl.UnifyAst$UnifyVisitor.handleMagicMethodCall(UnifyAst.java:576)
at com.google.gwt.dev.jjs.impl.UnifyAst$UnifyVisitor.endVisit(UnifyAst.java:306)
at com.google.gwt.dev.jjs.ast.JMethodCall.traverse(JMethodCall.java:248)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:381)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:293)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:285)
at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:128)
at com.google.gwt.dev.jjs.ast.JExpressionStatement.traverse(JExpressionStatement.java:42)
at com.google.gwt.dev.jjs.ast.JModVisitor$ListContext.traverse(JModVisitor.java:95)
at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemove(JModVisitor.java:351)
at com.google.gwt.dev.jjs.ast.JBlock.traverse(JBlock.java:92)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:381)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:293)
at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:149)
at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:145)
at com.google.gwt.dev.jjs.ast.JMethodBody.traverse(JMethodBody.java:83)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:381)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:293)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:285)
at com.google.gwt.dev.jjs.ast.JMethod.visitChildren(JMethod.java:600)
at com.google.gwt.dev.jjs.ast.JMethod.traverse(JMethod.java:569)
at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:381)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:293)
at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:285)
at com.google.gwt.dev.jjs.impl.UnifyAst.mainLoop(UnifyAst.java:1505)
at com.google.gwt.dev.jjs.impl.UnifyAst.exec(UnifyAst.java:870)
at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler$Precompiler.unifyJavaAst(JavaToJavaScriptCompiler.java:1305)
at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler$Precompiler.constructJavaAst(JavaToJavaScriptCompiler.java:1038)
at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler$Precompiler.precompile(JavaToJavaScriptCompiler.java:954)
at com.google.gwt.dev.jjs.MonolithicJavaToJavaScriptCompiler.precompile(MonolithicJavaToJavaScriptCompiler.java:303)
at com.google.gwt.dev.jjs.JavaScriptCompiler.precompile(JavaScriptCompiler.java:38)
at com.google.gwt.dev.Precompile.precompile(Precompile.java:286)
at com.google.gwt.dev.Precompile.precompile(Precompile.java:229)
at com.google.gwt.dev.Precompile.precompile(Precompile.java:145)
at com.google.gwt.dev.Compiler.run(Compiler.java:206)
at com.google.gwt.dev.Compiler.run(Compiler.java:158)
at com.google.gwt.dev.Compiler$1.run(Compiler.java:120)
at com.google.gwt.dev.CompileTaskRunner.doRun(CompileTaskRunner.java:55)
at com.google.gwt.dev.CompileTaskRunner.runWithAppropriateLogger(CompileTaskRunner.java:50)
at com.google.gwt.dev.Compiler.main(Compiler.java:127)
[ERROR] Errors in 'gwt/generics/bug/client/Gwt_generics_bug.java'
[ERROR] Line 14: Failed to resolve 'gwt.generics.bug.client.GreetingService' via deferred binding
The issue occurs with version 2.7.0. I haven't gotten around to testing the same with the 2.8.0 snapshot that is available so far. It would be great if someone could try the project in that context.
To reproduce, I've started a GWT project from scratch in Eclipse, letting the project wizard do its thing, then adjusted the service method as follows:
public class Pair<A, B> implements IsSerializable { ... }
with the usual, trivial implementation. The entry point is as simple as possible:
So far, this seems not special at all, and it is hard to see why the compiler would throw up on this. However, I debugged the compiler run (adding -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y to the VM arguments of the compiler launch) and found out that the compiler is having trouble with some seemingly unrelated type which happens to subclass Pair<A, B> as follows:
public class SpecialPair<A extends BoundsInterface> extends Pair<TwoTypeArgInterface<?, A>, A> {
BoundsInterface is an empty marker interface, and TwoTypeArgInterface looks like this:
public interface TwoTypeArgInterface<A extends InterfaceWithOneTypeArg<B>, B extends BoundsInterface> {}
The compiler debug session suggests that the compiler confuses the formal parameter "A" of class SpecialPair, occurring with ordinal 0, with its use as actual type parameter in the instantiation of TwoTypeArgInterface where it occurs with index 1. This index 1 is then used to look up the formal parameter in SpecialPair's type parameter list, leading to the ArrayIndexOutOfBoundsException above.
I hope someone from the compiler team could have a look.
In the meantime, we have worked around the issue by more or less repeating the Pair<A, B> implementation for the SpecialPair use case such that subclassing the two-type-params class Pair<A, B> is not necessary for the SpecialPair implementation anymore. This lets the compile succeed for us. Still, I'm of the opinion that this is a compiler bug that should be fixed, if it isn't already in 2.8.0 in which case this would only be "for the record" ;-).