Die GraalVM: Javas Sprung in die Gegenwart?

Das Erstellen des Binarys beeinflussen

Um die meisten der Einschränkungen umgehen zu können, bietet die SubstrateVM Entwicklern die Möglichkeit, das Erstellen des Binary zu beeinflussen: entweder durch das Bereitstellen von Konfigurationsdateien oder durch die SubstrateVM Java API. Sie ermöglicht es, Meta-Informationen für das Erstellen verfügbar zu machen

Um dem native-image-Befehl beispielsweise mitzuteilen, welche Klassen per Reflection geladen werden und damit im Binary mit aufgenommen werden sollen, kann man eine in JSON definierte Konfigurationsdatei zur Verfügung stellen. Folgendes Beispiel ist ein Auszug aus einer möglichen Konfiguration:

[ {
"name" : "com.fasterxml.jackson.datatype.jdk8.Jdk8Module",
"allDeclaredConstructors" : true
}, {

}]

Das Listing beschreibt, dass die Klasse Jdk8Module aus den Jackson-Projekten zusammen mit allen definierten Konstruktoren mit in das Binary kompiliert werden soll. Nur so ist es möglich, die Klasse später per Reflection zu nutzen. Mit der Konfigurationsdatei haben Entwickler eine feingranulare Kontrolle darüber, welche Teile einer Klasse sie mitkompilieren wollen. Eine weitere Konfigurationsdatei kann dazu dienen, alle Interfaces zu definieren, für die man später mögliche Proxys erstellen möchte. Durch die fehlende Möglichkeit, zur Laufzeit Bytecode zu erzeugen, müssen die Informationen bereits zur Kompilierzeit bekannt sein. Eine Datei, die Interfaces definiert, sieht zum Beispiel so aus:

[
["java.sql.PreparedStatement"]
]

Um komplizierte Konfigurationen vorzunehmen, bietet die SubstrateVM auch eine eigene Java-API an. Zum Beispiel bietet sie die Möglichkeit, Methodenimplementierungen durch eine alternative Implementierung zu ersetzen. Ein Beispiel dafür wäre folgendes:

@TargetClass(io.netty.util.internal.logging.InternalLoggerFactory.class)
final class Target_io_netty_util_internal_logging_InternalLoggerFactory {
@Substitute
private static InternalLoggerFactory newDefaultFactory(String name) {
return JdkLoggerFactory.INSTANCE;
}
}

@TargetClass und @Substitute sind Annotationen, die zur SubstrateVM-API gehören. Das sind Metainformationen, die die SubstrateVM beim Bauen des Binary auswerten kann. Im konkreten Beispiel ersetzt die definierte Methode, die mit @Substitute markiert ist, die Methode in der TargetClass, die eine identische Signatur und Namen besitzt. Die Methode newDefaultFactory(String name) in der Klasse InternalLoggerFactory wird durch die definierte Methode ersetzt. Dadurch hat man die Möglichkeit den Code, der beim Kompilieren zu Problemen führen kann, durch einen alternativen Code zu ersetzen. Das funktioniert ebenfalls wie hier beschrieben mit Drittanbieterbibliotheken wie Netty.

Neben dem Beispiel bietet die API noch weitere Möglichkeiten. Man kann ebenso Offsets für den Zugriff auf nativen Speicher über die Unsafe-API neu berechnen lassen, da sich der Adressraum zwischen der SubstrateVM und einer normalen JVM unterscheidet.