Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
50ff815
GraalVM support for
msailes Mar 30, 2021
ce27b2e
native-image support for the events lib
msailes Mar 31, 2021
9e11dab
reflect-config.json not needed for events lib.
msailes Apr 1, 2021
71279ee
added joda datetime
msailes Jun 4, 2021
567d59c
Adding GraalVM reflect-config.json and tests to catch any regressions.
msailes Jun 5, 2021
c85b0a3
trying out a single graalvm task
msailes Jul 8, 2021
693bbc8
trying out a single graalvm task
msailes Jul 8, 2021
ae2af66
add manually running jobs
msailes Jul 8, 2021
8a34d28
add manually running jobs
msailes Jul 8, 2021
602180e
add manually running jobs
msailes Jul 8, 2021
837b38f
quiet maven
msailes Jul 8, 2021
1e42782
graalvm
msailes Jul 8, 2021
80ea23c
might work
msailes Jul 8, 2021
a67cabf
app config
msailes Jul 8, 2021
187cebf
clean up
msailes Jul 12, 2021
c4c8661
typo
msailes Jul 12, 2021
a81c1fc
removed reference to my dockerfile
msailes Jul 12, 2021
33060df
merged Richard's LambdaEventsGraalVMFeature and removed the GraalVMCo…
msailes Jul 13, 2021
9430ae3
removing graalvm from the pr make
msailes Jul 13, 2021
6c7ce8d
Adding updated README.md from fafriat
msailes Jul 13, 2021
c5b928f
improving the java docs
msailes Jul 13, 2021
c9479ad
adding the Feature for Core
msailes Jul 14, 2021
e68cbb1
Add GraalVM test for StreamHandler
richarddavison Jul 14, 2021
a266a67
ignore .DS_Store
richarddavison Jul 14, 2021
2df8a6e
Merge branch 'graalvm-support' of https://github.com/msailes/aws-lamb…
richarddavison Jul 14, 2021
47bbe1e
Move GraalVM reflect-config.json to GraalVM features
richarddavison Jul 14, 2021
612c5a9
adding Javadocs to explain the Feature classes.
msailes Jul 15, 2021
ff795e6
adding the compile time graalvm dependency.
msailes Jul 15, 2021
c27cb9a
moving the graalvm sdk to provided.
msailes Jul 15, 2021
200d5b8
Merge branch 'master' into graalvm-support
carlzogh Sep 9, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ jobs:
- name: Run 'pr' target
working-directory: ./aws-lambda-java-runtime-interface-client
run: make pr

5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ dependency-reduced-pom.xml
.gradle
.settings
.classpath
.project
.project

#MacOS
.DS_Store
9 changes: 9 additions & 0 deletions aws-lambda-java-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@
</repository>
</distributionManagement>

<dependencies>
<dependency>
<groupId>org.graalvm.sdk</groupId>
<artifactId>graal-sdk</artifactId>
<version>21.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

<profiles>
<profile>
<id>dev</id>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.amazonaws.services.lambda.runtime.graalvm;

import com.amazonaws.services.lambda.runtime.LambdaRuntime;
import com.amazonaws.services.lambda.runtime.LambdaRuntimeInternal;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeReflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
* This class programmatically registers classes, methods and fields
* to be added to an application when used with GraalVM native-image.
*
* These specific classes are registered because GraalVM can't detect
* them during static analysis.
*
* @see <a href="https://www.graalvm.org/reference-manual/native-image/">GraalVM native-image</a>
*/
public class LambdaCoreGraalVMFeature implements Feature {

private static final Set<Class> classesForReflectConfig = new HashSet<>();

static {
classesForReflectConfig.add(LambdaRuntime.class);
classesForReflectConfig.add(LambdaRuntimeInternal.class);
}

@Override
public void beforeAnalysis(BeforeAnalysisAccess access) {
for (Class aClass : classesForReflectConfig) {
registerClass(aClass);
registerMethods(aClass);
registerFields(aClass);
}
}

private void registerMethods(Class<?> cl) {
for (Method method : cl.getDeclaredMethods()) {
RuntimeReflection.register(method);
}
}

private void registerFields(Class<?> cl) {
for (Field field : cl.getDeclaredFields()) {
RuntimeReflection.register(field);
}
}

private void registerClass(Class<?> cl) {
RuntimeReflection.register(cl);
for (Constructor<?> constructor : cl.getDeclaredConstructors()) {
RuntimeReflection.register(constructor);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Args = --features=com.amazonaws.services.lambda.runtime.graalvm.LambdaCoreGraalVMFeature
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"name":"com.amazonaws.services.lambda.runtime.LambdaRuntime",
"methods":[{"name":"<init>","parameterTypes":[] }],
"fields":[{"name":"logger"}],
"allPublicMethods":true
},
{
"name":"com.amazonaws.services.lambda.runtime.LambdaRuntimeInternal",
"methods":[{"name":"<init>","parameterTypes":[] }],
"allPublicMethods":true
}
]
Comment on lines +1 to +13
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file needed if we have the dynamic Feature?

13 changes: 13 additions & 0 deletions aws-lambda-java-events/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@
<version>2.6</version>
</dependency>

<dependency>
<groupId>org.graalvm.sdk</groupId>
<artifactId>graal-sdk</artifactId>
<version>21.1.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
Expand All @@ -68,6 +75,12 @@
<version>2.22.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId>
<version>4.8.110</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.amazonaws.services.lambda.runtime.graalvm;

import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeReflection;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
* The aws-lambda-java-events library supports GraalVM by containing a reflect-config.json file. This is located
* src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-events/reflect-config.json
*
* This config is used by the GraalVM native-image tool in order to load the required classes and methods into the
* native binary it creates.
*
* Any event or response class added to this library needs to be added to this config file.
*
* This implementation of Feature does that by iterating through the events package and registering
* them for runtime reflection.
*/
public class LambdaEventsGraalVMFeature implements Feature {

public static final String EVENTS_PACKAGE_NAME = "com.amazonaws.services.lambda.runtime.events";
Comment on lines +28 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should make this generic enough for it to be reused across all our libraries in this project, and move it out of the runtime addressable scope. It should be a build-only class that is not exposed in the library.

This is essentially boilerplate code that will traverse our libraries and determine what the appropriate native-image config is, so we don't really need a copy of it per project.


public static List<Class<?>> getClasses(String packageName)
throws ClassNotFoundException, IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
List<File> dirs = new ArrayList<>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
ArrayList<Class<?>> classes = new ArrayList<>();
for (File directory : dirs) {
classes.addAll(findClasses(directory, packageName));
}
return classes;
}

private static List<Class<?>> findClasses(File directory, String packageName) throws ClassNotFoundException {
List<Class<?>> classes = new ArrayList<>();
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
if(files == null){
return classes;
}
for (File file : files) {
String fileName = file.getName();
if (file.isDirectory()) {
assert !fileName.contains(".");
classes.addAll(findClasses(file, packageName + "." + fileName));
} else if (fileName.endsWith(".class")) {
classes.add(Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - ".class".length())));
}
}
return classes;
}

