Custom Runtime wrapper for Java written in Kotlin
-
Add Jitpack to repos in gradle.build.kts
repositories { maven { url = uri("https://jitpack.io") } }
-
Add dependency
dependencies { compile("com.github.richarddd:aws-lambda-java-custom-runtime:-SNAPSHOT") }
-
Set main class of your code to use
se.davison.aws.lambda.customruntime.MainKt
i.e:tasks.withType<Jar> { manifest { attributes( mapOf( "Main-Class" to "se.davison.aws.lambda.customruntime.MainKt" ) ) } }
-
Build jar
-
Create an empty file named
bootstrap
and make it executable:sudo echo "" > boostrap && chmod 755 boostrap
-
Copy built jar to root directory and name it lambda.jar (You can name it whatever you wan't just make sure to change the script below to match the new name)
-
Add this to
bootstrap
#!/bin/sh set -euo pipefail java -jar lambda.jar
-
Install docker
-
Setup GraalVM reflection (https://github.com/oracle/graal/blob/master/substratevm/REFLECTION.md)
-
This could be done in many ways. One option is to specify a reflection json and pass to native compilation (
-H:ReflectionConfigurationFiles=reflect.json
). However that's extremely verbose.A better option is to use another library by me which solves these problems automatically using compile time providers, annotations and class scanning.
-
Add this depedency
compile("com.github.richarddd:graal-auto-reflection:master-SNAPSHOT")
-
Create this provider class and modify according to your project. NOTE: It's important that you stay away from Kotlin methods in here and use Stream API as this class runs during GraalVM build time. It is of course possible to use Kotlin here as well, but those classes needs to be initialized at build-time using Native-Image configuration.
class AwsReflectionProvider : ReflectionProvider { override fun packages(classGraph: ClassGraph) = ArrayList<String>() override fun classes(classGraph: ClassGraph): List<Class<*>> { return classGraph.enableClassInfo().scan().let { Stream.concat( it.getClassesImplementing(RequestStreamHandler::class.java.name).stream().map { it.loadClass() }, it.getClassesImplementing(RequestHandler::class.java.name).stream().flatMap { Stream.concat( Stream.of(it.loadClass()), it.typeSignature.superinterfaceSignatures[0].typeArguments.stream().map { (it.typeSignature as ClassRefTypeSignature).loadClass() }) } ) .distinct().toList() } } } @Suppress("ReplaceJavaStaticMethodWithKotlinAnalog") class ReflectionData : ReflectionProvider { override fun packages(classGraph: ClassGraph) = ArrayList<String>() override fun classes(classGraph: ClassGraph) = Arrays.asList(APIGatewayProxyResponseEvent::class.java) }
-
Annotate all your response (stuff that you return from your handlers) classes with
@Reflect
-
-
Compile native image.
Copy this install script to your project directory.
sudo mkdir -p ./scripts && \ wget -O ./scripts/build.sh "https://github.com/richarddd/aws-lambda-java-custom-runtime/raw/master/build.sh" && \ chmod 755 ./scripts/build.sh
-
Use script to build native binary.
./scripts/build.sh
(To build and run on your machine use:
./scripts/build.sh local
) -
Add this to
bootstrap
#!/bin/sh ./runtime
You could use --args
to pass extra arguments to your GraalVM native-image build script, i.e: ./scripts/build.sh --args -H:+ReportExceptionStackTraces