Class ByteBuddyStageClassCreator

java.lang.Object
com.tngtech.jgiven.impl.ByteBuddyStageClassCreator
All Implemented Interfaces:
StageClassCreator

public class ByteBuddyStageClassCreator extends Object implements StageClassCreator
Creates JGiven stage subclasses at runtime using ByteBuddy.

The class loading strategy is chosen in three tiers, in order of preference:

  1. Reflection-based injection (ClassLoadingStrategy.Default.INJECTION) — used when ClassInjector.UsingReflection.isAvailable() returns true. This is the case when the class to be instrumented is not barred from injection via the Jave module system. (Mostly the case up to Java 21) The generated subclass is injected into the same classloader as the stage class via sun.misc.Unsafe/defineClass reflection, which preserves package membership.
  2. Lookup-based injection (ClassLoadingStrategy.UsingLookup) — used when reflective injection is unavailable but ClassInjector.UsingLookup.isAvailable() returns true and a MethodHandles.Lookup with PACKAGE/MODULE privileges over the stage class's package can be obtained via MethodHandles.privateLookupIn(java.lang.Class<?>, java.lang.invoke.MethodHandles.Lookup). The generated subclass is again injected into the stage class's classloader, preserving package membership. This tier is reached on Java 9+ runtimes that have not opened java.base/java.lang to reflection. If privateLookupIn fails (typically because the user's JPMS module does not --add-opens its package to JGiven), a single WARN-level log message is emitted and the strategy falls through to WRAPPER.
  3. Wrapping (ClassLoadingStrategy.Default.WRAPPER) — fallback when neither injector is available, or when the lookup tier cannot acquire a usable Lookup. The generated subclass is placed in a separate child classloader. Package-private stages cannot be instrumented under WRAPPER; the user must either --add-opens their stage class's package or move the stage class to the unnamed module / classpath.

Subclasses may override getClassLoadingStrategy(Class) to take a different decision.

  • Field Details

  • Constructor Details

    • ByteBuddyStageClassCreator

      public ByteBuddyStageClassCreator()
  • Method Details

    • createStageClass

      public <T> Class<? extends T> createStageClass(Class<T> stageClass)
      Specified by:
      createStageClass in interface StageClassCreator
    • getClassLoadingStrategy

      protected net.bytebuddy.dynamic.loading.ClassLoadingStrategy<ClassLoader> getClassLoadingStrategy(Class<?> stageClass)
    • getClassLoader

      protected ClassLoader getClassLoader(Class<?> stageClass)