-
Notifications
You must be signed in to change notification settings - Fork 634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using a value class as a path parameter causes java.lang.IllegalArgumentException: argument type mismatch #585
Comments
The thing that's doing the wrapping is the
I see two ways that we could solve this. One is to detect discrepancies in the type signature, and check whether unwrapping a value class would solve the problem. Another is to let the compiler do the heavy lifting, and generate the code that invokes the service call using a macro, rather than using reflection. The second approach is possibly the simpler one. |
5 tasks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you use a value class (a class that extends
AnyVal
) as a path parameter in a Lagom service call, and define aPathParamSerializer
for it, it will fail at runtime with anIllegalArgumentException
.This simplified example illustrates why:
I create instances of the service and a
UserId
and try to inspect the types. Everything looks like it matches, but everything is not as it seems...This is a reflective lookup of the
user
method, and it's similar to what Lagom actually does at runtime. We can see that the type of the parameter isjava.lang.String
, which is what is intended when you use a value class: it should avoid allocating a wrapper.So why do the calls to
tmoore.getClass
andsvc.user(tmoore)
print that the class is theUserId
wrapper? There are certain situations in which the Scala compiler inserts code to explicitly allocate a wrapper. CallinggetClass
is one of them. You can see what's happening if you disassemble the method:Assigning to an array is another case that triggers wrapping:
Note that this is actually an
Array[UserId]
, not anArray[String]
, and that the type of an array is not erased at runtime in the way that generic classes are. So theUserId
wrapper must be created before the array assignment.This is what causes it to blow up at runtime:
The service method is expecting a
String
but gets a wrappedUserId
.Workaround
The best workaround at this time is to avoid the use of value classes in path parameters. We should add a warning to the documentation about this.
I think we could also add better runtime validation of service call parameter types. That wouldn't actually fix the problem, but it would make it more obvious why it's happening.
The text was updated successfully, but these errors were encountered: