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 2022/09/14 06:27:59 UTC

[isis] branch master updated: ISIS-3209: introduces isis-core-privileged

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 530f8b699e ISIS-3209: introduces isis-core-privileged
530f8b699e is described below

commit 530f8b699e2273f2934601a3a9ffa3dbd427ff65
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Sep 14 08:27:51 2022 +0200

    ISIS-3209: introduces isis-core-privileged
    
    - a helper module with unrestricted access to the class-path (not
    module-path)
    
    - brings in codgen-bytebuddy as a named module
---
 commons/pom.xml                                    |  5 ++
 .../isis/commons/internal/reflection/_Reflect.java | 14 ----
 .../src/main/java/module-info.java}                | 21 +++--
 .../services/ClassLoadingStrategyAdvisor.java      | 36 ++------
 core/metamodel/src/main/java/module-info.java      |  1 +
 .../isis/core/metamodel/_testing/_TestDummies.java | 21 +++++
 .../ViewModelFacetForViewModelInterface.java       |  5 +-
 core/pom.xml                                       |  9 ++
 core/privileged/pom.xml                            | 49 +++++++++++
 .../apache/isis/core/privileged/_Privileged.java   | 98 ++++++++++++++++++++++
 viewers/wicket/ui/src/main/java/module-info.java   |  1 +
 .../choices/ChoiceProviderForReferencesTest.java   | 45 ++--------
 12 files changed, 212 insertions(+), 93 deletions(-)

diff --git a/commons/pom.xml b/commons/pom.xml
index b626d4a159..414ba19cd2 100644
--- a/commons/pom.xml
+++ b/commons/pom.xml
@@ -62,6 +62,11 @@
 			<artifactId>isis-jdk-supplemental</artifactId>
 			<type>pom</type>
 		</dependency>
+		
+		<dependency>
+			<groupId>org.apache.isis.core</groupId>
+			<artifactId>isis-core-privileged</artifactId>
+		</dependency>
 
 		<dependency>
 			<groupId>com.fasterxml.jackson.core</groupId>
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java b/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java
index bf7bd0bf01..c275d6d737 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java
@@ -23,8 +23,6 @@ import java.beans.IntrospectionException;
 import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
 import java.lang.annotation.Annotation;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Executable;
@@ -437,18 +435,6 @@ public final class _Reflect {
         return false;
     }
 
-    // -- METHOD/FIELD HANDLES
-
-    @Deprecated // does not work well with JPMS; inline at call-site instead
-    public static MethodHandle handleOf(final Method method) throws IllegalAccessException {
-        return MethodHandles.lookup().unreflect(method);
-    }
-
-    @Deprecated // does not work well with JPMS; inline at call-site instead
-    public static MethodHandle handleOfGetterOn(final Field field) throws IllegalAccessException {
-        return MethodHandles.lookup().unreflectGetter(field);
-    }
-
     // -- FIND GETTER
 
     @SneakyThrows
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/_TestDummies.java b/core/codegen-bytebuddy/src/main/java/module-info.java
similarity index 69%
copy from core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/_TestDummies.java
copy to core/codegen-bytebuddy/src/main/java/module-info.java
index 1d78aace5a..1cdc907f35 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/_TestDummies.java
+++ b/core/codegen-bytebuddy/src/main/java/module-info.java
@@ -16,15 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.core.metamodel._testing;
+module org.apache.isis.core.codegen.bytebuddy {
+    exports org.apache.isis.core.codegen.bytebuddy.services;
+    exports org.apache.isis.core.codegen.bytebuddy;
 
-import javax.annotation.PostConstruct;
-
-public class _TestDummies {
-
-    public static class WithPostConstruct {
-        @PostConstruct // @PostConstruct is allowed to appear on non-public methods
-        private void thisDoesHaveAnnotation(){}
-    }
-
-}
+    requires net.bytebuddy;
+    requires org.apache.isis.commons;
+    requires org.objenesis;
+    requires spring.context;
+    requires spring.core;
+    requires org.apache.isis.core.privileged;
+}
\ No newline at end of file
diff --git a/core/codegen-bytebuddy/src/main/java/org/apache/isis/core/codegen/bytebuddy/services/ClassLoadingStrategyAdvisor.java b/core/codegen-bytebuddy/src/main/java/org/apache/isis/core/codegen/bytebuddy/services/ClassLoadingStrategyAdvisor.java
index c033b70f9e..399ff327ef 100644
--- a/core/codegen-bytebuddy/src/main/java/org/apache/isis/core/codegen/bytebuddy/services/ClassLoadingStrategyAdvisor.java
+++ b/core/codegen-bytebuddy/src/main/java/org/apache/isis/core/codegen/bytebuddy/services/ClassLoadingStrategyAdvisor.java
@@ -19,8 +19,8 @@
 package org.apache.isis.core.codegen.bytebuddy.services;
 
 import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.reflect.Method;
