You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2018/10/28 15:44:05 UTC
[isis] branch v2 updated: ISIS-2026: Implementing a byte-buddy
class-loading-strategy that
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch v2
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/v2 by this push:
new ac7da8e ISIS-2026: Implementing a byte-buddy class-loading-strategy that
ac7da8e is described below
commit ac7da8e0e1d356c2772854efe0186d50ba27b31b
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sun Oct 28 16:43:58 2018 +0100
ISIS-2026: Implementing a byte-buddy class-loading-strategy that
allows to run byte-buddy 1.9.2 on both JDK 8 and JDK 9+ runtimes
Task-Url: https://issues.apache.org/jira/browse/ISIS-2026
---
.../ImposteriserTestUsingCodegenPlugin.java | 24 +++---
.../codegen/ClassLoadingStrategyAdvisor.java | 90 ++++++++++++++++++++++
.../codegen/ProxyFactoryPluginUsingByteBuddy.java | 26 ++++---
.../services/i18n/po/TranslationServicePo.java | 4 +-
.../runtime/services/i18n/po/PoReaderTest.java | 5 +-
5 files changed, 122 insertions(+), 27 deletions(-)
diff --git a/core/detached-tests/src/test/java/org/apache/isis/core/unittestsupport/jmocking/ImposteriserTestUsingCodegenPlugin.java b/core/detached-tests/src/test/java/org/apache/isis/core/unittestsupport/jmocking/ImposteriserTestUsingCodegenPlugin.java
index 7c99042..2e5dadd 100644
--- a/core/detached-tests/src/test/java/org/apache/isis/core/unittestsupport/jmocking/ImposteriserTestUsingCodegenPlugin.java
+++ b/core/detached-tests/src/test/java/org/apache/isis/core/unittestsupport/jmocking/ImposteriserTestUsingCodegenPlugin.java
@@ -37,10 +37,8 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.apache.isis.applib.services.i18n.TranslationsResolver;
import org.apache.isis.commons.internal.context._Context;
import org.apache.isis.core.plugins.codegen.ProxyFactoryPlugin;
-import org.apache.isis.core.runtime.services.i18n.po.TranslationServicePo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -99,6 +97,13 @@ public class ImposteriserTestUsingCodegenPlugin {
imposter.toString();
}
+ // class we want to mock, while making sure, that we have access to non public fields
+ static class NonPublicMethodStub {
+ Integer getInteger() {
+ return 1;
+ }
+ }
+
@Test
public void imposteriserShouldBeUsableForMockery() {
@@ -108,17 +113,16 @@ public class ImposteriserTestUsingCodegenPlugin {
}
};
- // using TranslationService here is just arbitrary, can be replaced any time ...
- final TranslationServicePo mockTranslationServicePo = context.mock(TranslationServicePo.class);
- final TranslationsResolver mockTranslationsResolver = context.mock(TranslationsResolver.class);
-
+ final NonPublicMethodStub mocked = context.mock(NonPublicMethodStub.class);
+
context.checking(new Expectations() {{
- allowing(mockTranslationServicePo).getTranslationsResolver();
- will(returnValue(mockTranslationsResolver));
+ allowing(mocked).getInteger();
+ will(returnValue(Integer.valueOf(2)));
}});
- Assert.assertNotNull(mockTranslationServicePo);
- Assert.assertNotNull(mockTranslationServicePo.getTranslationsResolver());
+ Assert.assertNotNull(mocked);
+ Assert.assertNotNull(mocked.getInteger());
+ Assert.assertEquals(2, mocked.getInteger().intValue());
}
// //////////////////////////////////////
diff --git a/core/plugins/codegen-bytebuddy/src/main/java/org/apache/isis/core/plugins/codegen/ClassLoadingStrategyAdvisor.java b/core/plugins/codegen-bytebuddy/src/main/java/org/apache/isis/core/plugins/codegen/ClassLoadingStrategyAdvisor.java
new file mode 100644
index 0000000..f9e2e61
--- /dev/null
+++ b/core/plugins/codegen-bytebuddy/src/main/java/org/apache/isis/core/plugins/codegen/ClassLoadingStrategyAdvisor.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.isis.core.plugins.codegen;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+
+import net.bytebuddy.dynamic.loading.ClassInjector;
+import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
+
+/**
+ * package private utility to advise on the ClassLoadingStrategy, dependent on the JVM version we are running on
+ *
+ * see <a href="https://mydailyjava.blogspot.com/2018/04/jdk-11-and-proxies-in-world-past.html">byte-buddy blog</a>
+ */
+class ClassLoadingStrategyAdvisor {
+
+ private final MethodHandle privateLookupMethodHandle;
+
+ ClassLoadingStrategyAdvisor() {
+ this.privateLookupMethodHandle = createPrivateLookupMethodHandle();
+ }
+
+ public ClassLoadingStrategy<ClassLoader> getSuitableStrategy(final Class<?> targetClass) {
+
+ // JDK 9+
+ if (privateLookupMethodHandle!=null) {
+
+ try {
+ Object privateLookup = privateLookupMethodHandle.invoke(targetClass, MethodHandles.lookup());
+ return ClassLoadingStrategy.UsingLookup.of(privateLookup);
+ } catch (Throwable e) {
+ throw new IllegalStateException(
+ String.format("Failed to utilize code generation strategy on class '%s'",
+ targetClass.getName())
+ , e);
+ }
+ }
+
+ // JDK 8
+ return ClassLoadingStrategy.Default.INJECTION;
+
+ }
+
+ // -- HELPER
+
+ private MethodHandle createPrivateLookupMethodHandle() {
+
+ // JDK 9+
+ if (ClassInjector.UsingLookup.isAvailable()) {
+
+ try {
+ Class<?> methodHandles = java.lang.invoke.MethodHandles.class;
+ Method privateLookupIn = methodHandles.getMethod("privateLookupIn",
+ Class.class,
+ java.lang.invoke.MethodHandles.Lookup.class);
+
+ MethodHandle mh = MethodHandles.publicLookup().unreflect(privateLookupIn);
+ return mh;
+ } catch (Exception e) {
+ throw new IllegalStateException("No code generation strategy available", e);
+ }
+ }
+
+ // JDK 8
+ if (ClassInjector.UsingReflection.isAvailable()) {
+ return null;
+ }
+
+ throw new IllegalStateException("No code generation strategy available");
+ }
+
+
+
+}
diff --git a/core/plugins/codegen-bytebuddy/src/main/java/org/apache/isis/core/plugins/codegen/ProxyFactoryPluginUsingByteBuddy.java b/core/plugins/codegen-bytebuddy/src/main/java/org/apache/isis/core/plugins/codegen/ProxyFactoryPluginUsingByteBuddy.java
index a0b088c..21db918 100644
--- a/core/plugins/codegen-bytebuddy/src/main/java/org/apache/isis/core/plugins/codegen/ProxyFactoryPluginUsingByteBuddy.java
+++ b/core/plugins/codegen-bytebuddy/src/main/java/org/apache/isis/core/plugins/codegen/ProxyFactoryPluginUsingByteBuddy.java
@@ -37,17 +37,9 @@ import net.bytebuddy.implementation.InvocationHandlerAdapter;
import net.bytebuddy.matcher.ElementMatchers;
public class ProxyFactoryPluginUsingByteBuddy implements ProxyFactoryPlugin {
-
- private static <T> ImplementationDefinition<T> nextProxyDef(
- Class<T> base,
- Class<?>[] interfaces) {
- return new ByteBuddy()
- .with(new NamingStrategy.SuffixingRandom("bb"))
- .subclass(base)
- .implement(interfaces)
- .method(ElementMatchers.any());
- }
-
+
+ private final ClassLoadingStrategyAdvisor strategyAdvisor = new ClassLoadingStrategyAdvisor();
+
@Override
public <T> ProxyFactory<T> factory(
Class<T> base,
@@ -60,7 +52,7 @@ public class ProxyFactoryPluginUsingByteBuddy implements ProxyFactoryPlugin {
nextProxyDef(base, interfaces)
.intercept(InvocationHandlerAdapter.of(handler))
.make()
- .load(_Context.getDefaultClassLoader())
+ .load(_Context.getDefaultClassLoader(), strategyAdvisor.getSuitableStrategy(base))
.getLoaded();
return new ProxyFactory<T>() {
@@ -121,6 +113,16 @@ public class ProxyFactoryPluginUsingByteBuddy implements ProxyFactoryPlugin {
}
// -- HELPER
+
+ private static <T> ImplementationDefinition<T> nextProxyDef(
+ Class<T> base,
+ Class<?>[] interfaces) {
+ return new ByteBuddy()
+ .with(new NamingStrategy.SuffixingRandom("bb"))
+ .subclass(base)
+ .implement(interfaces)
+ .method(ElementMatchers.any());
+ }
private static void ensureSameSize(Class<?>[] a, Object[] b) {
if(_NullSafe.size(a) != _NullSafe.size(b)) {
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/i18n/po/TranslationServicePo.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/i18n/po/TranslationServicePo.java
index 48b8db0..e4480f9 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/i18n/po/TranslationServicePo.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/i18n/po/TranslationServicePo.java
@@ -184,7 +184,7 @@ public class TranslationServicePo implements TranslationService {
private TranslationsResolver translationsResolver;
@Programmatic
- public TranslationsResolver getTranslationsResolver() {
+ TranslationsResolver getTranslationsResolver() {
return translationsResolver;
}
@@ -192,7 +192,7 @@ public class TranslationServicePo implements TranslationService {
private LocaleProvider localeProvider;
@Programmatic
- public LocaleProvider getLocaleProvider() {
+ LocaleProvider getLocaleProvider() {
return localeProvider;
}
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/services/i18n/po/PoReaderTest.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/services/i18n/po/PoReaderTest.java
index 093bde5..b696742 100644
--- a/core/runtime/src/test/java/org/apache/isis/core/runtime/services/i18n/po/PoReaderTest.java
+++ b/core/runtime/src/test/java/org/apache/isis/core/runtime/services/i18n/po/PoReaderTest.java
@@ -62,9 +62,8 @@ public class PoReaderTest {
will(returnValue(Locale.UK));
}});
- //[ahuber] with update of byte-buddy 1.8.0 -> 1.9.2, Apache Isis runs on JDK 11+, but
- // it seems to no longer support mockery of non public methods, so we
- // explicitly test proper mockery here ...
+ //[ahuber] with update of byte-buddy 1.8.0 -> 1.9.2, Apache Isis runs on JDK 11+,
+ // we explicitly test proper mockery of non-public methods here ...
Assert.assertNotNull(mockTranslationServicePo.getLocaleProvider());
Assert.assertNotNull(mockTranslationServicePo.getTranslationsResolver());
Assert.assertNotNull(mockLocaleProvider.getLocale());