I'm attempting to dynamically add services that are passed into the function concatOrNotFound
import akka.grpc.javadsl.ServiceHandler;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.HttpResponse;
import akka.japi.function.Function;
Function<HttpRequest, CompletionStage<HttpResponse>> greeterService =
GreeterServiceHandlerFactory.create(new GreeterServiceImpl(mat), sys);
Function<HttpRequest, CompletionStage<HttpResponse>> echoService =
EchoServiceHandlerFactory.create(new EchoServiceImpl(), sys);
@SuppressWarnings("unchecked")
Function<HttpRequest, CompletionStage<HttpResponse>> serviceHandlers =
ServiceHandler.concatOrNotFound(greeterService, echoService);
Http.get(sys)
.newServerAt("127.0.0.1", 8090)
.bind(serviceHandlers)
(https://doc.akka.io/docs/akka-grpc/current/server/walkthrough.html)
The concatOrNotFound
has following method signature :
@scala.annotation.varargs
def concatOrNotFound(handlers : akka.japi.Function[akka.http.javadsl.model.HttpRequest, java.util.concurrent.CompletionStage[akka.http.javadsl.model.HttpResponse]]*) : akka.japi.Function[akka.http.javadsl.model.HttpRequest, java.util.concurrent.CompletionStage[akka.http.javadsl.model.HttpResponse]] = { /* compiled code */ }
How to pass greeterService
& echoService
into as List and then invoke ServiceHandler.concatOrNotFound
on this List
?
As handlers
is a varargs I've tried the following :
List serviceList = new ArrayList();
serviceList.add(eventService);
serviceList.add(echoService);
@SuppressWarnings("unchecked") // Calling varargs method with generic instances
final Function<HttpRequest, CompletionStage<HttpResponse>> serviceHandlers =
ServiceHandler.concatOrNotFound(l.toArray(new Function[serviceList.size()]));
But this fails with compiler error :
Cannot resolve method 'concatOrNotFound(java.lang.Object[])'
What I’m attempting to achieve is use a list of services that is converted to varargs to be passed into the concatOrNotFound method. The reason I want use a list is that the list will be populated based on conditional logic that will determine which services are added to the list.
The other option I’m considering is iterate over the list and invoke concatOrNotFound for each list element where each list element is a service.
Update:
This appears to enable passing the List
into method with a varargs parameter:
List<akka.japi.Function<akka.http.javadsl.model.HttpRequest, java.util.concurrent.CompletionStage<akka.http.javadsl.model.HttpResponse>>> serviceList = new ArrayList();
serviceList.add(eventService);
serviceList.add(echoService);
final Function<HttpRequest, CompletionStage<HttpResponse>> serviceHandlers =
ServiceHandler.concatOrNotFound(Iterables.toArray(serviceList, akka.japi.Function.class));
Is explicitly typing the List type parameters to
List<akka.japi.Function<akka.http.javadsl.model.HttpRequest, java.util.concurrent.CompletionStage<akka.http.javadsl.model.HttpResponse>>>
required as a result of type erasure ?
I assume that in this case, scala sourced compiled byte code may differ from the actual intended written source code. It's one of the pitfalls of scala programming, and it's especially true with vararg Scala/Java interoperability.
Either that, or greeterService
and echoService
are inferred as different types with no common hierarchy, maybe due to vararg conversion itself. That's the cause for them being is inferred as Object
types in your 1st attempt. Look at ServiceHandler's source code: JFunction is expected
For your second attempt, you're doing List serviceList = new ArrayList();
which again, infers the elements as Object
instances and thus the compiler fails.
Is explicitly typing the List type parameters to List<akka.japi.Function<akka.http.javadsl.model.HttpRequest, java.util.concurrent.CompletionStage<akka.http.javadsl.model.HttpResponse>>>
required as a result of type erasure ?
Yes it is required, but it's not related to type-erasure. Generic types are discarded as part of the compilation process. Providing the concrete element type simply allows the compiler to understand correct types are passed to function calls expecting them
I don't have the source code in front of me, but you can initially type convert your services to JFunction
instances .you might have better luck with that. Another approach would be to gather them using a correctly typed JFunction
array to begin with.