CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-graalvm-sdk--graal-sdk

GraalVM Standard Development Kit providing APIs for polyglot language embedding, native AOT compilation, memory-efficient collections, low-level memory access, JNI utilities, and native bridge communication.

Pending
Overview
Eval results
Files

substitutions.mddocs/

Native Image Substitutions

Build-time class modification system for replacing methods, fields, and types during native image compilation. Note: This API is provided for compatibility only and is not part of the supported public API.

Capabilities

Class Targeting

Annotations for identifying which classes to modify during native image compilation.

/**
 * Identifies the target class for substitutions
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TargetClass {
    /** Target class to substitute */
    Class<?> value() default void.class;
    
    /** Target class name as string (for classes not on classpath) */
    String className() default "";
    
    /** Provider for computing target class name dynamically */
    Class<? extends Function<TargetClass, String>> classNameProvider() default NoClassNameProvider.class;
    
    /** Target class only on specific platforms */
    Class<? extends BooleanSupplier>[] onlyWith() default {};
    
    /** Exclude target class on specific platforms */
    Class<? extends BooleanSupplier>[] innerClass() default {};
}

/**
 * Fine-grained targeting of specific class elements
 */
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)  
public @interface TargetElement {
    /** Target element name */
    String name() default "";
    
    /** Target method parameter types */
    Class<?>[] parameters() default {};
    
    /** Target element only on specific platforms */
    Class<? extends BooleanSupplier>[] onlyWith() default {};
}

Usage Examples:

import com.oracle.svm.core.annotate.*;

// Substitute methods in java.lang.System
@TargetClass(System.class)
final class SystemSubstitutions {
    
    // Target specific method with parameters
    @TargetElement(name = "getProperty", parameters = {String.class})
    @Substitute
    public static String getProperty(String key) {
        // Custom implementation for native image
        return NativeImageProperties.getProperty(key);
    }
}

// Target class by name (when class not available at build time)
@TargetClass(className = "com.example.PlatformSpecific")
final class PlatformSpecificSubstitutions {
    
    @Substitute
    public static void platformMethod() {
        // Native image compatible implementation
        throw new UnsupportedOperationException("Not supported in native image");
    }
}

// Conditional targeting based on platform
@TargetClass(value = WindowsSpecificClass.class, 
             onlyWith = WindowsPlatform.class)
final class WindowsSubstitutions {
    
    @Substitute
    public static void windowsOnlyMethod() {
        // Windows-specific native implementation
    }
}

Method Substitution

Replace method implementations with native image compatible versions.

/**
 * Marks methods that replace original implementations
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Substitute {
    /** Handle methods with polymorphic signatures */
    boolean polymorphicSignature() default false;
    
    /** Override static modifier detection */
    boolean isStatic() default false;
}

/**
 * Keep original method alongside substitution
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface KeepOriginal {
}

/**
 * Add annotations to original method without changing implementation
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotateOriginal {
}

Usage Examples:

@TargetClass(java.util.concurrent.ThreadLocalRandom.class)
final class ThreadLocalRandomSubstitutions {
    
    // Replace problematic method with native image compatible version
    @Substitute
    public static ThreadLocalRandom current() {
        // Use global random instead of thread-local in native image
        return GlobalRandom.getInstance();
    }
    
    // Keep original for specific use cases
    @KeepOriginal
    @Substitute
    public int nextInt() {
        // This preserves original method as backup
        return original_nextInt();
    }
    
    // Add annotation without changing implementation
    @AnnotateOriginal
    @TruffleBoundary
    public native double nextGaussian();
}

// Handle polymorphic signatures (like MethodHandle.invoke)
@TargetClass(java.lang.invoke.MethodHandle.class)
final class MethodHandleSubstitutions {
    
    @Substitute
    @MethodHandle.PolymorphicSignature
    public native Object invoke(Object... args) throws Throwable;
    
    @Substitute
    @MethodHandle.PolymorphicSignature  
    public native Object invokeExact(Object... args) throws Throwable;
}

Field and Element Management

Control field behavior and manage class elements during compilation.

/**
 * Create alias to access original field or method
 */
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Alias {
    /** Accessor methods for private fields */
    boolean accessors() default false;
}

