aclement / spring-boot-graal-processor

Annotation processor for creating reflection json files for graal

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

spring-boot-graal-processor

Annotation processor that produces a JSON file detailing types needing reflective access that can be passed to a graal native image build step.

Note: 29-Jul: The compilationhint branch actually is looking at what it would mean to process hint annotations on spring framework/boot and apps and produce the right data (as opposed to purely trying to work it out from class files). That represents the most up to date experiment...

Operation

The processor looks at the current app to discern new types that may need reflective access and merges that information with data from a reflect.defaults.json resource file that covers the common cases, producing a META-INF\reflects.json file in the project. It also uses a supplied project compilation classpath to add in any other types necessary based on classpath analysis (e.g. from META-INF\spring.factories files).

Maven snippet

The processor likes to know the project classpath. Until I learn how else to do it that is achieved by an extra bit of maven voodoo. Here is the snippet to include the processor:

<plugins>
	<plugin>
		<artifactId>maven-dependency-plugin</artifactId>
		<version>2.8</version>
		<executions>
			<execution>
				<phase>generate-sources</phase>
				<goals>
					<goal>build-classpath</goal>
				</goals>
				<configuration>
					<outputProperty>maven.compile.classpath</outputProperty>
					<pathSeparator>:</pathSeparator>
				</configuration>
			</execution>
		</executions>
	</plugin>
	<plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-compiler-plugin</artifactId>
		<configuration>
			<compilerArgs>
				<arg>-Aorg.springframework.boot.reflectionannotationprocessor.classpath=${maven.compile.classpath}</arg>
			</compilerArgs>
			<annotationProcessors>
				<annotationProcessor>
org.springframework.boot.reflectionprocessor.ReflectiveAccessAnnotationProcessor
				</annotationProcessor>
			</annotationProcessors>
			<debug>true</debug>
		</configuration>
	</plugin>
</plugins>

Output

The processor writes a META-INF/reflect.json file that has this kind of format:

[
  {
    "name" : "java.lang.Class",
    "allDeclaredConstructors" : true,
    "allPublicConstructors" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true,
    "allDeclaredClasses" : true,
    "allPublicClasses" : true
  },
  {
    "name" : "java.lang.String",
    "fields" : [
      { "name" : "value", "allowWrite" : true },
      { "name" : "hash" }
    ],
    "methods" : [
      { "name" : "<init>", "parameterTypes" : [] },
      { "name" : "<init>", "parameterTypes" : ["char[]"] },
      { "name" : "charAt" },
      { "name" : "format", "parameterTypes" : ["java.lang.String", "java.lang.Object[]"] }
    ]
  },
  {
    "name" : "java.lang.String$CaseInsensitiveComparator",
    "methods" : [
      { "name" : "compare" }
    ]
  }
]

as described in REFLECTION.md

Running Graal

The test-projects folder includes some examples. See the build.sh files in each, for example:

After running mvn clean package the build.sh file will:

unzip target/app-0.0.1-SNAPSHOT.jar -d target/app-0.0.1-SNAPSHOT

native-image
  -H:ReflectionConfigurationFiles=target/app-0.0.1-SNAPSHOT/META-INF/reflect.json 
  -Dio.netty.noUnsafe=true
  -H:+ReportExceptionStackTraces 
  --allow-incomplete-classpath
  -H:+ReportUnsupportedElementsAtRuntime
  -Dfile.encoding=UTF-8 
  -cp ".:$(echo target/app-0.0.1-SNAPSHOT/BOOT-INF/lib/*.jar | tr ' ' ':')":target/app-0.0.1-SNAPSHOT/BOOT-INF/classes
  com.example.demo1.Application

which will result in a executable form of the app in the current folder.

Agent usage

The spring-boot-graal-processor can also be run as an agent that will create a JSON file based on what it discovers as the process runs. For example:

java -Dspringbootgraal=file=myreflect.json -javaagent:spring-boot-graal-processor-0.0.1.BUILD-SNAPSHOT.jar -jar target/demo1-0.0.1-SNAPSHOT.jar

(If file is not specified in the system property, the default name is reflect.json in current folder)

Comparing reflect json files

The spring-boot-graal-processor is also a runnable jar. In this mode it should be passed two .json files and it will produce a simple diff:

java -jar spring-boot-graal-processor-XXX.jar r1.json r2.json

Resources

Graal REFLECTION.md

About

Annotation processor for creating reflection json files for graal


Languages

Language:Java 99.7%Language:Shell 0.3%