diff --git a/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/Initializer/DynamicModuleApplicationContextInitializer.java b/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/Initializer/DynamicModuleExportApplicationContextInitializer.java similarity index 82% rename from sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/Initializer/DynamicModuleApplicationContextInitializer.java rename to sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/Initializer/DynamicModuleExportApplicationContextInitializer.java index 73f92a0bc..ea7ad06d3 100644 --- a/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/Initializer/DynamicModuleApplicationContextInitializer.java +++ b/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/Initializer/DynamicModuleExportApplicationContextInitializer.java @@ -22,12 +22,11 @@ /** * @author huazhongming - * @date 2024/8/7 * @since 4.4.0 */ -public class DynamicModuleApplicationContextInitializer - implements - ApplicationContextInitializer { +public class DynamicModuleExportApplicationContextInitializer + implements + ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext applicationContext) { ModuleUtil.exportAllJDKModulePackageToAll(); diff --git a/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/util/ModuleUtil.java b/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/util/ModuleUtil.java index 1b4564851..585c31499 100644 --- a/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/util/ModuleUtil.java +++ b/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/util/ModuleUtil.java @@ -16,6 +16,9 @@ */ package com.alipay.sofa.boot.util; +import com.alipay.sofa.boot.log.SofaBootLoggerFactory; +import org.slf4j.Logger; + import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; import java.util.Map; @@ -23,25 +26,28 @@ /** * @author huazhongming - * @date 2024/8/7 16 * @since 4.4.0 */ public class ModuleUtil { + + private static final Logger LOGGER = SofaBootLoggerFactory.getLogger(ModuleUtil.class); + private static final MethodHandle implAddOpensToAllUnnamed; private static final MethodHandle implAddOpens; private static final MethodHandle implAddExportsToAllUnnamed; private static final MethodHandle implAddExports; static { - implAddOpensToAllUnnamed = createModuleMethodHandle("implAddOpensToAllUnnamed", String.class); + implAddOpensToAllUnnamed = createModuleMethodHandle("implAddOpensToAllUnnamed", + String.class); implAddOpens = createModuleMethodHandle("implAddOpens", String.class); - implAddExportsToAllUnnamed = createModuleMethodHandle("implAddExportsToAllUnnamed", String.class); + implAddExportsToAllUnnamed = createModuleMethodHandle("implAddExportsToAllUnnamed", + String.class); implAddExports = createModuleMethodHandle("implAddExports", String.class); - } /** - * + * Export all JDK module packages to all. */ public static void exportAllJDKModulePackageToAll() { try { @@ -54,8 +60,8 @@ public static void exportAllJDKModulePackageToAll() { } })); } - } catch (Throwable ignored) { - + } catch (Throwable t) { + LOGGER.error("Failed to export all JDK module package to all", t); } } @@ -63,6 +69,9 @@ private static boolean isJDKModulePackage(String modulePackageName) { return modulePackageName.startsWith("java.") || modulePackageName.startsWith("jdk."); } + /** + * Export all module packages to all. + */ public static void exportAllModulePackageToAll() { try { Map nameToModules = getNameToModule(); @@ -72,25 +81,67 @@ public static void exportAllModulePackageToAll() { addExportsToAll(module, pkgName); })); } - } catch (Throwable ignored) { - + } catch (Throwable t) { + LOGGER.error("Failed to export all module package to all", t); } } /** + * Updates this module to open a package to all unnamed modules. + * * @param moduleName * @param packageName - * @see java.lang.Module#implAddOpensToAllUnnamed(String) */ public static boolean addOpensToAllUnnamed(String moduleName, String packageName) { return invokeModuleMethod(implAddOpensToAllUnnamed, moduleName, packageName); } /** + * Updates this module to open a package to all unnamed modules. + * + * @param module + * @param packageName + */ + public static boolean addOpensToAllUnnamed(Module module, String packageName) { + return invokeModuleMethod(implAddOpensToAllUnnamed, module, packageName); + } + + /** + * Updates this module to export a package to all unnamed modules. + * + * @param moduleName + * @param packageName + */ + public static boolean addExportsToAllUnnamed(String moduleName, String packageName) { + return invokeModuleMethod(implAddExportsToAllUnnamed, moduleName, packageName); + } + + /** + * Updates this module to export a package to all unnamed modules. + * + * @param module + * @param packageName + */ + public static boolean addExportsToAllUnnamed(Module module, String packageName) { + return invokeModuleMethod(implAddExportsToAllUnnamed, module, packageName); + } + + /** + * Updates this module to open a package to another module. + * + * @param moduleName + * @param packageName + */ + public static boolean addOpensToAll(String moduleName, String packageName) { + + return invokeModuleMethod(implAddOpens, moduleName, packageName); + } + + /** + * Updates this module to open a package to another module. * * @param module * @param packageName - * @see java.lang.Module#implAddOpens(String) */ public static boolean addOpensToAll(Module module, String packageName) { @@ -98,30 +149,39 @@ public static boolean addOpensToAll(Module module, String packageName) { } /** + * Updates this module to export a package unconditionally. + * @param moduleName + * @param packageName + */ + public static boolean addExportsToAll(String moduleName, String packageName) { + return invokeModuleMethod(implAddExports, moduleName, packageName); + } + + /** + * Updates this module to export a package unconditionally. * @param module * @param packageName - * @see java.lang.Module#implAddExports(String) */ public static boolean addExportsToAll(Module module, String packageName) { return invokeModuleMethod(implAddExports, module, packageName); } - /** - * invoke ModuleLayer.bootLayer method + * invoke ModuleLayer method * * @param method * @param moduleName * @param packageName * @return */ - public static boolean invokeModuleMethod(MethodHandle method, String moduleName, String packageName) { + public static boolean invokeModuleMethod(MethodHandle method, String moduleName, + String packageName) { Optional findModule = ModuleLayer.boot().findModule(moduleName); if (findModule.isPresent()) { try { return invokeModuleMethod(method, findModule.get(), packageName); - } catch (Throwable e) { - // ignore + } catch (Throwable t) { + LOGGER.error("Failed to invoke ModuleLayer method: {}", method, t); } } return false; @@ -131,8 +191,8 @@ public static boolean invokeModuleMethod(MethodHandle method, Module module, Str try { method.invoke(module, packageName); return true; - } catch (Throwable e) { - // ignore + } catch (Throwable t) { + LOGGER.error("Failed to invoke Module method: {}", method, t); } return false; } @@ -144,12 +204,13 @@ public static boolean invokeModuleMethod(MethodHandle method, Module module, Str * @param parameterTypes * @return MethodHandle */ - private static MethodHandle createModuleMethodHandle(String methodName, Class... parameterTypes) { + private static MethodHandle createModuleMethodHandle(String methodName, + Class... parameterTypes) { try { return UnsafeUtil.implLookup().unreflect( - Module.class.getDeclaredMethod(methodName, parameterTypes)); - } catch (Throwable e) { - // ignore + Module.class.getDeclaredMethod(methodName, parameterTypes)); + } catch (Throwable t) { + LOGGER.error("Failed to create Module method handle: {}", methodName, t); } return null; } @@ -167,13 +228,13 @@ private static Object getModuleLayerFieldsValue(String fieldName) { Field field = moduleLayerClass.getDeclaredField(fieldName); return UnsafeUtil.implLookup().unreflectVarHandle(field).get(moduleLayer); } catch (Throwable t) { - // ignore + LOGGER.error("Failed to get ModuleLayer field value: {}", fieldName, t); } return null; } /** - * Get all Modules from System.bootLayer + * Get all modules from System.bootLayer * * @return modules */ diff --git a/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/util/UnsafeUtil.java b/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/util/UnsafeUtil.java index 8ed4b8361..0bbbca199 100644 --- a/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/util/UnsafeUtil.java +++ b/sofa-boot-project/sofa-boot/src/main/java/com/alipay/sofa/boot/util/UnsafeUtil.java @@ -23,7 +23,6 @@ /** * @author huazhongming - * @date 2024/8/7 16 * @since 4.4.0 */ public class UnsafeUtil { @@ -38,7 +37,6 @@ public static Unsafe unsafe() { theUnsafeField.setAccessible(true); unsafe = (Unsafe) theUnsafeField.get(null); } catch (Throwable ignored) { - // ignored } UNSAFE = unsafe; } @@ -55,8 +53,7 @@ public static MethodHandles.Lookup implLookup() { long offset = unsafe().staticFieldOffset(implLookupField); IMPL_LOOKUP = (MethodHandles.Lookup) unsafe().getObject( unsafe().staticFieldBase(implLookupField), offset); - } catch (Throwable e) { - // ignored + } catch (Throwable ignored) { } } return IMPL_LOOKUP; diff --git a/sofa-boot-project/sofa-boot/src/main/resources/META-INF/spring.factories b/sofa-boot-project/sofa-boot/src/main/resources/META-INF/spring.factories index 2fa85440b..d8588564b 100644 --- a/sofa-boot-project/sofa-boot/src/main/resources/META-INF/spring.factories +++ b/sofa-boot-project/sofa-boot/src/main/resources/META-INF/spring.factories @@ -16,4 +16,4 @@ org.springframework.boot.SpringApplicationRunListener=\ # Initializers org.springframework.context.ApplicationContextInitializer=\ com.alipay.sofa.boot.compatibility.CompatibilityVerifierApplicationContextInitializer,\ - com.alipay.sofa.boot.Initializer.DynamicModuleApplicationContextInitializer + com.alipay.sofa.boot.Initializer.DynamicModuleExportApplicationContextInitializer diff --git a/sofa-boot-project/sofa-boot/src/test/java/com/alipay/sofa/boot/util/ModuleUtilTests.java b/sofa-boot-project/sofa-boot/src/test/java/com/alipay/sofa/boot/util/ModuleUtilTests.java new file mode 100644 index 000000000..d9f22d27c --- /dev/null +++ b/sofa-boot-project/sofa-boot/src/test/java/com/alipay/sofa/boot/util/ModuleUtilTests.java @@ -0,0 +1,50 @@ +/* + * 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 com.alipay.sofa.boot.util; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.InaccessibleObjectException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author huazhongming + * @since 4.4.0 + */ +public class ModuleUtilTests { + + @Test + public void testExportAllJDKModulePackageToAll() throws NoSuchMethodException { + + Exception exception = assertThrows(InaccessibleObjectException.class,() -> { + Method newByteChannel0Method = Files.class.getDeclaredMethod("provider", Path.class); + newByteChannel0Method.setAccessible(true); + }); + + assertTrue(exception.getMessage().contains("module java.base does not \"opens java.nio.file\" to unnamed module")); + + ModuleUtil.exportAllJDKModulePackageToAll(); + + java.lang.reflect.Method newByteChannel0Method = Files.class.getDeclaredMethod("provider", Path.class); + newByteChannel0Method.setAccessible(true); + } +}