| /* |
| * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /** |
| * @test |
| * @summary Basic test for redefineModule |
| * |
| * @build java.base/java.lang.TestProvider |
| * java.base/jdk.internal.test.TestProviderImpl1 |
| * java.base/jdk.internal.test.TestProviderImpl2 |
| * @run shell MakeJAR3.sh RedefineModuleAgent |
| * @run testng/othervm --illegal-access=deny -javaagent:RedefineModuleAgent.jar RedefineModuleTest |
| */ |
| |
| import java.lang.TestProvider; |
| import java.lang.instrument.Instrumentation; |
| import java.net.URLStreamHandler; |
| import java.net.spi.URLStreamHandlerProvider; |
| import java.nio.file.FileSystems; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.ServiceLoader; |
| import java.util.Set; |
| |
| import org.testng.annotations.Test; |
| import static org.testng.Assert.*; |
| |
| @Test |
| public class RedefineModuleTest { |
| |
| static void redefineModule(Module module, |
| Set<Module> extraReads, |
| Map<String, Set<Module>> extraExports, |
| Map<String, Set<Module>> extraOpens, |
| Set<Class<?>> extraUses, |
| Map<Class<?>, List<Class<?>>> extraProvides) { |
| RedefineModuleAgent.redefineModule(module, |
| extraReads, |
| extraExports, |
| extraOpens, |
| extraUses, |
| extraProvides); |
| } |
| |
| static boolean isModifiableModule(Module module) { |
| return RedefineModuleAgent.isModifiableModule(module); |
| } |
| |
| |
| /** |
| * Use redefineModule to update java.base to read java.instrument |
| */ |
| public void testAddReads() { |
| Module baseModule = Object.class.getModule(); |
| Module instrumentModule = Instrumentation.class.getModule(); |
| |
| // pre-conditions |
| assertFalse(baseModule.canRead(instrumentModule)); |
| |
| // update java.base to read java.instrument |
| Set<Module> extraReads = Set.of(instrumentModule); |
| redefineModule(baseModule, extraReads, Map.of(), Map.of(), Set.of(), Map.of()); |
| assertTrue(baseModule.canRead(instrumentModule)); |
| } |
| |
| /** |
| * Use redefineModule to update java.base to export jdk.internal.misc |
| */ |
| public void testAddExports() { |
| Module baseModule = Object.class.getModule(); |
| Module thisModule = this.getClass().getClassLoader().getUnnamedModule(); |
| String pkg = "jdk.internal.misc"; |
| |
| // pre-conditions |
| assertFalse(baseModule.isExported(pkg)); |
| assertFalse(baseModule.isExported(pkg, thisModule)); |
| |
| // update java.base to export jdk.internal.misc to an unnamed module |
| Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of(thisModule)); |
| redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); |
| assertFalse(baseModule.isExported(pkg)); |
| assertTrue(baseModule.isExported(pkg, thisModule)); |
| assertFalse(baseModule.isOpen(pkg)); |
| assertFalse(baseModule.isOpen(pkg, thisModule)); |
| } |
| |
| /** |
| * Use redefineModule to update java.base to open jdk.internal.loader |
| */ |
| public void testAddOpens() { |
| Module baseModule = Object.class.getModule(); |
| Module thisModule = this.getClass().getClassLoader().getUnnamedModule(); |
| String pkg = "jdk.internal.loader"; |
| |
| // pre-conditions |
| assertFalse(baseModule.isOpen(pkg)); |
| assertFalse(baseModule.isOpen(pkg, thisModule)); |
| |
| // update java.base to open dk.internal.loader to an unnamed module |
| Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of(thisModule)); |
| redefineModule(baseModule, Set.of(), Map.of(), extraExports, Set.of(), Map.of()); |
| assertFalse(baseModule.isExported(pkg)); |
| assertTrue(baseModule.isExported(pkg, thisModule)); |
| assertFalse(baseModule.isOpen(pkg)); |
| assertTrue(baseModule.isOpen(pkg, thisModule)); |
| } |
| |
| /** |
| * Use redefineModule to update java.base to use TestProvider and |
| * provide implementations of TestProvider. |
| */ |
| public void testAddUsesAndProvides() throws Exception { |
| Module baseModule = Object.class.getModule(); |
| Class<TestProvider> service = TestProvider.class; |
| |
| // pre-conditions |
| assertFalse(baseModule.canUse(service)); |
| assertTrue(collect(ServiceLoader.load(service)).isEmpty()); |
| assertTrue(collect(ServiceLoader.load(ModuleLayer.boot(), service)).isEmpty()); |
| |
| // update java.base to use TestProvider |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(service), Map.of()); |
| assertTrue(baseModule.canUse(service)); |
| assertTrue(collect(ServiceLoader.load(service)).isEmpty()); |
| assertTrue(collect(ServiceLoader.load(ModuleLayer.boot(), service)).isEmpty()); |
| |
| // update java.base to provide an implementation of TestProvider |
| Class<?> type1 = Class.forName("jdk.internal.test.TestProviderImpl1"); |
| Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of(type1)); |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); |
| |
| // invoke ServiceLoader from java.base to find providers |
| Set<TestProvider> providers = collect(TestProvider.providers()); |
| assertTrue(providers.size() == 1); |
| assertTrue(containsInstanceOf(providers, type1)); |
| |
| // use ServiceLoader to load implementations visible via TCCL |
| providers = collect(ServiceLoader.load(service)); |
| assertTrue(collect(providers).size() == 1); |
| assertTrue(containsInstanceOf(collect(providers), type1)); |
| |
| // use ServiceLoader to load implementations in the boot layer |
| providers = collect(ServiceLoader.load(ModuleLayer.boot(), service)); |
| assertTrue(collect(providers).size() == 1); |
| assertTrue(containsInstanceOf(collect(providers), type1)); |
| |
| // update java.base to provide a second implementation of TestProvider |
| Class<?> type2 = Class.forName("jdk.internal.test.TestProviderImpl2"); |
| extraProvides = Map.of(service, List.of(type2)); |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); |
| |
| // invoke ServiceLoader from java.base to find providers |
| providers = collect(TestProvider.providers()); |
| assertTrue(providers.size() == 2); |
| assertTrue(containsInstanceOf(providers, type1)); |
| assertTrue(containsInstanceOf(providers, type2)); |
| |
| // use ServiceLoader to load implementations visible via TCCL |
| providers = collect(ServiceLoader.load(service)); |
| assertTrue(collect(providers).size() == 2); |
| assertTrue(containsInstanceOf(providers, type1)); |
| assertTrue(containsInstanceOf(providers, type2)); |
| |
| // use ServiceLoader to load implementations in the boot layer |
| providers = collect(ServiceLoader.load(ModuleLayer.boot(), service)); |
| assertTrue(collect(providers).size() == 2); |
| assertTrue(containsInstanceOf(providers, type1)); |
| assertTrue(containsInstanceOf(providers, type2)); |
| } |
| |
| private <S> Set<S> collect(Iterable<S> sl) { |
| Set<S> providers = new HashSet<>(); |
| sl.forEach(providers::add); |
| return providers; |
| } |
| |
| private boolean containsInstanceOf(Collection<?> c, Class<?> type) { |
| for (Object o : c) { |
| if (type.isInstance(o)) return true; |
| } |
| return false; |
| } |
| |
| @Test(expectedExceptions = IllegalArgumentException.class) |
| public void testExportPackageToEmptySet() { |
| // attempt to update java.base to export jdk.internal.misc to nobody |
| Module baseModule = Object.class.getModule(); |
| Map<String, Set<Module>> extraExports = Map.of("jdk.internal.misc", Set.of()); |
| redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); |
| } |
| |
| @Test(expectedExceptions = IllegalArgumentException.class) |
| public void testOpenPackageToEmptySet() { |
| // attempt to update java.base to open jdk.internal.misc to nobody |
| Module baseModule = Object.class.getModule(); |
| Map<String, Set<Module>> extraOpens = Map.of("jdk.internal.misc", Set.of()); |
| redefineModule(baseModule, Set.of(), Map.of(), extraOpens, Set.of(), Map.of()); |
| } |
| |
| @Test(expectedExceptions = IllegalArgumentException.class) |
| public void testProvideServiceWithEmptyList() throws Exception { |
| // update java.base to provide an empty list of TestProvider |
| Module baseModule = Object.class.getModule(); |
| Class<?> service = TestProvider.class; |
| Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of()); |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); |
| } |
| |
| /** |
| * Test redefineClass by attempting to update java.base to export a package |
| * that it does not contain. |
| */ |
| @Test(expectedExceptions = IllegalArgumentException.class) |
| public void testExportPackageNotInModule() { |
| Module baseModule = Object.class.getModule(); |
| String pkg = "jdk.doesnotexist"; |
| |
| // attempt to update java.base to export jdk.doesnotexist |
| Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of()); |
| redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); |
| } |
| |
| /** |
| * Test redefineClass by attempting to update java.base to provide a service |
| * where the service provider class is not in the module. |
| */ |
| @Test(expectedExceptions = IllegalArgumentException.class) |
| public void testProvideServiceNotInModule() { |
| Module baseModule = Object.class.getModule(); |
| class MyProvider extends URLStreamHandlerProvider { |
| @Override |
| public URLStreamHandler createURLStreamHandler(String protocol) { |
| return null; |
| } |
| } |
| |
| // attempt to update java.base to provide MyProvider |
| Map<Class<?>, List<Class<?>>> extraProvides |
| = Map.of(URLStreamHandlerProvider.class, List.of(MyProvider.class)); |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); |
| } |
| |
| /** |
| * Test redefineClass by attempting to update java.base to provide a |
| * service where the service provider class is not a sub-type. |
| */ |
| @Test(expectedExceptions = IllegalArgumentException.class) |
| public void testProvideServiceNotSubtype() { |
| Module baseModule = Object.class.getModule(); |
| |
| Class<?> service = TestProvider.class; |
| Class<?> impl = FileSystems.getDefault().provider().getClass(); |
| |
| // attempt to update java.base to provide an implementation of TestProvider |
| Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of(impl)); |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); |
| } |
| |
| /** |
| * Exercise IsModifiableModule |
| */ |
| @Test |
| public void testIsModifiableModule() { |
| ClassLoader pcl = ClassLoader.getPlatformClassLoader(); |
| ClassLoader scl = ClassLoader.getSystemClassLoader(); |
| assertTrue(isModifiableModule(pcl.getUnnamedModule())); |
| assertTrue(isModifiableModule(scl.getUnnamedModule())); |
| assertTrue(isModifiableModule(RedefineModuleTest.class.getModule())); |
| assertTrue(isModifiableModule(Object.class.getModule())); |
| } |
| |
| /** |
| * Test redefineClass with null |
| */ |
| public void testNulls() { |
| Module baseModule = Object.class.getModule(); |
| |
| try { |
| redefineModule(null, Set.of(), Map.of(), Map.of(), Set.of(), Map.of()); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| redefineModule(baseModule, null, Map.of(), Map.of(), Set.of(), Map.of()); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| redefineModule(baseModule, Set.of(), null, Map.of(), Set.of(), Map.of()); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| redefineModule(baseModule, Set.of(), Map.of(), null, Set.of(), Map.of()); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), null, Map.of()); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), null); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| Set<Module> containsNull = new HashSet<>(); |
| containsNull.add(null); |
| redefineModule(baseModule, containsNull, Map.of(), Map.of(), Set.of(), Map.of()); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| Map<String, Set<Module>> extraExports = new HashMap<>(); |
| extraExports.put(null, Set.of()); |
| redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| Map<String, Set<Module>> extraExports = new HashMap<>(); |
| extraExports.put(null, Set.of()); |
| redefineModule(baseModule, Set.of(), Map.of(), extraExports, Set.of(), Map.of()); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| Set<Module> containsNull = new HashSet<>(); |
| containsNull.add(null); |
| Map<String, Set<Module>> extraExports = Map.of("java.lang", containsNull); |
| redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| Set<Class<?>> containsNull = new HashSet<>(); |
| containsNull.add(null); |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), containsNull, Map.of()); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| Map<Class<?>, List<Class<?>>> extraProvides = new HashMap<>(); |
| extraProvides.put(null, List.of()); |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| |
| try { |
| List<Class<?>> containsNull = new ArrayList<>(); |
| containsNull.add(null); |
| Map<Class<?>, List<Class<?>>> extraProvides = Map.of(TestProvider.class, containsNull); |
| redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); |
| assertTrue(false); |
| } catch (NullPointerException e) { } |
| } |
| |
| } |