Javalin: Groovy Calls to Context.pathParam("param") or .body() Results in UnsupportedOperationException

Created on 7 May 2019  路  13Comments  路  Source: tipsy/javalin

Actual behavior (the bug)
Calls to Context.pathParam("param") or .body() result in an UnsupportedOperationException being thrown.

Expected behavior
Supposing that the path parameter "param" exists, pathParam("param") should return the corresponding path parameter value. Calls to .body() should return the body variables map.

To Reproduce
Create get route to test pathParam and a post route to test .body()
In the get route Handler, make a call to the context's pathParam function.
In the post route Handler, make a call to contexts body() function.
Start Javalin 2.8.0 in Groovy 2.5.0.
Navigate such that either route is called.
The Handler should crash and display a UnsupportedOperationException specifically stating: "This function has a reified type parameter and thus can only be inlined at compilation time, not called directly."

Additional context
The issues appears to be Groovy using the Kotlin only version of the methods. Of note, the pathParam issue is not present in 2.7.0, however the .body() issue is present through version 2.0.0.
The relevant line in Context.kt for pathParam (this is the one referred to in the stack trace) is: https://github.com/tipsy/javalin/blob/68b2f7592f237db1c2b597e645697eb75fdaee53/src/main/java/io/javalin/http/Context.kt#L190

Attached below is an image of the stack trace for the error:
Screen Shot 2019-05-06 at 10 37 56 PM

QUESTION

All 13 comments

Not sure why inline reified function got called, but not possible to use them from outside Kotlin. Neither groovy, nor java supports the function as they're not aware of such transformation.

Regarding groovy's access to the pathParamMap which is internal, use one of these:

String a = ctx.pathParamMap().id;
String b = ctx.pathParam("id");
Integer c = ctx.pathParam("id", Integer).get();

The stacktrace is not from the code in the last image, is it?

I apologize, that my example image is actually inaccurate, that actually was the temporary fix. That should have read
def id = ctx.pathParam("id");

Edit: Above post was edited to remove the image since it wasn't applicable.

Thank you for your reply though. I'm not sure why the Kotlin version is visible either.

I suspect groovy doesn't respect Kotlin's visibility on that map. I'll take a look into why ctx.pathParam("id"); doesn't work

Just confirmed, groovy chooses (probably because it ignores specifics of inline reified) inline reified on ctx.pathParam("id) since both classical and reified functions resolve to string pathParam(string). I can only guess that groovy, given this ambiguous situation chooses later declaration (which is the inline reified declaration).

So this is more of groovy and java issue (neither java can call reified, but at least String id = ctx.pathParam("id") is resolved correctly)

Your options are:

String a = ctx.pathParamMap().id;
String b = ctx.pathParam("id");
Integer c = ctx.pathParam("id", Integer).get();

@tipsy, we could consider something to get rid of ambiguity where groovy sees both pathParam(string): string and inline pathParam(string): T as identical methods and chooses the later (accidentally, or chooses last declaration I can guess). This could be naming methods differently. Or we could describe these situations with inline reifed functions somewhere in dedicated short section for groovy. Thoughts?

Noted, thank you @ernestas2k for your help. Do you think this is the cause of the same error on calls to .body() on context instances as well?

Yes, same reason (java.lang.UnsupportedOperationException: This function has a reified type parameter and thus can only be inlined at compilation time, not called directly.).
Here are alternatives to use:

ctx.bodyAsClass(String) // thats what you actually call internally when you perform .body()
ctx.bodyAsClass(MyClass) 

I hope these alternatives are ok for you :)

I think they will work. I appreciate you assistance in the matter. Thank you @ernestas2k :)

Note, that unfortunatelly you'll face this issue for all inline reified methods (body, request param, form param, etc), but you can find alternatives in the same file: https://github.com/tipsy/javalin/blob/master/src/main/java/io/javalin/http/Context.kt

Let's see what @tipsy thinks of this _incompatibility_

I'll have a closer look in a few days (I'm on a trip), but my general attitude is that we shouldn't add additional complexity in order to accommodate groovy users. Adding docs would be great though.

I lean towards your opinion, since this is something groovy compiler should be aware of (I'll try to raise this question in groovys tracker when I find free time). Meanwhile docs should help, I'll try to summarize these issues with a separate pull request.

@ernestas2k Great, I think adding docs is the best solution. Changing method names is not going to happen, but we could change method order (if that matters). It's not something that people should rely on though, so I think it's really up to the groovy devs to fix this.

Registered the bug in groovy tracker: https://issues.apache.org/jira/browse/GROOVY-9114
Let's see what they think.

Seems like they're on top of it. I don't think it makes sense to keep this issue open, but please post an update if you hear anything from them. Nice work on the debugging and creating a reproducible example!

Was this page helpful?
0 / 5 - 0 ratings