/**
 * Remove elements from target class
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface Delete {
    /** Override static modifier detection */
    boolean isStatic() default false;
}

/**
 * Inject new fields or methods into target class
 */
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
}

/**
 * Generate accessor methods for fields
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectAccessors {
    /** Accessor class to generate */
    Class<?> value();
}

Usage Examples:

@TargetClass(java.lang.Thread.class)
final class ThreadSubstitutions {
    
    // Create alias to access private field
    @Alias
    private String name;
    
    // Create accessor methods for private field
    @Alias
    @InjectAccessors(ThreadAccessors.class)
    private ThreadGroup group;
    
    // Inject new field into target class
    @Inject
    private static volatile int nativeThreadCounter = 0;
    
    // Remove problematic method
    @Delete
    public static native void dumpThreads(Thread[] threads);
    
    // Inject new utility method
    @Inject
    public static int getNativeThreadCount() {
        return nativeThreadCounter;
    }
    
    // Use alias in substitution
    @Substitute
    public String getName() {
        return name != null ? name : "native-thread-" + nativeThreadCounter++;
    }
}

// Accessor class for generated methods
final class ThreadAccessors {
    public static ThreadGroup getGroup(Thread thread) {
        // Generated by @InjectAccessors
        return null; // Implementation provided by annotation processor
    }
    
    public static void setGroup(Thread thread, ThreadGroup group) {
        // Generated by @InjectAccessors
    }
}

Field Value Recomputation

Transform static field values during image build for optimization and configuration.

/**
 * Recompute static field values at build time
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RecomputeFieldValue {
    /** Recomputation strategy */
    Kind kind();
    
    /** Declaring class for field reference */
    Class<?> declClass() default void.class;
    
    /** Field name for reference */
    String name() default "";
    
    /** Make field final after recomputation */
    boolean isFinal() default true;
    
    /** Transformation kinds */
    enum Kind {
        /** Reset to default value (0, null, false) */
        Reset,
        
        /** Copy value from another field */
        FromAlias,
        
        /** Compute value using custom transformer */
        Custom,
        
        /** Set to array length */
        ArrayLength,
        
        /** Set to current timestamp */
        AtBuildTime
    }
}

Usage Examples:

@TargetClass(java.lang.System.class)
final class SystemFieldSubstitutions {
    
    // Reset security manager to null in native image
    @Alias
    @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)
    private static SecurityManager security;
    
    // Copy build-time property value
    @Alias
    @RecomputeFieldValue(
        kind = RecomputeFieldValue.Kind.FromAlias,
        name = "buildTimeJavaVersion"
    )
    private static String javaVersion;
    
    @Inject
    private static final String buildTimeJavaVersion = System.getProperty("java.version");
    
    // Custom field transformation
    @Alias
    @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom,
                        declClass = BuildTimeComputer.class,
                        name = "computeMemorySize")
    private static long maxMemory;
    
    // Set to build timestamp
    @Inject
    @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.AtBuildTime)
    private static final long buildTimestamp = System.currentTimeMillis();
}

// Custom field value computer
final class BuildTimeComputer {
    public static long computeMemorySize() {
        // Compute appropriate memory size for native image
        return Runtime.getRuntime().maxMemory() / 2;
    }
}

Automatic Feature Registration

Automatically register feature classes for native image generation.

