Variable length argument lists (varargs) have been around since Java 5 (so quite a long while), yet I get the impression that many people either don’t know about this feature or their tools don’t support it. I ran into one of them working with Netty from Clojure and it wasn’t trivial at all how to use them through interop.
In Java, calling that vararg constructor of Http2ServerUpgradeCodec isn’t complicated at all. Just give it any number of ChannelHandlers and you’re good.
new Http2ServerUpgradeCodec(codec, awesomeHandler);
Doing the same from Clojure doesn’t work as expected though.
(Http2ServerUpgradeCodec. codec awesome-handler)
First, this reflects. It’s gonna say something along the lines of “Reflection warning, call to io.netty.handler.codec.http2.Http2ServerUpgradeCodec ctor can’t be resolved.” And then an IllegalArgumentException, saying “No matching ctor found” for the class. But… why?
I can’t go too deep with the why’s. I can say that the immediate reason is that varargs have to be passed as arrays of the given class from Clojure. It’s sad that it’s not smoother than that. Naturally just wrapping your handler(s) in a vector won’t do – I figure it’d do nasty things if the elements are different types? It has to be specifically an array of the class ChannelHandler… which can be made with
(Http2ServerUpgradeCodec. codec (into-array ChannelHandler [awesome-handler])
Now this works, but it still reflects. That’s pretty amusing considering you’re explicitly making a Java array out of a Java class. Apparently that’s not enough. As with reflection usually, a type hint solves the issue – just type hinting arrays isn’t exactly intuitive.
For an array of bytes it’d be
^"[B". What a meaningful and legible designation. By the way if you want to handle bytes in a protocol, you’ll have to use
(Class/forName "[B") because parsing
bytes as equivalent would be too simple. For non-primitive classes that turns into
^"[Lfully.qualified.AwesomeClass;" and that trailing semicolon is required. So to get rid of the nasty reflection warning, the code will need a hint like that.
(Http2ServerUpgradeCodec. codec ^"[Lio.netty.channel.ChannelHandler;" (into-array ChannelHandler [awesome-handler]))
That with both
awesome-handler type-hinted at definition. Its verbosity is funny in the light of how Clojure prides itself as being much more concise and readable than Java. Well, in this case Java is 51 characters (2 parens and a semicolon) while Clojure doubles that at 115 characters with 7 brackets and a semicolon.