@Override
public void beforeAnalysis(BeforeAnalysisAccess access) {
try {
List<Class<?>> classes = getClasses(EVENTS_PACKAGE_NAME);
for (Class<?> cl : classes) {
System.out.println("Registering class:"+cl.getName());
registerClass(cl);
registerMethods(cl);
registerFields(cl);
}
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
System.err.println("Failed to automatically load classes from "+ LambdaEventsGraalVMFeature.class.getName());
System.exit(1);
}
}

private void registerMethods(Class<?> cl) {
for (Method method : cl.getDeclaredMethods()) {
RuntimeReflection.register(method);
}
}

private void registerFields(Class<?> cl) {
for (Field field : cl.getDeclaredFields()) {
RuntimeReflection.register(field);
}
}

private void registerClass(Class<?> cl) {
RuntimeReflection.register(cl);
for (Constructor<?> constructor : cl.getDeclaredConstructors()) {
RuntimeReflection.register(constructor);
}
System.out.printf("\tAdding constructors for %s%n", cl.getName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Args = --enable-all-security-services \
--enable-url-protocols=http,https \
--features=com.amazonaws.services.lambda.runtime.graalvm.LambdaEventsGraalVMFeature
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.amazonaws.services.lambda.runtime.events.graalvm;

import com.amazonaws.services.lambda.runtime.graalvm.LambdaEventsGraalVMFeature;
import io.github.classgraph.ClassGraph;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

import static com.amazonaws.services.lambda.runtime.graalvm.LambdaEventsGraalVMFeature.EVENTS_PACKAGE_NAME;

/**
* The aws-lambda-java-events library supports GraalVM by containing a reflect-config.json file. This is located
* src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-events/reflect-config.json
*
* This config is used by the GraalVM native-image tool in order to load the required classes and methods into the
* native binary it creates.
*
* Any event or response class added to this library needs to be added to this config file.
*
* This test asserts that all the classes are included.
*/
public class LambdaEventsGraalVMFeatureTest {

@TestFactory
public Stream<DynamicTest> testEventClassesAreFound() throws IOException, ClassNotFoundException {

Set<Class<?>> eventClassNames = new HashSet<>(LambdaEventsGraalVMFeature.getClasses(EVENTS_PACKAGE_NAME));

return new ClassGraph()
.enableClassInfo()
.acceptPackages(EVENTS_PACKAGE_NAME)
.scan().getAllClasses().stream()
.map(classInfo -> DynamicTest.dynamicTest("Test " + classInfo.getSimpleName(), () -> {
Class<?> eventClass = classInfo.loadClass();
Assertions.assertTrue(eventClassNames.contains(eventClass));
}));
}
}
1 change: 1 addition & 0 deletions aws-lambda-java-runtime-interface-client/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
compile-flags.txt
codebuild.*
9 changes: 7 additions & 2 deletions aws-lambda-java-runtime-interface-client/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ target:

.PHONY: test
test:
mvn test
mvn test -q

.PHONY: setup-codebuild-agent
setup-codebuild-agent:
Expand All @@ -16,6 +16,11 @@ test-smoke: setup-codebuild-agent
CODEBUILD_IMAGE_TAG=codebuild-agent test/integration/codebuild-local/test_one.sh test/integration/codebuild/buildspec.os.alpine.yml alpine 3.12 corretto11
CODEBUILD_IMAGE_TAG=codebuild-agent test/integration/codebuild-local/test_one.sh test/integration/codebuild/buildspec.os.amazoncorretto.yml amazoncorretto amazoncorretto 11

.PHONY: test-graalvm
test-graalvm:
docker build --progress=plain -t codebuild-agent - < test/integration/codebuild-local/Dockerfile.graalvm-agent
CODEBUILD_IMAGE_TAG=codebuild-agent test/integration/codebuild-local/test_one.sh test/integration/codebuild-graalvm/buildspec.os.amazoncorretto.yml amazoncorretto amazoncorretto 11

.PHONY: test-integ
test-integ: setup-codebuild-agent
CODEBUILD_IMAGE_TAG=codebuild-agent test/integration/codebuild-local/test_all.sh test/integration/codebuild
Expand All @@ -30,7 +35,7 @@ pr: test test-smoke

.PHONY: build
build:
mvn clean install
mvn clean install -q

define HELP_MESSAGE

Expand Down
Loading