diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/ClassLoadingStrategy.java b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/ClassLoadingStrategy.java index 41928294d1..7de3a7fe4a 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/ClassLoadingStrategy.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/ClassLoadingStrategy.java @@ -22,6 +22,7 @@ import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; import java.util.Map; +import java.util.concurrent.Callable; /** * A strategy for loading a collection of types. @@ -459,6 +460,28 @@ public static ClassLoadingStrategy of(Object lookup) { return new UsingLookup(ClassInjector.UsingLookup.of(lookup)); } + /** + * Resolves a class loading strategy using a lookup if available on the current JVM. If the current JVM supports method handles + * lookups, a lookup instance will be used. Alternatively, unsafe class definition is used, if supported. If neither strategy is + * supported, an exception is thrown. + * + * @param lookup A resolver for a lookup instance if the current JVM allows for lookup-based class injection. + * @return An appropriate class loading strategy for the current JVM that uses a method handles lookup if available. + */ + public static ClassLoadingStrategy withFallback(Callable lookup) { + if (ClassInjector.UsingLookup.isAvailable()) { + try { + return of(lookup.call()); + } catch (Exception exception) { + throw new IllegalStateException(exception); + } + } else if (ClassInjector.UsingUnsafe.isAvailable()) { + return new ClassLoadingStrategy.ForUnsafeInjection(); + } else { + throw new IllegalStateException("Neither lookup or unsafe class injection is available"); + } + } + /** * {@inheritDoc} */ diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/dynamic/loading/ClassLoadingStrategyUsingLookupTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/dynamic/loading/ClassLoadingStrategyUsingLookupTest.java index cac0aa2566..508e3ecf1e 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/dynamic/loading/ClassLoadingStrategyUsingLookupTest.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/dynamic/loading/ClassLoadingStrategyUsingLookupTest.java @@ -2,6 +2,8 @@ import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.test.utility.MockitoRule; +import net.bytebuddy.utility.JavaConstant; +import net.bytebuddy.utility.JavaType; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -10,8 +12,10 @@ import java.util.Collections; import java.util.Map; +import java.util.concurrent.Callable; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.when; @@ -45,6 +49,16 @@ public void testInjection() throws Exception { assertThat(type.getName(), is(Foo.class.getName())); } + @Test + public void testFallback() { + assertThat(ClassLoadingStrategy.UsingLookup.withFallback(new Callable() { + @Override + public Object call() throws Exception { + return JavaType.METHOD_HANDLES.load().getMethod("lookup").invoke(null); + } + }), notNullValue(ClassLoadingStrategy.class)); + } + private static class Foo { /* empty */ }