diff --git a/jvm-runtime/ftl-runtime/common/deployment/src/main/java/xyz/block/ftl/deployment/ModuleBuilder.java b/jvm-runtime/ftl-runtime/common/deployment/src/main/java/xyz/block/ftl/deployment/ModuleBuilder.java index 98f3c4d93..914c47db2 100644 --- a/jvm-runtime/ftl-runtime/common/deployment/src/main/java/xyz/block/ftl/deployment/ModuleBuilder.java +++ b/jvm-runtime/ftl-runtime/common/deployment/src/main/java/xyz/block/ftl/deployment/ModuleBuilder.java @@ -17,7 +17,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.regex.Pattern; @@ -36,7 +35,6 @@ import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import io.quarkus.arc.processor.DotNames; import xyz.block.ftl.Config; @@ -73,7 +71,6 @@ import xyz.block.ftl.schema.v1.TypeAlias; import xyz.block.ftl.schema.v1.Unit; import xyz.block.ftl.schema.v1.Verb; -import xyz.block.ftl.v1.CallRequest; public class ModuleBuilder { @@ -190,7 +187,7 @@ public void registerVerbMethod(MethodInfo method, String className, boolean exported, BodyType bodyType, Consumer metadataCallback) { try { List> parameterTypes = new ArrayList<>(); - List> paramMappers = new ArrayList<>(); + List paramMappers = new ArrayList<>(); org.jboss.jandex.Type bodyParamType = null; Nullability bodyParamNullability = Nullability.MISSING; @@ -199,7 +196,9 @@ public void registerVerbMethod(MethodInfo method, String className, MetadataCalls.Builder callsMetadata = MetadataCalls.newBuilder(); MetadataConfig.Builder configMetadata = MetadataConfig.newBuilder(); MetadataSecrets.Builder secretMetadata = MetadataSecrets.newBuilder(); + var pos = -1; for (var param : method.parameters()) { + pos++; if (param.hasAnnotation(Secret.class)) { Class paramType = ModuleBuilder.loadClass(param.type()); parameterTypes.add(paramType); @@ -248,7 +247,7 @@ public void registerVerbMethod(MethodInfo method, String className, Class paramType = ModuleBuilder.loadClass(param.type()); parameterTypes.add(paramType); //TODO: map and list types - paramMappers.add(new VerbRegistry.BodySupplier(paramType)); + paramMappers.add(new VerbRegistry.BodySupplier(pos)); } else { throw new RuntimeException("Unknown parameter type " + param.type() + " on FTL method: " + method.declaringClass().name() + "." + method.name()); diff --git a/jvm-runtime/ftl-runtime/common/runtime/src/main/java/xyz/block/ftl/runtime/FTLRecorder.java b/jvm-runtime/ftl-runtime/common/runtime/src/main/java/xyz/block/ftl/runtime/FTLRecorder.java index 3b67e8e65..8dac19302 100644 --- a/jvm-runtime/ftl-runtime/common/runtime/src/main/java/xyz/block/ftl/runtime/FTLRecorder.java +++ b/jvm-runtime/ftl-runtime/common/runtime/src/main/java/xyz/block/ftl/runtime/FTLRecorder.java @@ -6,7 +6,6 @@ import java.util.List; import java.util.Timer; import java.util.TimerTask; -import java.util.function.BiFunction; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; import org.jboss.resteasy.reactive.server.core.parameters.ParameterExtractor; @@ -27,7 +26,7 @@ public class FTLRecorder { public static final String X_FTL_VERB = "X-ftl-verb"; public void registerVerb(String module, String verbName, String methodName, List> parameterTypes, - Class verbHandlerClass, List> paramMappers, + Class verbHandlerClass, List paramMappers, boolean allowNullReturn) { //TODO: this sucks try { @@ -67,11 +66,11 @@ public void registerEnum(Class ennum, List> variants) { } } - public BiFunction topicSupplier(String className, String callingVerb) { + public VerbRegistry.ParameterSupplier topicSupplier(String className, String callingVerb) { try { var cls = Thread.currentThread().getContextClassLoader().loadClass(className.replace("/", ".")); var topic = cls.getDeclaredConstructor(String.class).newInstance(callingVerb); - return new BiFunction() { + return new VerbRegistry.ParameterSupplier() { @Override public Object apply(ObjectMapper mapper, CallRequest callRequest) { return topic; @@ -82,11 +81,11 @@ public Object apply(ObjectMapper mapper, CallRequest callRequest) { } } - public BiFunction verbClientSupplier(String className) { + public VerbRegistry.ParameterSupplier verbClientSupplier(String className) { try { var cls = Thread.currentThread().getContextClassLoader().loadClass(className.replace("/", ".")); var client = cls.getDeclaredConstructor().newInstance(); - return new BiFunction() { + return new VerbRegistry.ParameterSupplier() { @Override public Object apply(ObjectMapper mapper, CallRequest callRequest) { return client; @@ -97,8 +96,8 @@ public Object apply(ObjectMapper mapper, CallRequest callRequest) { } } - public BiFunction leaseClientSupplier() { - return new BiFunction() { + public VerbRegistry.ParameterSupplier leaseClientSupplier() { + return new VerbRegistry.ParameterSupplier() { @Override public Object apply(ObjectMapper mapper, CallRequest callRequest) { diff --git a/jvm-runtime/ftl-runtime/common/runtime/src/main/java/xyz/block/ftl/runtime/VerbRegistry.java b/jvm-runtime/ftl-runtime/common/runtime/src/main/java/xyz/block/ftl/runtime/VerbRegistry.java index cb9a7e9d6..c02ceb813 100644 --- a/jvm-runtime/ftl-runtime/common/runtime/src/main/java/xyz/block/ftl/runtime/VerbRegistry.java +++ b/jvm-runtime/ftl-runtime/common/runtime/src/main/java/xyz/block/ftl/runtime/VerbRegistry.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; @@ -16,6 +17,7 @@ import org.jboss.resteasy.reactive.server.core.parameters.ParameterExtractor; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; import com.google.protobuf.ByteString; import io.quarkus.arc.Arc; @@ -37,7 +39,7 @@ public VerbRegistry(ObjectMapper mapper) { } public void register(String module, String name, InstanceHandle verbHandlerClass, Method method, - List> paramMappers, boolean allowNullReturn) { + List paramMappers, boolean allowNullReturn) { verbs.put(new Key(module, name), new AnnotatedEndpointHandler(verbHandlerClass, method, paramMappers, allowNullReturn)); } @@ -61,15 +63,18 @@ private record Key(String module, String name) { private class AnnotatedEndpointHandler implements VerbInvoker { final InstanceHandle verbHandlerClass; final Method method; - final List> parameterSuppliers; + final List parameterSuppliers; final boolean allowNull; private AnnotatedEndpointHandler(InstanceHandle verbHandlerClass, Method method, - List> parameterSuppliers, boolean allowNull) { + List parameterSuppliers, boolean allowNull) { this.verbHandlerClass = verbHandlerClass; this.method = method; this.parameterSuppliers = parameterSuppliers; this.allowNull = allowNull; + for (ParameterSupplier parameterSupplier : parameterSuppliers) { + parameterSupplier.init(method); + } } public CallResponse handle(CallRequest in) { @@ -106,19 +111,36 @@ public CallResponse handle(CallRequest in) { } } - public record BodySupplier(Class inputClass) implements BiFunction { + public static class BodySupplier implements ParameterSupplier { + + final int parameterIndex; + volatile Type inputClass; + + public BodySupplier(int parameterIndex) { + this.parameterIndex = parameterIndex; + } + + public void init(Method method) { + inputClass = method.getGenericParameterTypes()[parameterIndex]; + } @Override public Object apply(ObjectMapper mapper, CallRequest in) { try { - return mapper.createParser(in.getBody().newInput()).readValueAs(inputClass); + ObjectReader reader = mapper.reader(); + return reader.forType(reader.getTypeFactory().constructType(inputClass)) + .readValue(in.getBody().newInput()); } catch (IOException e) { throw new RuntimeException(e); } } + + public int getParameterIndex() { + return parameterIndex; + } } - public static class SecretSupplier implements BiFunction, ParameterExtractor { + public static class SecretSupplier implements ParameterSupplier, ParameterExtractor { final String name; final Class inputClass; @@ -153,7 +175,7 @@ public Object extractParameter(ResteasyReactiveRequestContext context) { } } - public static class ConfigSupplier implements BiFunction, ParameterExtractor { + public static class ConfigSupplier implements ParameterSupplier, ParameterExtractor { final String name; final Class inputClass; @@ -187,4 +209,12 @@ public String getName() { } } + public interface ParameterSupplier extends BiFunction { + + // TODO: this is pretty yuck, but it lets us avoid a whole heap of nasty stuff to get the generic type + default void init(Method method) { + + } + + } }