+
+import org.apache.isis.core.privileged._Privileged;
 
 import net.bytebuddy.dynamic.loading.ClassInjector;
 import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
@@ -35,12 +35,17 @@ class ClassLoadingStrategyAdvisor {
     final MethodHandle privateLookupMethodHandle;
 
     ClassLoadingStrategyAdvisor() {
-        this.privateLookupMethodHandle = createPrivateLookupMethodHandle();
+        // JDK 9+ required
+        if (!ClassInjector.UsingLookup.isAvailable()) {
+            throw new IllegalStateException("No code generation strategy available");
+        }
+        this.privateLookupMethodHandle = _Privileged.createPrivateLookupMethodHandle();
     }
 
     public ClassLoadingStrategy<ClassLoader> getSuitableStrategy(final Class<?> targetClass) {
         try {
-            Object privateLookup = privateLookupMethodHandle.invoke(targetClass, MethodHandles.lookup());
+            final Object privateLookup = _Privileged
+                    .invokeLookup(privateLookupMethodHandle, targetClass);
             return ClassLoadingStrategy.UsingLookup.of(privateLookup);
         } catch (Throwable e) {
             throw new IllegalStateException(
@@ -50,27 +55,4 @@ class ClassLoadingStrategyAdvisor {
         }
     }
 
-    // -- HELPER
-
-    private MethodHandle createPrivateLookupMethodHandle() {
-
-        // JDK 9+
-        if (!ClassInjector.UsingLookup.isAvailable()) {
-            throw new IllegalStateException("No code generation strategy available");
-        }
-
-        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);
-        }
-
-    }
-
 }