/**
 * Automatically register feature classes during image build
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutomaticFeature {
}

Usage Examples:

import org.graalvm.nativeimage.hosted.Feature;

// Automatically registered feature
@AutomaticFeature
public class DatabaseConnectionFeature implements Feature {
    
    @Override
    public void beforeAnalysis(BeforeAnalysisAccess access) {
        // Register database driver classes for reflection
        access.registerClassForReflection(
            com.mysql.cj.jdbc.Driver.class,
            org.postgresql.Driver.class
        );
    }
    
    @Override
    public void afterRegistration(AfterRegistrationAccess access) {
        // Initialize connection pool
        DatabaseConnectionPool pool = new DatabaseConnectionPool();
        ImageSingletons.add(DatabaseConnectionPool.class, pool);
    }
}

// Feature for JSON serialization support
@AutomaticFeature
public class JsonSerializationFeature implements Feature {
    
    @Override 
    public void beforeAnalysis(BeforeAnalysisAccess access) {
        // Find all classes with JSON annotations
        for (Class<?> clazz : findJsonAnnotatedClasses()) {
            access.registerClassForReflection(clazz);
            
            // Register all fields and methods for JSON processing
            for (Field field : clazz.getDeclaredFields()) {
                access.registerFieldForReflection(field);
            }
            
            for (Method method : clazz.getDeclaredMethods()) {
                if (isJsonMethod(method)) {
                    access.registerMethodForReflection(method);
                }
            }
        }
    }
    
    private List<Class<?>> findJsonAnnotatedClasses() {
        // Implementation to find JSON-annotated classes
        return Collections.emptyList();
    }
    
    private boolean isJsonMethod(Method method) {
        // Check if method is relevant for JSON processing
        return method.getName().startsWith("get") || 
               method.getName().startsWith("set") ||
               method.getName().startsWith("is");
    }
}

Platform Conditional Substitutions

Create platform-specific substitutions that only apply on certain operating systems or architectures.

// Platform detection interfaces
public interface Platform extends BooleanSupplier {
    interface HOSTED_ONLY extends Platform {}
    interface LINUX extends Platform {}
    interface DARWIN extends Platform {}  
    interface WINDOWS extends Platform {}
    interface AMD64 extends Platform {}
    interface AARCH64 extends Platform {}
}

Usage Examples:

// Windows-specific substitutions
@TargetClass(value = File.class, onlyWith = Platform.WINDOWS.class)
final class WindowsFileSubstitutions {
    
    @Substitute
    public boolean setExecutable(boolean executable) {
        // Windows-specific implementation
        return WindowsFileSystem.setExecutable(this, executable);
    }
}

// Linux-specific substitutions  
@TargetClass(value = UnixFileSystem.class, onlyWith = Platform.LINUX.class)
final class LinuxFileSystemSubstitutions {
    
    @Substitute
    public long getSpace(File f, int t) {
        // Linux-specific disk space implementation
        return LinuxNativeFS.getSpace(f.getPath(), t);
    }
}

// Architecture-specific optimizations
@TargetClass(value = CRC32.class, onlyWith = Platform.AMD64.class)
final class AMD64CRC32Substitutions {
    
    @Substitute
    public void update(byte[] b, int off, int len) {
        // AMD64-optimized CRC32 implementation
        updateAMD64(b, off, len);
    }
    
    private native void updateAMD64(byte[] b, int off, int len);
}

// Custom platform conditions
public final class CustomPlatform implements BooleanSupplier {
    @Override
    public boolean getAsBoolean() {
        return System.getProperty("custom.platform.enabled", "false").equals("true");
    }
}

@TargetClass(value = CustomClass.class, onlyWith = CustomPlatform.class)
final class ConditionalSubstitutions {
    
    @Substitute  
    public void customMethod() {
        // Only included when custom.platform.enabled=true
    }
}

Types

// Exception types
public class SubstitutionException extends RuntimeException {
    public SubstitutionException(String message);
    public SubstitutionException(String message, Throwable cause);
}

// Utility interfaces
public interface BooleanSupplier {
    boolean getAsBoolean();
}

public interface Function<T, R> {
    R apply(T t);
}

// Internal marker class
final class NoClassNameProvider implements Function<TargetClass, String> {
    @Override
    public String apply(TargetClass targetClass) {
        return "";
    }
}

// Build-time transformer interface
public interface FieldValueTransformer {
    Object transform(Object receiver, Object originalValue);
}

Install with Tessl CLI

npx tessl i tessl/maven-org-graalvm-sdk--graal-sdk

docs

c-interop.md

collections.md

config.md

index.md

jni-utils.md

native-bridge.md

native-image.md

polyglot.md

substitutions.md

word.md

tile.json