/* * Copyright (c) 2016, 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 -javaagent:RedefineModuleAgent.jar RedefineModuleTest */ import java.lang.TestProvider; import java.lang.instrument.Instrumentation; import java.lang.reflect.Layer; import java.lang.reflect.Module; 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 extraReads, Map> extraExports, Map> extraOpens, Set> extraUses, Map, List>> extraProvides) { RedefineModuleAgent.redefineModule(module, extraReads, extraExports, extraOpens, extraUses, extraProvides); } /** * 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 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> 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> 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 service = TestProvider.class; // pre-conditions assertFalse(baseModule.canUse(service)); assertTrue(collect(ServiceLoader.load(service)).isEmpty()); assertTrue(collect(ServiceLoader.load(Layer.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(Layer.boot(), service)).isEmpty()); // update java.base to provide an implementation of TestProvider Class type1 = Class.forName("jdk.internal.test.TestProviderImpl1"); Map, List>> 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 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(Layer.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(Layer.boot(), service)); assertTrue(collect(providers).size() == 2); assertTrue(containsInstanceOf(providers, type1)); assertTrue(containsInstanceOf(providers, type2)); } private Set collect(Iterable sl) { Set 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> 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> 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, List>> 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> 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, List>> 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, List>> extraProvides = Map.of(service, List.of(impl)); redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); } /** * 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 containsNull = new HashSet<>(); containsNull.add(null); redefineModule(baseModule, containsNull, Map.of(), Map.of(), Set.of(), Map.of()); assertTrue(false); } catch (NullPointerException e) { } try { Map> 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> 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 containsNull = new HashSet<>(); containsNull.add(null); Map> extraExports = Map.of("java.lang", containsNull); redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); assertTrue(false); } catch (NullPointerException e) { } try { Set> containsNull = new HashSet<>(); containsNull.add(null); redefineModule(baseModule, Set.of(), Map.of(), Map.of(), containsNull, Map.of()); assertTrue(false); } catch (NullPointerException e) { } try { Map, List>> 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> containsNull = new ArrayList<>(); containsNull.add(null); Map, List>> extraProvides = Map.of(TestProvider.class, containsNull); redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); assertTrue(false); } catch (NullPointerException e) { } } }