diff --git a/core/metamodel/src/main/java/module-info.java b/core/metamodel/src/main/java/module-info.java
index 2faa38e5e8..41fd9edd91 100644
--- a/core/metamodel/src/main/java/module-info.java
+++ b/core/metamodel/src/main/java/module-info.java
@@ -306,6 +306,7 @@ open module org.apache.isis.core.metamodel {
     requires spring.beans;
     requires spring.context;
     requires spring.core;
+    requires org.apache.isis.core.privileged;
 
 //   opens org.apache.isis.core.metamodel.services to spring.core;
 //   opens org.apache.isis.core.metamodel.services.registry to spring.core;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/_TestDummies.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/_TestDummies.java
index 1d78aace5a..c80914df7c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/_TestDummies.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/_TestDummies.java
@@ -20,6 +20,13 @@ package org.apache.isis.core.metamodel._testing;
 
 import javax.annotation.PostConstruct;
 
+import org.apache.isis.applib.ViewModel;
+import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Nature;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
 public class _TestDummies {
 
     public static class WithPostConstruct {
@@ -27,4 +34,18 @@ public class _TestDummies {
         private void thisDoesHaveAnnotation(){}
     }
 
+    @DomainObject(nature = Nature.VIEW_MODEL)
+    @Data
+    @AllArgsConstructor
+    public static class CustomerAsViewmodel implements ViewModel {
+
+        private String name;
+
+        @Override
+        public String viewModelMemento() {
+            return name;
+        }
+
+    }
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java
index 67e4c1bc57..1c3d4591cb 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java
@@ -28,6 +28,7 @@ import org.apache.isis.core.metamodel.facets.HasPostConstructMethodCache;
 import org.apache.isis.core.metamodel.object.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
+import org.apache.isis.core.privileged._Privileged;
 
 import lombok.NonNull;
 import lombok.SneakyThrows;
@@ -103,8 +104,8 @@ extends ViewModelFacetAbstract {
         val constructorTakingMemento = ProgrammingModelConstants.ViewmodelConstructor.SINGLE_STRING_ARG
                 .get(viewmodelSpec.getCorrespondingClass())
                 .orElseThrow();
-        val viewmodelPojo = constructorTakingMemento
-                .newInstance(memento);
+        val viewmodelPojo = _Privileged
+                .newInstance(constructorTakingMemento, memento);
         return viewmodelPojo;
     }
 
diff --git a/core/pom.xml b/core/pom.xml
index 647f5d8ce8..4f8cc84212 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -473,6 +473,13 @@
 				<type>jar</type>
 				<scope>compile</scope>
 			</dependency>
+			<dependency>
+				<groupId>org.apache.isis.core</groupId>
+				<artifactId>isis-core-privileged</artifactId>
+				<version>2.0.0-SNAPSHOT</version>
+				<type>jar</type>
+				<scope>compile</scope>
+			</dependency>
 			<dependency>
 				<groupId>org.apache.isis.core</groupId>
 				<artifactId>isis-core-config</artifactId>
@@ -1640,6 +1647,8 @@
 
 		<module>jdk-supplemental</module>
 
+		<module>privileged</module>
+
 		<module>../commons</module>
 
 		<module>../api/schema</module>
diff --git a/core/privileged/pom.xml b/core/privileged/pom.xml
new file mode 100644
index 0000000000..74577bd714
--- /dev/null
+++ b/core/privileged/pom.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.isis.core</groupId>
+        <artifactId>isis-core</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>isis-core-privileged</artifactId>
+    <name>Apache Isis Core - Privileged</name>
+    <description>
+    	Installs as an automatic module with unrestricted access to the class-path (not module-path).
+    	In the context of the Java platform module system, allows for reflective access to all classes
+    	on the class-path. Classes on the module-path need to 'opens' to this module. 
+    </description>
+
+    <properties>
+    	<!-- For automatic module name resolution to work with your IDE, this project needs to be 
+    		'closed' (Eclipse) or 'ignored' (IntelliJ).
+    		see https://stackoverflow.com/questions/54195765/automatic-modules-not-found-in-eclipse-2018-12-when-project-is-opened 
+		-->
+        <jar-plugin.automaticModuleName>org.apache.isis.core.privileged</jar-plugin.automaticModuleName>
+        <git-plugin.propertiesDir>org/apache/isis/core/privileged</git-plugin.propertiesDir>
+    </properties>
+
+    <dependencies>
+    </dependencies>
+
+</project>
diff --git a/core/privileged/src/main/java/org/apache/isis/core/privileged/_Privileged.java b/core/privileged/src/main/java/org/apache/isis/core/privileged/_Privileged.java
new file mode 100644
index 0000000000..c180f92aa7
--- /dev/null
+++ b/core/privileged/src/main/java/org/apache/isis/core/privileged/_Privileged.java
@@ -0,0 +1,98 @@
+/*
+ *  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.privileged;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.concurrent.Callable;
+
+import lombok.NonNull;
+import lombok.SneakyThrows;
+import lombok.experimental.UtilityClass;
+
+/**
+ * <h1>- internal use only -</h1>
+ * <p>
+ * In the context of the Java platform module system (JPMS),
+ * allows for reflective access to all classes on the class-path (not module-path).
+ * <p>
+ * Requires the module - this class is contained in - to be installed as
+ * an automatic module.
+ * <p>
+ * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/>
+ * These may be changed or removed without notice!
+ *
+ * @since 2.0
+ */
+@UtilityClass
+public final class _Privileged {
+
+    // -- METHOD/FIELD HANDLES
+
+    public MethodHandle handleOf(final Method method) throws IllegalAccessException {
+        return MethodHandles.lookup().unreflect(method);
+    }
+
+    public MethodHandle handleOfGetterOn(final Field field) throws IllegalAccessException {
+        return MethodHandles.lookup().unreflectGetter(field);
+    }
+
+    // -- CONSTRUCTION
+
+    @SneakyThrows
+    public <T> T newInstance(final @NonNull Constructor<T> constructor, final Object ... initargs) {
+        return constructor.newInstance(initargs);
+    }
+
+    // -- METHOD INVOCATION
+
+    @SneakyThrows
+    public Object invoke(final @NonNull MethodHandle mh, final Object ... args) {
+        return mh.invoke(args);
+    }
+
+    @SneakyThrows
+    public Object invokeLookup(final @NonNull MethodHandle mh, final Class<?> targetClass) {
+        return mh.invoke(targetClass, MethodHandles.lookup());
+    }
+
+    public MethodHandle createPrivateLookupMethodHandle() {
+        try {
+            final Method privateLookupIn = java.lang.invoke.MethodHandles.class
+                    .getMethod("privateLookupIn",
+                        Class.class,
+                        java.lang.invoke.MethodHandles.Lookup.class);
+            return MethodHandles.publicLookup().unreflect(privateLookupIn);
+        } catch (Exception e) {
+            throw new IllegalStateException("MethodHandles.privateLookupIn(...) is not available", e);
+        }
+    }
+
+    // -- PRIVILEGED CALLS
+
+    @Deprecated // does not work
+    @SneakyThrows
+    public <T> T call(final @NonNull Callable<T> callable) {
+        return callable.call();
+    }
+
+}
diff --git a/viewers/wicket/ui/src/main/java/module-info.java b/viewers/wicket/ui/src/main/java/module-info.java
index e10bb531f7..9f2e9d39b1 100644
--- a/viewers/wicket/ui/src/main/java/module-info.java
+++ b/viewers/wicket/ui/src/main/java/module-info.java
@@ -160,4 +160,5 @@ module org.apache.isis.viewer.wicket.ui {
     requires wicket.bootstrap.themes;
     requires wicket.webjars;
     requires wicketstuff.select2;
+
 }
\ No newline at end of file
diff --git a/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/test/components/widgets/choices/ChoiceProviderForReferencesTest.java b/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/test/components/widgets/choices/ChoiceProviderForReferencesTest.java
index ada9ff051e..a498a82553 100644
--- a/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/test/components/widgets/choices/ChoiceProviderForReferencesTest.java
+++ b/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/test/components/widgets/choices/ChoiceProviderForReferencesTest.java
@@ -20,21 +20,16 @@ package org.apache.isis.viewer.wicket.ui.test.components.widgets.choices;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
 import org.wicketstuff.select2.Response;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-import org.apache.isis.applib.ViewModel;
-import org.apache.isis.applib.annotation.DomainObject;
-import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.commons.collections.Can;
+import org.apache.isis.core.metamodel._testing._TestDummies;
 import org.apache.isis.core.metamodel.object.ManagedObject;
 import org.apache.isis.core.metamodel.objectmanager.memento.ObjectMemento;
 import org.apache.isis.viewer.wicket.ui.components.widgets.select2.providers.ChoiceProviderForReferences;
 
-import lombok.AllArgsConstructor;
-import lombok.Data;
 import lombok.val;
 
 class ChoiceProviderForReferencesTest extends ChoiceProviderTestAbstract {
@@ -44,41 +39,12 @@ class ChoiceProviderForReferencesTest extends ChoiceProviderTestAbstract {
         super.setUp();
     }
 
-    @DomainObject(nature = Nature.VIEW_MODEL)
-    @Data
-    @AllArgsConstructor
-    public static class Customer implements ViewModel {
-
-        private String name;
-
-        @Override
-        public String viewModelMemento() {
-            return name;
-        }
-
-    }
-
-  //FIXME[ISIS-3207]
-    /*
-     * java.lang.IllegalAccessException:
-     * class org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacetForViewModelInterface
-     * (in module org.apache.isis.core.metamodel)
-     * cannot access
-     * class org.apache.isis.viewer.wicket.ui.test.components.widgets.choices.ChoiceProviderForReferencesTest$Customer
-     * (in module org.apache.isis.viewer.wicket.ui)
-     * because module
-     * org.apache.isis.viewer.wicket.ui
-     * does not export
-     * org.apache.isis.viewer.wicket.ui.test.components.widgets.choices
-     * to module org.apache.isis.core.metamodel
-     */
-    @DisabledIfSystemProperty(named = "isRunningWithSurefire", matches = "true")
     @Test
     void roundtrip() {
 
-        val a = new Customer("a");
-        val b = new Customer("b");
-        val c = new Customer("c");
+        val a = new _TestDummies.CustomerAsViewmodel("a");
+        val b = new _TestDummies.CustomerAsViewmodel("b");
+        val c = new _TestDummies.CustomerAsViewmodel("c");
 
         val choiceValues = Can.of(a, b, c);
 
@@ -94,12 +60,13 @@ class ChoiceProviderForReferencesTest extends ChoiceProviderTestAbstract {
 
         assertEquals(3, mementos.size());
 
+        /* debug
         mementos
         .forEach(memento->{
             System.err.printf("id: %s%n", choiceProvider.getIdValue(memento));
             System.err.printf("title (un-translated):  %s%n", memento.getTitle());
             System.err.printf("displayValue: %s%n", choiceProvider.getDisplayValue(memento));
-        });
+        });*/
 
         val asIds = mementos.map(choiceProvider::getIdValue);