undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,157 @@
/*
* Copyright (c) 2017, 2025, 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
* @modules java.base/jdk.internal.module
* @library /test/lib
* @build jdk.test.lib.util.ModuleInfoWriter
* @run testng ClassFileVersionsTest
* @summary Test parsing of module-info.class with different class file versions
*/
import java.lang.classfile.ClassFile;
import java.lang.module.InvalidModuleDescriptorException;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.Requires.Modifier;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
import jdk.test.lib.util.ModuleInfoWriter;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
public class ClassFileVersionsTest {
private static final int PREVIEW_MINOR_VERSION =
ClassFile.PREVIEW_MINOR_VERSION;
private static final int FEATURE;
static {
FEATURE = Runtime.version().feature();
assert FEATURE >= 10;
}
// major, minor, modifiers for requires java.base
@DataProvider(name = "supported")
public Object[][] supported() {
/*
* There are four test cases for JDK 9, one test case
* for each subsequent JDK version from JDK 10 to the current
* feature release, and two tests for the current release with
* a preview flag set, for a total of (4 + (FEATURE - 9) + 2)
* rows.
*/
List<Object[]> result = new ArrayList<>(4 + (FEATURE - 9) + 2);
// Class file version of JDK 9 is 53.0
result.add(new Object[]{ 53, 0, Set.of()});
result.add(new Object[]{ 53, 0, Set.of(STATIC) });
result.add(new Object[]{ 53, 0, Set.of(TRANSITIVE) });
result.add(new Object[]{ 53, 0, Set.of(STATIC, TRANSITIVE) });
// Major class file version of JDK N is 44 + n. Create rows
// for JDK 10 through FEATURE.
for (int i = 10; i <= FEATURE; i++) {
result.add(new Object[]{ 44 + i, 0, Set.of()});
result.add(new Object[]{ 44 + i, 0, Set.of(TRANSITIVE)});
}
result.add(new Object[]{ 44 + FEATURE,
PREVIEW_MINOR_VERSION,
Set.of()});
result.add(new Object[]{ 44 + FEATURE,
PREVIEW_MINOR_VERSION,
Set.of(TRANSITIVE) });
return result.toArray(s -> new Object[s][]);
}
// major, minor, modifiers for requires java.base
@DataProvider(name = "unsupported")
public Object[][] unsupported() {
/*
* There are three test cases for releases prior to JDK 9,
* three test cases for each JDK version from JDK 10 to the
* current feature release, two tests for the current release with
* the preview flag set, plus one addition test case for
* the next release for a total of (3 + (FEATURE - 9) * 3 + 2 + 1)
* rows.
*/
List<Object[]> result = new ArrayList<>(3 + (FEATURE - 9) * 3 + 2 + 1);
result.add(new Object[]{50, 0, Set.of()}); // JDK 6
result.add(new Object[]{51, 0, Set.of()}); // JDK 7
result.add(new Object[]{52, 0, Set.of()}); // JDK 8
for (int i = 10; i <= FEATURE ; i++) {
// Major class file version of JDK N is 44+n
result.add(new Object[]{i + 44, 0, Set.of(STATIC)});
result.add(new Object[]{i + 44, 0, Set.of(STATIC, TRANSITIVE)});
}
result.add(new Object[]{FEATURE + 44,
PREVIEW_MINOR_VERSION,
Set.of(STATIC)});
result.add(new Object[]{FEATURE + 44,
PREVIEW_MINOR_VERSION,
Set.of(STATIC, TRANSITIVE)});
result.add(new Object[]{FEATURE+1+44, 0, Set.of()});
return result.toArray(s -> new Object[s][]);
}
@Test(dataProvider = "supported")
public void testSupported(int major, int minor, Set<Modifier> ms) {
ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo")
.requires(ms, "java.base")
.build();
ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor);
classFileVersion(bb, major, minor);
descriptor = ModuleDescriptor.read(bb);
assertEquals(descriptor.name(), "foo");
}
@Test(dataProvider = "unsupported",
expectedExceptions = InvalidModuleDescriptorException.class)
public void testUnsupported(int major, int minor, Set<Modifier> ms) {
ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo")
.requires(ms, "java.base")
.build();
ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor);
classFileVersion(bb, major, minor);
// throws InvalidModuleDescriptorException
ModuleDescriptor.read(bb);
}
private void classFileVersion(ByteBuffer bb, int major, int minor) {
bb.putShort(4, (short) minor);
bb.putShort(6, (short) major);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,190 @@
/*
* Copyright (c) 2021, 2022, 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.
*/
import java.io.IOException;
import java.io.InputStream;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.Exports;
import java.lang.module.ModuleDescriptor.Opens;
import java.lang.module.ModuleDescriptor.Requires;
import java.util.Set;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotSame;
/**
* @test
* @bug 8275509 8290041
* @summary Tests the ModuleDescriptor.hashCode()
* @run testng ModuleDescriptorHashCodeTest
* @run testng/othervm -Xshare:off ModuleDescriptorHashCodeTest
*/
public class ModuleDescriptorHashCodeTest {
/**
* Verifies that the ModuleDescriptor.hashCode() returned by a boot layer module is
* the same as that returned by a ModuleDescriptor constructed from the ModuleDescriptor.Builder
* for the same module.
*/
@Test
public void testBootModuleDescriptor() throws Exception {
Set<Module> bootModules = ModuleLayer.boot().modules();
for (Module bootModule : bootModules) {
System.out.println("Testing module descriptor of boot module " + bootModule);
ModuleDescriptor bootMD = bootModule.getDescriptor();
ModuleDescriptor mdFromBuilder = fromModuleInfoClass(bootModule);
// verify that this object is indeed a different object instance than the boot module descriptor
// to prevent any artificial passing of the test
assertNotSame(mdFromBuilder, bootMD, "ModuleDescriptor loaded from boot layer and " +
"one created from module-info.class unexpectedly returned the same instance");
assertEquals(mdFromBuilder.hashCode(), bootMD.hashCode(),
"Unexpected ModuleDescriptor.hashCode() for " + mdFromBuilder);
assertEquals(mdFromBuilder.compareTo(bootMD), 0,
"Unexpected ModuleDescriptor.compareTo() for " + mdFromBuilder);
}
}
/**
* Verifies that two "equal" module descriptors which only differ in the order of
* {@link ModuleDescriptor.Opens.Modifier opens modifiers}, that were used to construct the
* descriptors, have the same hashcode.
*/
@Test
public void testOpensModifiersOrdering() throws Exception {
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
final Set<Opens.Modifier> mods1 = Set.of(Opens.Modifier.SYNTHETIC, Opens.Modifier.MANDATED);
final ModuleDescriptor desc1 = createModuleDescriptor(mods1, null, null);
// create the same module descriptor again and this time just change the order of the
// "opens" modifiers' Set.
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
final Set<Opens.Modifier> mods2 = Set.of(Opens.Modifier.MANDATED, Opens.Modifier.SYNTHETIC);
final ModuleDescriptor desc2 = createModuleDescriptor(mods2, null, null);
// basic verification of the modifiers themselves before we check the module descriptors
assertEquals(mods1, mods2, "Modifiers were expected to be equal");
// now verify the module descriptors
assertEquals(desc1, desc2, "Module descriptors were expected to be equal");
assertEquals(desc1.compareTo(desc2), 0, "compareTo was expected to return" +
" 0 for module descriptors that are equal");
System.out.println(desc1 + " hashcode = " + desc1.hashCode());
System.out.println(desc2 + " hashcode = " + desc2.hashCode());
assertEquals(desc1.hashCode(), desc2.hashCode(), "Module descriptor hashcodes" +
" were expected to be equal");
}
/**
* Verifies that two "equal" module descriptors which only differ in the order of
* {@link ModuleDescriptor.Exports.Modifier exports modifiers}, that were used to construct the
* descriptors, have the same hashcode.
*/
@Test
public void testExportsModifiersOrdering() throws Exception {
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
final Set<Exports.Modifier> mods1 = Set.of(Exports.Modifier.SYNTHETIC, Exports.Modifier.MANDATED);
final ModuleDescriptor desc1 = createModuleDescriptor(null, null, mods1);
// create the same module descriptor again and this time just change the order of the
// "exports" modifiers' Set.
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
final Set<Exports.Modifier> mods2 = Set.of(Exports.Modifier.MANDATED, Exports.Modifier.SYNTHETIC);
final ModuleDescriptor desc2 = createModuleDescriptor(null, null, mods2);
// basic verification of the modifiers themselves before we check the module descriptors
assertEquals(mods1, mods2, "Modifiers were expected to be equal");
// now verify the module descriptors
assertEquals(desc1, desc2, "Module descriptors were expected to be equal");
assertEquals(desc1.compareTo(desc2), 0, "compareTo was expected to return" +
" 0 for module descriptors that are equal");
System.out.println(desc1 + " hashcode = " + desc1.hashCode());
System.out.println(desc2 + " hashcode = " + desc2.hashCode());
assertEquals(desc1.hashCode(), desc2.hashCode(), "Module descriptor hashcodes" +
" were expected to be equal");
}
/**
* Verifies that two "equal" module descriptors which only differ in the order of
* {@link ModuleDescriptor.Requires.Modifier requires modifiers}, that were used to construct the
* descriptors, have the same hashcode.
*/
@Test
public void testRequiresModifiersOrdering() throws Exception {
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
final Set<Requires.Modifier> mods1 = Set.of(Requires.Modifier.SYNTHETIC, Requires.Modifier.MANDATED);
final ModuleDescriptor desc1 = createModuleDescriptor(null, mods1, null);
// create the same module descriptor again and this time just change the order of the
// "exports" modifiers' Set.
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
final Set<Requires.Modifier> mods2 = Set.of(Requires.Modifier.MANDATED, Requires.Modifier.SYNTHETIC);
final ModuleDescriptor desc2 = createModuleDescriptor(null, mods2, null);
// basic verification of the modifiers themselves before we check the module descriptors
assertEquals(mods1, mods2, "Modifiers were expected to be equal");
// now verify the module descriptors
assertEquals(desc1, desc2, "Module descriptors were expected to be equal");
assertEquals(desc1.compareTo(desc2), 0, "compareTo was expected to return" +
" 0 for module descriptors that are equal");
System.out.println(desc1 + " hashcode = " + desc1.hashCode());
System.out.println(desc2 + " hashcode = " + desc2.hashCode());
assertEquals(desc1.hashCode(), desc2.hashCode(), "Module descriptor hashcodes" +
" were expected to be equal");
}
// Returns a ModuleDescriptor parsed out of the module-info.class of the passed Module
private static ModuleDescriptor fromModuleInfoClass(Module module) throws IOException {
try (InputStream moduleInfo = module.getResourceAsStream("module-info.class")) {
if (moduleInfo == null) {
throw new RuntimeException("Could not locate module-info.class in " + module);
}
// internally calls ModuleDescriptor.Builder
return ModuleDescriptor.read(moduleInfo);
}
}
// creates a module descriptor with passed (optional) opens/exports/requires modifiers
private static ModuleDescriptor createModuleDescriptor(
Set<Opens.Modifier> opensModifiers,
Set<Requires.Modifier> reqsModifiers,
Set<Exports.Modifier> expsModifiers) {
final ModuleDescriptor.Builder builder = ModuleDescriptor.newModule("foobar");
if (opensModifiers != null) {
builder.opens(opensModifiers, "a.p1", Set.of("a.m1"));
}
if (reqsModifiers != null) {
builder.requires(reqsModifiers, "a.m2");
}
if (expsModifiers != null) {
builder.exports(expsModifiers, "a.b.c", Set.of("a.m3"));
}
return builder.build();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,829 @@
/*
* Copyright (c) 2015, 2024, 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
* @modules java.base/jdk.internal.module
* @library /test/lib
* @build ModuleFinderTest jdk.test.lib.util.ModuleInfoWriter
* @run testng ModuleFinderTest
* @summary Basic tests for java.lang.module.ModuleFinder
*/
import java.io.File;
import java.io.OutputStream;
import java.lang.module.FindException;
import java.lang.module.InvalidModuleDescriptorException;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;
import jdk.test.lib.util.ModuleInfoWriter;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@Test
public class ModuleFinderTest {
private static final Path USER_DIR
= Paths.get(System.getProperty("user.dir"));
/**
* Test ModuleFinder.ofSystem
*/
public void testOfSystem() {
ModuleFinder finder = ModuleFinder.ofSystem();
assertTrue(finder.find("java.se").isPresent());
assertTrue(finder.find("java.base").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
Set<String> names = finder.findAll().stream()
.map(ModuleReference::descriptor)
.map(ModuleDescriptor::name)
.collect(Collectors.toSet());
assertTrue(names.contains("java.se"));
assertTrue(names.contains("java.base"));
assertFalse(names.contains("java.rhubarb"));
}
/**
* Test ModuleFinder.of with no entries
*/
public void testOfNoEntries() {
ModuleFinder finder = ModuleFinder.of();
assertTrue(finder.findAll().isEmpty());
assertFalse(finder.find("java.rhubarb").isPresent());
}
/**
* Test ModuleFinder.of with one directory of modules
*/
public void testOfOneDirectory() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
createExplodedModule(dir.resolve("m1"), "m1");
createModularJar(dir.resolve("m2.jar"), "m2");
ModuleFinder finder = ModuleFinder.of(dir);
assertTrue(finder.findAll().size() == 2);
assertTrue(finder.find("m1").isPresent());
assertTrue(finder.find("m2").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
}
/**
* Test ModuleFinder.of with two directories
*/
public void testOfTwoDirectories() throws Exception {
Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
createExplodedModule(dir1.resolve("m1"), "m1@1.0");
createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
createExplodedModule(dir2.resolve("m1"), "m1@2.0");
createModularJar(dir2.resolve("m2.jar"), "m2@2.0");
createExplodedModule(dir2.resolve("m3"), "m3");
createModularJar(dir2.resolve("m4.jar"), "m4");
ModuleFinder finder = ModuleFinder.of(dir1, dir2);
assertTrue(finder.findAll().size() == 4);
assertTrue(finder.find("m1").isPresent());
assertTrue(finder.find("m2").isPresent());
assertTrue(finder.find("m3").isPresent());
assertTrue(finder.find("m4").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
// check that m1@1.0 (and not m1@2.0) is found
ModuleDescriptor m1 = finder.find("m1").get().descriptor();
assertEquals(m1.version().get().toString(), "1.0");
// check that m2@1.0 (and not m2@2.0) is found
ModuleDescriptor m2 = finder.find("m2").get().descriptor();
assertEquals(m2.version().get().toString(), "1.0");
}
/**
* Test ModuleFinder.of with one JAR file
*/
public void testOfOneJarFile() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Path jar1 = createModularJar(dir.resolve("m1.jar"), "m1");
ModuleFinder finder = ModuleFinder.of(jar1);
assertTrue(finder.findAll().size() == 1);
assertTrue(finder.find("m1").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
}
/**
* Test ModuleFinder.of with two JAR files
*/
public void testOfTwoJarFiles() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Path jar1 = createModularJar(dir.resolve("m1.jar"), "m1");
Path jar2 = createModularJar(dir.resolve("m2.jar"), "m2");
ModuleFinder finder = ModuleFinder.of(jar1, jar2);
assertTrue(finder.findAll().size() == 2);
assertTrue(finder.find("m1").isPresent());
assertTrue(finder.find("m2").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
}
/**
* Test ModuleFinder.of with many JAR files
*/
public void testOfManyJarFiles() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Path jar1 = createModularJar(dir.resolve("m1@1.0.jar"), "m1@1.0");
Path jar2 = createModularJar(dir.resolve("m2@1.0.jar"), "m2");
Path jar3 = createModularJar(dir.resolve("m1@2.0.jar"), "m1@2.0"); // shadowed
Path jar4 = createModularJar(dir.resolve("m3@1.0.jar"), "m3");
ModuleFinder finder = ModuleFinder.of(jar1, jar2, jar3, jar4);
assertTrue(finder.findAll().size() == 3);
assertTrue(finder.find("m1").isPresent());
assertTrue(finder.find("m2").isPresent());
assertTrue(finder.find("m3").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
// check that m1@1.0 (and not m1@2.0) is found
ModuleDescriptor m1 = finder.find("m1").get().descriptor();
assertEquals(m1.version().get().toString(), "1.0");
}
/**
* Test ModuleFinder.of with one exploded module.
*/
public void testOfOneExplodedModule() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Path m1_dir = createExplodedModule(dir.resolve("m1"), "m1");
ModuleFinder finder = ModuleFinder.of(m1_dir);
assertTrue(finder.findAll().size() == 1);
assertTrue(finder.find("m1").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
}
/**
* Test ModuleFinder.of with two exploded modules.
*/
public void testOfTwoExplodedModules() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Path m1_dir = createExplodedModule(dir.resolve("m1"), "m1");
Path m2_dir = createExplodedModule(dir.resolve("m2"), "m2");
ModuleFinder finder = ModuleFinder.of(m1_dir, m2_dir);
assertTrue(finder.findAll().size() == 2);
assertTrue(finder.find("m1").isPresent());
assertTrue(finder.find("m2").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
}
/**
* Test ModuleFinder.of with a mix of module directories and JAR files.
*/
public void testOfMixDirectoriesAndJars() throws Exception {
// directory with m1@1.0 and m2@1.0
Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
createExplodedModule(dir1.resolve("m1"), "m1@1.0");
createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
// JAR files: m1@2.0, m2@2.0, m3@2.0, m4@2.0
Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
Path jar1 = createModularJar(dir2.resolve("m1.jar"), "m1@2.0");
Path jar2 = createModularJar(dir2.resolve("m2.jar"), "m2@2.0");
Path jar3 = createModularJar(dir2.resolve("m3.jar"), "m3@2.0");
Path jar4 = createModularJar(dir2.resolve("m4.jar"), "m4@2.0");
// directory with m3@3.0 and m4@3.0
Path dir3 = Files.createTempDirectory(USER_DIR, "mods3");
createExplodedModule(dir3.resolve("m3"), "m3@3.0");
createModularJar(dir3.resolve("m4.jar"), "m4@3.0");
// JAR files: m5 and m6
Path dir4 = Files.createTempDirectory(USER_DIR, "mods4");
Path jar5 = createModularJar(dir4.resolve("m5.jar"), "m5@4.0");
Path jar6 = createModularJar(dir4.resolve("m6.jar"), "m6@4.0");
ModuleFinder finder
= ModuleFinder.of(dir1, jar1, jar2, jar3, jar4, dir3, jar5, jar6);
assertTrue(finder.findAll().size() == 6);
assertTrue(finder.find("m1").isPresent());
assertTrue(finder.find("m2").isPresent());
assertTrue(finder.find("m3").isPresent());
assertTrue(finder.find("m4").isPresent());
assertTrue(finder.find("m5").isPresent());
assertTrue(finder.find("m6").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
// m1 and m2 should be located in dir1
ModuleDescriptor m1 = finder.find("m1").get().descriptor();
assertEquals(m1.version().get().toString(), "1.0");
ModuleDescriptor m2 = finder.find("m2").get().descriptor();
assertEquals(m2.version().get().toString(), "1.0");
// m3 and m4 should be located in JAR files
ModuleDescriptor m3 = finder.find("m3").get().descriptor();
assertEquals(m3.version().get().toString(), "2.0");
ModuleDescriptor m4 = finder.find("m4").get().descriptor();
assertEquals(m4.version().get().toString(), "2.0");
// m5 and m6 should be located in JAR files
ModuleDescriptor m5 = finder.find("m5").get().descriptor();
assertEquals(m5.version().get().toString(), "4.0");
ModuleDescriptor m6 = finder.find("m6").get().descriptor();
assertEquals(m6.version().get().toString(), "4.0");
}
/**
* Test ModuleFinder.of with a mix of module directories and exploded
* modules.
*/
public void testOfMixDirectoriesAndExplodedModules() throws Exception {
// directory with m1@1.0 and m2@1.0
Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
createExplodedModule(dir1.resolve("m1"), "m1@1.0");
createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
// exploded modules: m1@2.0, m2@2.0, m3@2.0, m4@2.0
Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
Path m1_dir = createExplodedModule(dir2.resolve("m1"), "m1@2.0");
Path m2_dir = createExplodedModule(dir2.resolve("m2"), "m2@2.0");
Path m3_dir = createExplodedModule(dir2.resolve("m3"), "m3@2.0");
Path m4_dir = createExplodedModule(dir2.resolve("m4"), "m4@2.0");
ModuleFinder finder = ModuleFinder.of(dir1, m1_dir, m2_dir, m3_dir, m4_dir);
assertTrue(finder.findAll().size() == 4);
assertTrue(finder.find("m1").isPresent());
assertTrue(finder.find("m2").isPresent());
assertTrue(finder.find("m3").isPresent());
assertTrue(finder.find("m4").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
// m1 and m2 should be located in dir1
ModuleDescriptor m1 = finder.find("m1").get().descriptor();
assertEquals(m1.version().get().toString(), "1.0");
ModuleDescriptor m2 = finder.find("m2").get().descriptor();
assertEquals(m2.version().get().toString(), "1.0");
// m3 and m4 should be located in dir2
ModuleDescriptor m3 = finder.find("m3").get().descriptor();
assertEquals(m3.version().get().toString(), "2.0");
ModuleDescriptor m4 = finder.find("m4").get().descriptor();
assertEquals(m4.version().get().toString(), "2.0");
}
/**
* Test ModuleFinder with a JAR file containing a mix of class and
* non-class resources.
*/
public void testOfOneJarFileWithResources() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Path jar = createModularJar(dir.resolve("m.jar"), "m",
"LICENSE",
"README",
"WEB-INF/tags",
"p/Type.class",
"p/resources/m.properties",
"q-/Type.class", // not a legal package name
"q-/resources/m/properties");
ModuleFinder finder = ModuleFinder.of(jar);
Optional<ModuleReference> mref = finder.find("m");
assertTrue(mref.isPresent(), "m1 not found");
ModuleDescriptor descriptor = mref.get().descriptor();
assertTrue(descriptor.packages().size() == 2);
assertTrue(descriptor.packages().contains("p"));
assertTrue(descriptor.packages().contains("p.resources"));
}
/**
* Test ModuleFinder with an exploded module containing a mix of class
* and non-class resources
*/
public void testOfOneExplodedModuleWithResources() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Path m_dir = createExplodedModule(dir.resolve("m"), "m",
"LICENSE",
"README",
"WEB-INF/tags",
"p/Type.class",
"p/resources/m.properties",
"q-/Type.class", // not a legal package name
"q-/resources/m/properties");
ModuleFinder finder = ModuleFinder.of(m_dir);
Optional<ModuleReference> mref = finder.find("m");
assertTrue(mref.isPresent(), "m not found");
ModuleDescriptor descriptor = mref.get().descriptor();
assertTrue(descriptor.packages().size() == 2);
assertTrue(descriptor.packages().contains("p"));
assertTrue(descriptor.packages().contains("p.resources"));
}
/**
* Test ModuleFinder with a JAR file containing a .class file in the top
* level directory.
*/
public void testOfOneJarFileWithTopLevelClass() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Path jar = createModularJar(dir.resolve("m.jar"), "m", "Mojo.class");
ModuleFinder finder = ModuleFinder.of(jar);
try {
finder.find("m");
assertTrue(false);
} catch (FindException e) {
assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
assertTrue(e.getCause().getMessage().contains("Mojo.class"));
}
finder = ModuleFinder.of(jar);
try {
finder.findAll();
assertTrue(false);
} catch (FindException e) {
assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
assertTrue(e.getCause().getMessage().contains("Mojo.class"));
}
}
/**
* Test ModuleFinder with a JAR file containing a .class file in the top
* level directory.
*/
public void testOfOneExplodedModuleWithTopLevelClass() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Path m_dir = createExplodedModule(dir.resolve("m"), "m", "Mojo.class");
ModuleFinder finder = ModuleFinder.of(m_dir);
try {
finder.find("m");
assertTrue(false);
} catch (FindException e) {
assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
assertTrue(e.getCause().getMessage().contains("Mojo.class"));
}
finder = ModuleFinder.of(m_dir);
try {
finder.findAll();
assertTrue(false);
} catch (FindException e) {
assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
assertTrue(e.getCause().getMessage().contains("Mojo.class"));
}
}
/**
* Test ModuleFinder.of with a path to a file that does not exist.
*/
public void testOfWithDoesNotExistEntry() throws Exception {
Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
createModularJar(dir2.resolve("m2.jar"), "m2@1.0");
Files.delete(dir1);
ModuleFinder finder = ModuleFinder.of(dir1, dir2);
assertTrue(finder.find("m2").isPresent());
assertTrue(finder.findAll().size() == 1);
assertFalse(finder.find("java.rhubarb").isPresent());
}
/**
* Test ModuleFinder.of with a file path to an unrecognized file type.
*/
public void testOfWithUnrecognizedEntry() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Path mod = Files.createTempFile(dir, "m", ".junk");
ModuleFinder finder = ModuleFinder.of(mod);
try {
finder.find("java.rhubarb");
assertTrue(false);
} catch (FindException e) {
// expected
}
finder = ModuleFinder.of(mod);
try {
finder.findAll();
assertTrue(false);
} catch (FindException e) {
// expected
}
}
/**
* Test ModuleFinder.of with a file path to a directory containing a file
* that will not be recognized as a module.
*/
public void testOfWithUnrecognizedEntryInDirectory1() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
Files.createTempFile(dir, "m", ".junk");
ModuleFinder finder = ModuleFinder.of(dir);
assertFalse(finder.find("java.rhubarb").isPresent());
finder = ModuleFinder.of(dir);
assertTrue(finder.findAll().isEmpty());
}
/**
* Test ModuleFinder.of with a file path to a directory containing a file
* that will not be recognized as a module.
*/
public void testOfWithUnrecognizedEntryInDirectory2() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
createModularJar(dir.resolve("m1.jar"), "m1");
Files.createTempFile(dir, "m2", ".junk");
ModuleFinder finder = ModuleFinder.of(dir);
assertTrue(finder.find("m1").isPresent());
assertFalse(finder.find("m2").isPresent());
finder = ModuleFinder.of(dir);
assertTrue(finder.findAll().size() == 1);
}
/**
* Test ModuleFinder.of with a directory that contains two
* versions of the same module
*/
public void testOfDuplicateModulesInDirectory() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
createModularJar(dir.resolve("m1@1.0.jar"), "m1");
createModularJar(dir.resolve("m1@2.0.jar"), "m1");
ModuleFinder finder = ModuleFinder.of(dir);
try {
finder.find("m1");
assertTrue(false);
} catch (FindException expected) { }
finder = ModuleFinder.of(dir);
try {
finder.findAll();
assertTrue(false);
} catch (FindException expected) { }
}
/**
* Test ModuleFinder.of with a directory containing hidden files
*/
public void testOfWithHiddenFiles() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
createExplodedModule(dir.resolve("m"), "m",
"com/.ignore",
"com/foo/.ignore",
"com/foo/foo.properties");
ModuleFinder finder = ModuleFinder.of(dir);
ModuleReference mref = finder.find("m").orElse(null);
assertNotNull(mref);
Set<String> expectedPackages;
if (System.getProperty("os.name").startsWith("Windows")) {
expectedPackages = Set.of("com", "com.foo");
} else {
expectedPackages = Set.of("com.foo");
}
assertEquals(mref.descriptor().packages(), expectedPackages);
}
/**
* Test ModuleFinder.of with a truncated module-info.class
*/
public void testOfWithTruncatedModuleInfo() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
// create an empty <dir>/rhubarb/module-info.class
Path subdir = Files.createDirectory(dir.resolve("rhubarb"));
Files.createFile(subdir.resolve("module-info.class"));
ModuleFinder finder = ModuleFinder.of(dir);
try {
finder.find("rhubarb");
assertTrue(false);
} catch (FindException e) {
assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
}
finder = ModuleFinder.of(dir);
try {
finder.findAll();
assertTrue(false);
} catch (FindException e) {
assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
}
}
/**
* Test ModuleFinder.compose with no module finders
*/
public void testComposeOfNone() throws Exception {
ModuleFinder finder = ModuleFinder.of();
assertTrue(finder.findAll().isEmpty());
assertFalse(finder.find("java.rhubarb").isPresent());
}
/**
* Test ModuleFinder.compose with one module finder
*/
public void testComposeOfOne() throws Exception {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
createModularJar(dir.resolve("m1.jar"), "m1");
createModularJar(dir.resolve("m2.jar"), "m2");
ModuleFinder finder1 = ModuleFinder.of(dir);
ModuleFinder finder = ModuleFinder.compose(finder1);
assertTrue(finder.findAll().size() == 2);
assertTrue(finder.find("m1").isPresent());
assertTrue(finder.find("m2").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
}
/**
* Test ModuleFinder.compose with two module finders
*/
public void testComposeOfTwo() throws Exception {
Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
createModularJar(dir1.resolve("m1.jar"), "m1@1.0");
createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
createModularJar(dir2.resolve("m1.jar"), "m1@2.0");
createModularJar(dir2.resolve("m2.jar"), "m2@2.0");
createModularJar(dir2.resolve("m3.jar"), "m3");
createModularJar(dir2.resolve("m4.jar"), "m4");
ModuleFinder finder1 = ModuleFinder.of(dir1);
ModuleFinder finder2 = ModuleFinder.of(dir2);
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
assertTrue(finder.findAll().size() == 4);
assertTrue(finder.find("m1").isPresent());
assertTrue(finder.find("m2").isPresent());
assertTrue(finder.find("m3").isPresent());
assertTrue(finder.find("m4").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
// check that m1@1.0 is found
ModuleDescriptor m1 = finder.find("m1").get().descriptor();
assertEquals(m1.version().get().toString(), "1.0");
// check that m2@1.0 is found
ModuleDescriptor m2 = finder.find("m2").get().descriptor();
assertEquals(m2.version().get().toString(), "1.0");
}
/**
* Test ModuleFinder.compose with three module finders
*/
public void testComposeOfThree() throws Exception {
Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
createModularJar(dir1.resolve("m1.jar"), "m1@1.0");
createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
createModularJar(dir2.resolve("m1.jar"), "m1@2.0");
createModularJar(dir2.resolve("m2.jar"), "m2@2.0");
createModularJar(dir2.resolve("m3.jar"), "m3@2.0");
createModularJar(dir2.resolve("m4.jar"), "m4@2.0");
Path dir3 = Files.createTempDirectory(USER_DIR, "mods3");
createModularJar(dir3.resolve("m3.jar"), "m3@3.0");
createModularJar(dir3.resolve("m4.jar"), "m4@3.0");
createModularJar(dir3.resolve("m5.jar"), "m5");
createModularJar(dir3.resolve("m6.jar"), "m6");
ModuleFinder finder1 = ModuleFinder.of(dir1);
ModuleFinder finder2 = ModuleFinder.of(dir2);
ModuleFinder finder3 = ModuleFinder.of(dir3);
ModuleFinder finder = ModuleFinder.compose(finder1, finder2, finder3);
assertTrue(finder.findAll().size() == 6);
assertTrue(finder.find("m1").isPresent());
assertTrue(finder.find("m2").isPresent());
assertTrue(finder.find("m3").isPresent());
assertTrue(finder.find("m4").isPresent());
assertTrue(finder.find("m5").isPresent());
assertTrue(finder.find("m6").isPresent());
assertFalse(finder.find("java.rhubarb").isPresent());
// check that m1@1.0 is found
ModuleDescriptor m1 = finder.find("m1").get().descriptor();
assertEquals(m1.version().get().toString(), "1.0");
// check that m2@1.0 is found
ModuleDescriptor m2 = finder.find("m2").get().descriptor();
assertEquals(m2.version().get().toString(), "1.0");
// check that m3@2.0 is found
ModuleDescriptor m3 = finder.find("m3").get().descriptor();
assertEquals(m3.version().get().toString(), "2.0");
// check that m4@2.0 is found
ModuleDescriptor m4 = finder.find("m4").get().descriptor();
assertEquals(m4.version().get().toString(), "2.0");
}
/**
* Test null handling
*/
public void testNulls() {
// ofSystem
try {
ModuleFinder.ofSystem().find(null);
assertTrue(false);
} catch (NullPointerException expected) { }
// of
Path dir = Paths.get("d");
try {
ModuleFinder.of().find(null);
assertTrue(false);
} catch (NullPointerException expected) { }
try {
ModuleFinder.of((Path)null);
assertTrue(false);
} catch (NullPointerException expected) { }
try {
ModuleFinder.of((Path[])null);
assertTrue(false);
} catch (NullPointerException expected) { }
try {
ModuleFinder.of(dir, null);
assertTrue(false);
} catch (NullPointerException expected) { }
try {
ModuleFinder.of(null, dir);
assertTrue(false);
} catch (NullPointerException expected) { }
// compose
ModuleFinder finder = ModuleFinder.of();
try {
ModuleFinder.compose((ModuleFinder)null);
assertTrue(false);
} catch (NullPointerException expected) { }
try {
ModuleFinder.compose((ModuleFinder[])null);
assertTrue(false);
} catch (NullPointerException expected) { }
try {
ModuleFinder.compose(finder, null);
assertTrue(false);
} catch (NullPointerException expected) { }
try {
ModuleFinder.compose(null, finder);
assertTrue(false);
} catch (NullPointerException expected) { }
}
/**
* Parses a string of the form {@code name[@version]} and returns a
* ModuleDescriptor with that name and version. The ModuleDescriptor
* will have a requires on java.base.
*/
static ModuleDescriptor newModuleDescriptor(String mid) {
String mn;
String vs;
int i = mid.indexOf("@");
if (i == -1) {
mn = mid;
vs = null;
} else {
mn = mid.substring(0, i);
vs = mid.substring(i+1);
}
ModuleDescriptor.Builder builder
= ModuleDescriptor.newModule(mn).requires("java.base");
if (vs != null)
builder.version(vs);
return builder.build();
}
/**
* Creates an exploded module in the given directory and containing a
* module descriptor with the given module name/version.
*/
static Path createExplodedModule(Path dir, String mid, String... entries)
throws Exception
{
ModuleDescriptor descriptor = newModuleDescriptor(mid);
Files.createDirectories(dir);
Path mi = dir.resolve("module-info.class");
try (OutputStream out = Files.newOutputStream(mi)) {
ModuleInfoWriter.write(descriptor, out);
}
for (String entry : entries) {
Path file = dir.resolve(entry.replace('/', File.separatorChar));
Files.createDirectories(file.getParent());
Files.createFile(file);
}
return dir;
}
/**
* Creates a JAR file with the given file path and containing a module
* descriptor with the given module name/version.
*/
static Path createModularJar(Path file, String mid, String ... entries)
throws Exception
{
ModuleDescriptor descriptor = newModuleDescriptor(mid);
try (OutputStream out = Files.newOutputStream(file)) {
try (JarOutputStream jos = new JarOutputStream(out)) {
JarEntry je = new JarEntry("module-info.class");
jos.putNextEntry(je);
ModuleInfoWriter.write(descriptor, jos);
jos.closeEntry();
for (String entry : entries) {
je = new JarEntry(entry);
jos.putNextEntry(je);
jos.closeEntry();
}
}
}
return file;
}
}

View file

@ -0,0 +1,264 @@
/*
* Copyright (c) 2016, 2024, 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
* @modules java.base/jdk.internal.access
* java.base/jdk.internal.module
* @library /test/lib
* @build jdk.test.lib.util.ModuleInfoWriter
* @run testng ModuleNamesTest
* @summary Basic test of reading a module-info.class with module names that
* are legal in class files but not legal in the Java Language
*/
import java.io.ByteArrayOutputStream;
import java.lang.module.InvalidModuleDescriptorException;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.Builder;
import java.lang.module.ModuleDescriptor.Exports;
import java.lang.module.ModuleDescriptor.Opens;
import java.lang.module.ModuleDescriptor.Requires;
import java.nio.ByteBuffer;
import java.util.Optional;
import java.util.Set;
import jdk.internal.access.SharedSecrets;
import jdk.test.lib.util.ModuleInfoWriter;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@Test
public class ModuleNamesTest {
@DataProvider(name = "legalModuleNames")
public Object[][] legalModuleNames() {
return new Object[][] {
{ ".", "." },
{ ".foo", ".foo" },
{ "foo.", "foo." },
{ "foo.bar", "foo.bar" },
{ "..", ".." },
{ "..foo", "..foo" },
{ "foo..", "foo.." },
{ "foo..bar", "foo..bar" },
{ "[", "[" },
{ "[foo", "[foo" },
{ "foo[", "foo[" },
{ "foo[bar", "foo[bar" },
{ ";", ";" },
{ ";foo", ";foo" },
{ "foo;", "foo;" },
{ "foo;bar", "foo;bar" },
{ "\\\\", "\\" },
{ "\\\\foo", "\\foo" },
{ "foo\\\\", "foo\\" },
{ "foo\\\\bar", "foo\\bar" },
{ "\\\\\\\\", "\\\\" },
{ "\\\\\\\\foo", "\\\\foo" },
{ "foo\\\\\\\\", "foo\\\\" },
{ "foo\\\\\\\\bar", "foo\\\\bar" },
{ "\\:", ":" },
{ "\\:foo", ":foo" },
{ "foo\\:", "foo:" },
{ "foo\\:bar", "foo:bar" },
{ "\\:\\:", "::" },
{ "\\:\\:foo", "::foo" },
{ "foo\\:\\:", "foo::" },
{ "foo\\:\\:bar", "foo::bar" },
{ "\\@", "@" },
{ "\\@foo", "@foo" },
{ "foo\\@", "foo@" },
{ "foo\\@bar", "foo@bar" },
{ "\\@\\@", "@@" },
{ "\\@\\@foo", "@@foo" },
{ "foo\\@\\@", "foo@@" },
{ "foo\\@\\@bar", "foo@@bar" },
{ makeString("", 0x20, ""), " " },
{ makeString("foo", 0x20, ""), "foo " },
{ makeString("", 0x20, "foo"), " foo" },
{ makeString("foo", 0x20, "bar"), "foo bar" },
};
}
@DataProvider(name = "illegalModuleNames")
public Object[][] illegalModuleNames() {
return new Object[][] {
{ "", null },
{ ":", null },
{ ":foo", null },
{ "foo:", null },
{ "foo:bar", null },
{ "@", null },
{ "@foo", null },
{ "foo@", null },
{ "foo@bar", null },
{ "\\", null },
{ "\\foo", null },
{ "foo\\", null },
{ "foo\\bar", null },
{ makeString("", 0x00, ""), null },
{ makeString("", 0x00, "foo"), null },
{ makeString("foo", 0x00, ""), null },
{ makeString("foo", 0x00, "bar"), null },
{ makeString("", 0x1f, ""), null },
{ makeString("", 0x1f, "foo"), null },
{ makeString("foo", 0x1f, ""), null },
{ makeString("foo", 0x1f, "bar"), null },
};
}
@Test(dataProvider = "legalModuleNames")
public void testLegalModuleName(String mn, String expected) throws Exception {
ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
ByteBuffer bb = toBuffer(md);
String name = ModuleDescriptor.read(bb).name();
assertEquals(name, expected);
}
@Test(dataProvider = "illegalModuleNames",
expectedExceptions = InvalidModuleDescriptorException.class)
public void testIllegalModuleName(String mn, String ignore) throws Exception {
ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
ByteBuffer bb = toBuffer(md);
ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
}
@Test(dataProvider = "legalModuleNames")
public void testLegalRequires(String mn, String expected) throws Exception {
ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
ByteBuffer bb = toBuffer(md);
ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
Optional<Requires> requires = descriptor.requires().stream()
.filter(r -> !r.name().equals("java.base"))
.findAny();
assertTrue(requires.isPresent());
assertEquals(requires.get().name(), expected);
}
@Test(dataProvider = "illegalModuleNames",
expectedExceptions = InvalidModuleDescriptorException.class)
public void testIllegalRequires(String mn, String ignore) throws Exception {
ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
ByteBuffer bb = toBuffer(md);
ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
}
@Test(dataProvider = "legalModuleNames")
public void testLegalExports(String mn, String expected) throws Exception {
ModuleDescriptor md = newBuilder("m")
.requires("java.base")
.exports("p", Set.of(mn))
.build();
ByteBuffer bb = toBuffer(md);
ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
Optional<Exports> export = descriptor.exports().stream().findAny();
assertTrue(export.isPresent());
assertTrue(export.get().targets().contains(expected));
}
@Test(dataProvider = "illegalModuleNames",
expectedExceptions = InvalidModuleDescriptorException.class)
public void testIllegalExports(String mn, String ignore) throws Exception {
ModuleDescriptor md = newBuilder("m")
.requires("java.base")
.exports("p", Set.of(mn))
.build();
ByteBuffer bb = toBuffer(md);
ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
}
@Test(dataProvider = "legalModuleNames")
public void testLegalOpens(String mn, String expected) throws Exception {
ModuleDescriptor md = newBuilder("m")
.requires("java.base")
.opens("p", Set.of(mn))
.build();
ByteBuffer bb = toBuffer(md);
ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
Optional<Opens> opens = descriptor.opens().stream().findAny();
assertTrue(opens.isPresent());
assertTrue(opens.get().targets().contains(expected));
}
@Test(dataProvider = "illegalModuleNames",
expectedExceptions = InvalidModuleDescriptorException.class)
public void testIllegalOpens(String mn, String ignore) throws Exception {
ModuleDescriptor md = newBuilder("m")
.requires("java.base")
.opens("p", Set.of(mn))
.build();
ByteBuffer bb = toBuffer(md);
ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
}
/**
* Returns a Builder that does not validate module names.
*/
private Builder newBuilder(String mn) {
return SharedSecrets.getJavaLangModuleAccess()
.newModuleBuilder(mn, false, Set.of());
}
/**
* Returns a {@code ByteBuffer} containing the given module descriptor
* in module-info.class format.
*/
private ByteBuffer toBuffer(ModuleDescriptor descriptor) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ModuleInfoWriter.write(descriptor, baos);
return ByteBuffer.wrap(baos.toByteArray());
}
/**
* Returns a string containing a given code point.
*/
private String makeString(String prefix, int codePoint, String suffix) {
StringBuilder sb = new StringBuilder();
sb.append(prefix);
sb.appendCodePoint(codePoint);
sb.append(suffix);
return sb.toString();
}
}

View file

@ -0,0 +1,391 @@
/*
* Copyright (c) 2015, 2026, 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
* @bug 8142968 8300228
* @library /test/lib
* @modules java.base/jdk.internal.module
* jdk.compiler
* jdk.jlink
* @build ModuleReaderTest
* jdk.test.lib.compiler.CompilerUtils
* jdk.test.lib.util.JarUtils
* @run junit ModuleReaderTest
* @summary Basic tests for java.lang.module.ModuleReader
*/
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.spi.ToolProvider;
import java.util.stream.Stream;
import jdk.internal.module.ModulePath;
import jdk.test.lib.compiler.CompilerUtils;
import jdk.test.lib.util.JarUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ModuleReaderTest {
private static final String TEST_SRC = System.getProperty("test.src");
private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get("mods");
// the module name of the base module
private static final String BASE_MODULE = "java.base";
// the module name of the test module
private static final String TEST_MODULE = "m";
// resources in the base module
private static final String[] BASE_RESOURCES = {
"java/lang/Object.class"
};
// (directory) resources that may be in the base module
private static final String[] MAYBE_BASE_RESOURCES = {
"java",
"java/",
"java/lang",
"java/lang/",
};
// resource names that should not be found in the base module
private static final String[] NOT_BASE_RESOURCES = {
"NotFound",
"/java",
"//java",
"/java/lang",
"//java/lang",
"java//lang",
"/java/lang/Object.class",
"//java/lang/Object.class",
"java/lang/Object.class/",
"java//lang//Object.class",
"./java/lang/Object.class",
"java/./lang/Object.class",
"java/lang/./Object.class",
"../java/lang/Object.class",
"java/../lang/Object.class",
"java/lang/../Object.class",
// junk resource names
"java\u0000",
"C:java",
"C:\\java",
"java\\lang\\Object.class"
};
// resources in test module (can't use module-info.class as a test
// resource as it will be modified by the jmod tool)
private static final String[] TEST_RESOURCES = {
"p/Main.class"
};
// (directory) resources that may be in the test module
private static final String[] MAYBE_TEST_RESOURCES = {
"p",
"p/"
};
// resource names that should not be found in the test module
private static final String[] NOT_TEST_RESOURCES = {
"NotFound",
"/p",
"//p",
"/p/Main.class",
"//p/Main.class",
"p/Main.class/",
"p//Main.class",
"./p/Main.class",
"p/./Main.class",
"../p/Main.class",
"p/../p/Main.class",
// junk resource names
"p\u0000",
"C:p",
"C:\\p",
"p\\Main.class"
};
@BeforeAll
public static void compileTestModule() throws Exception {
// javac -d mods/$TESTMODULE src/$TESTMODULE/**
boolean compiled = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE),
MODS_DIR.resolve(TEST_MODULE));
assertTrue(compiled, "test module did not compile");
}
/**
* Test ModuleReader with module in runtime image.
*/
@Test
public void testImage() throws IOException {
ModuleFinder finder = ModuleFinder.ofSystem();
ModuleReference mref = finder.find(BASE_MODULE).get();
ModuleReader reader = mref.open();
try (reader) {
for (String name : BASE_RESOURCES) {
byte[] expectedBytes;
Module baseModule = Object.class.getModule();
try (InputStream in = baseModule.getResourceAsStream(name)) {
expectedBytes = in.readAllBytes();
}
testFind(reader, name, expectedBytes);
testOpen(reader, name, expectedBytes);
testRead(reader, name, expectedBytes);
testList(reader, name);
}
// test resources that may be in the base module
for (String name : MAYBE_BASE_RESOURCES) {
Optional<URI> ouri = reader.find(name);
ouri.ifPresent(uri -> {
if (name.endsWith("/"))
assertTrue(uri.toString().endsWith("/"),
"mismatched directory URI for '" + name + "': " + uri);
});
}
// test "not found" in java.base module
for (String name : NOT_BASE_RESOURCES) {
assertFalse(reader.find(name).isPresent(), "Unexpected resource found: " + name);
assertFalse(reader.open(name).isPresent(), "Unexpected resource opened: " + name);
assertFalse(reader.read(name).isPresent(), "Unexpected resource read: " + name);
}
// test nulls
assertThrows(NullPointerException.class, () -> reader.find(null));
assertThrows(NullPointerException.class, () -> reader.open(null));
assertThrows(NullPointerException.class, () -> reader.read(null));
assertThrows(NullPointerException.class, () -> reader.release(null));
}
// test closed ModuleReader
assertThrows(IOException.class, () -> reader.open(BASE_RESOURCES[0]));
assertThrows(IOException.class, () -> reader.read(BASE_RESOURCES[0]));
assertThrows(IOException.class, reader::list);
}
/**
* Test ModuleReader with exploded module.
*/
@Test
public void testExplodedModule() throws IOException {
test(MODS_DIR);
}
/**
* Test ModuleReader with module in modular JAR.
*/
@Test
public void testModularJar() throws IOException {
Path dir = Files.createTempDirectory(USER_DIR, "mlib");
// jar cf mlib/${TESTMODULE}.jar -C mods .
JarUtils.createJarFile(dir.resolve("m.jar"),
MODS_DIR.resolve(TEST_MODULE));
test(dir);
}
/**
* Test ModuleReader with module in a JMOD file.
*/
@Test
public void testJMod() throws IOException {
Path dir = Files.createTempDirectory(USER_DIR, "mlib");
// jmod create --class-path mods/${TESTMODULE} mlib/${TESTMODULE}.jmod
String cp = MODS_DIR.resolve(TEST_MODULE).toString();
String jmod = dir.resolve("m.jmod").toString();
String[] args = { "create", "--class-path", cp, jmod };
ToolProvider jmodTool = ToolProvider.findFirst("jmod")
.orElseThrow(() ->
new RuntimeException("jmod tool not found")
);
assertEquals(0, jmodTool.run(System.out, System.out, args), "jmod tool failed");
test(dir);
}
/**
* The test module is found on the given module path. Open a ModuleReader
* to the test module and test the reader.
*/
void test(Path mp) throws IOException {
ModuleFinder finder = ModulePath.of(Runtime.version(), true, mp);
ModuleReference mref = finder.find(TEST_MODULE).get();
ModuleReader reader = mref.open();
try (reader) {
// test resources in test module
for (String name : TEST_RESOURCES) {
System.out.println("resource: " + name);
byte[] expectedBytes
= Files.readAllBytes(MODS_DIR
.resolve(TEST_MODULE)
.resolve(name.replace('/', File.separatorChar)));
testFind(reader, name, expectedBytes);
testOpen(reader, name, expectedBytes);
testRead(reader, name, expectedBytes);
testList(reader, name);
}
// test resources that may be in the test module
for (String name : MAYBE_TEST_RESOURCES) {
System.out.println("resource: " + name);
Optional<URI> ouri = reader.find(name);
ouri.ifPresent(uri -> {
if (name.endsWith("/"))
assertTrue(uri.toString().endsWith("/"),
"mismatched directory URI for '" + name + "': " + uri);
});
}
// test "not found" in test module
for (String name : NOT_TEST_RESOURCES) {
System.out.println("resource: " + name);
assertFalse(reader.find(name).isPresent(), "Unexpected resource found: " + name);
assertFalse(reader.open(name).isPresent(), "Unexpected resource open: " + name);
assertFalse(reader.read(name).isPresent(), "Unexpected resource read: " + name);
}
// test nulls
assertThrows(NullPointerException.class, () -> reader.find(null));
assertThrows(NullPointerException.class, () -> reader.open(null));
assertThrows(NullPointerException.class, () -> reader.read(null));
assertThrows(NullPointerException.class, () -> reader.release(null));
}
// test closed ModuleReader
assertThrows(IOException.class, () -> reader.open(BASE_RESOURCES[0]));
assertThrows(IOException.class, () -> reader.read(BASE_RESOURCES[0]));
assertThrows(IOException.class, reader::list);
}
/**
* Test ModuleReader#find
*/
void testFind(ModuleReader reader, String name, byte[] expectedBytes)
throws IOException
{
Optional<URI> ouri = reader.find(name);
assertTrue(ouri.isPresent(), "missing URI for: " + name);
URL url = ouri.get().toURL();
if (!url.getProtocol().equalsIgnoreCase("jmod")) {
URLConnection uc = url.openConnection();
uc.setUseCaches(false);
try (InputStream in = uc.getInputStream()) {
byte[] bytes = in.readAllBytes();
assertArrayEquals(expectedBytes, bytes, "resource bytes differ for: " + name);
}
}
}
/**
* Test ModuleReader#open
*/
void testOpen(ModuleReader reader, String name, byte[] expectedBytes)
throws IOException
{
Optional<InputStream> oin = reader.open(name);
assertTrue(oin.isPresent(), "missing input stream for: " + name);
try (InputStream in = oin.get()) {
byte[] bytes = in.readAllBytes();
assertArrayEquals(expectedBytes, bytes, "resource bytes differ for: " + name);
}
}
/**
* Test ModuleReader#read
*/
void testRead(ModuleReader reader, String name, byte[] expectedBytes)
throws IOException
{
Optional<ByteBuffer> obb = reader.read(name);
assertTrue(obb.isPresent());
ByteBuffer bb = obb.get();
try {
int rem = bb.remaining();
assertEquals(expectedBytes.length, rem, "resource lengths differ: " + name);
byte[] bytes = new byte[rem];
bb.get(bytes);
assertArrayEquals(expectedBytes, bytes, "resource bytes differ: " + name);
} finally {
reader.release(bb);
}
}
/**
* Test ModuleReader#list
*/
void testList(ModuleReader reader, String name) throws IOException {
final List<String> list;
try (Stream<String> stream = reader.list()) {
list = stream.toList();
}
Set<String> names = new HashSet<>(list);
assertEquals(names.size(), list.size(), "resource list contains duplicates: " + list);
assertTrue(names.contains("module-info.class"), "resource list did not contain 'module-info.class': " + list);
assertTrue(names.contains(name), "resource list did not contain '" + name + "'" + list);
// all resources should be locatable via find
for (String e : names) {
assertTrue(reader.find(e).isPresent(), "resource not found: " + name);
}
}
}

View file

@ -0,0 +1,132 @@
/*
* Copyright (c) 2025, 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.
*/
import java.io.IOException;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
import java.net.URI;
import java.util.Optional;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
/*
* @test
* @bug 8372787
* @summary Test the behaviour of ModuleReader when using --patch-module
* @comment patch the java.base module with a test specific resource
* @compile/module=java.base java/lang/PatchedFoo.java
* @run junit/othervm ${test.main.class}
*/
class PatchedModuleReaderTest {
private static ModuleReference patchedModuleRef;
@BeforeAll
static void beforeAll() {
patchedModuleRef = ModuleFinder.ofSystem()
.find("java.base")
.orElseThrow();
}
/*
* Verifies that the resource that was patched into a module
* is found by the ModuleReader.
*/
@Test
void testResourceFound() throws Exception {
try (ModuleReader reader = patchedModuleRef.open()) {
String resourceName = "java/lang/PatchedFoo.class";
Optional<URI> res = reader.find(resourceName);
assertTrue(res.isPresent(), resourceName + " is missing in "
+ patchedModuleRef.descriptor().name() + " module");
URI uri = res.get();
assertEquals("file", uri.getScheme(),
"unexpected scheme in resource URI " + uri);
assertTrue(uri.getPath().endsWith(resourceName),
"unexpected path component " + uri.getPath()
+ " in resource URI " + uri);
}
}
/*
* Verifies the ModuleReader against a resource which isn't
* expected to be part of the patched module.
*/
@Test
void testResourceNotFound() throws Exception {
try (ModuleReader reader = patchedModuleRef.open()) {
String nonExistentResource = "foo/bar/NonExistent.class";
Optional<URI> res = reader.find(nonExistentResource);
assertTrue(res.isEmpty(), "unexpected resource " + nonExistentResource
+ " in " + patchedModuleRef.descriptor().name() + " module");
}
}
/*
* This test opens a ModuleReader for a patched module, accumulates
* the Stream of resources from that ModuleReader and then closes that
* ModuleReader. It then verifies that the closed ModuleReader
* throws the specified IOException whenever it is used for subsequent
* operations on the Stream of resources.
*/
@Test
void testIOExceptionAfterClose() throws Exception {
ModuleReader reader;
Stream<String> resources;
try (var _ = reader = patchedModuleRef.open()) {
// hold on to the available resources, to test them after the
// ModuleReader is closed
resources = reader.list();
} // close the ModuleReader
// verify IOException is thrown by the closed ModuleReader
assertThrows(IOException.class, () -> reader.list(),
"ModuleReader.list()");
resources.forEach(rn -> {
assertThrows(IOException.class, () -> reader.read(rn),
"ModuleReader.read(String)");
assertThrows(IOException.class, () -> reader.open(rn),
"ModuleReader.open(String)");
assertThrows(IOException.class, () -> reader.find(rn),
"ModuleReader.find(String)");
});
// repeat the test for a non-existent resource
String nonExistentResource = "foo/bar/NonExistent.class";
assertThrows(IOException.class, () -> reader.read(nonExistentResource),
"ModuleReader.read(String)");
assertThrows(IOException.class, () -> reader.open(nonExistentResource),
"ModuleReader.open(String)");
assertThrows(IOException.class, () -> reader.find(nonExistentResource),
"ModuleReader.find(String)");
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2025, 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.
*/
package java.lang;
public class PatchedFoo {
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2015, 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.
*/
module m {
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2015, 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.
*/
package p;
/**
* Main class for dummy module.
*/
public class Main {
public static void main(String[] args) {
}
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2014, 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
* @run testng ModuleReferenceTest
* @summary Basic tests for java.lang.module.ModuleReference
*/
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
import java.net.URI;
import java.util.Set;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@Test
public class ModuleReferenceTest {
private ModuleReference newModuleReference(ModuleDescriptor descriptor, URI uri) {
return new ModuleReference(descriptor, uri) {
@Override
public ModuleReader open() {
throw new UnsupportedOperationException();
}
};
}
public void testBasic() throws Exception {
ModuleDescriptor descriptor
= ModuleDescriptor.newModule("m")
.exports("p")
.exports("q")
.packages(Set.of("p.internal"))
.build();
URI uri = URI.create("module:/m");
ModuleReference mref = newModuleReference(descriptor, uri);
assertTrue(mref.descriptor().equals(descriptor));
assertTrue(mref.location().get().equals(uri));
}
@Test(expectedExceptions = { NullPointerException.class })
public void testNullDescriptor() throws Exception {
URI location = URI.create("module:/m");
newModuleReference(null, location);
}
public void testNullLocation() {
ModuleDescriptor descriptor
= ModuleDescriptor.newModule("m")
.exports("p")
.build();
ModuleReference mref = newModuleReference(descriptor, null);
assertTrue(!mref.location().isPresent());
}
}

View file

@ -0,0 +1,339 @@
/*
* Copyright (c) 2016, 2024, 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
* @modules java.base/jdk.internal.module
* @library /test/lib
* @build MultiReleaseJarTest
* jdk.test.lib.util.JarUtils
* jdk.test.lib.util.ModuleInfoWriter
* @run testng MultiReleaseJarTest
* @run testng/othervm -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarTest
* @summary Basic test of modular JARs as multi-release JARs
*/
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
import java.net.URI;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import jdk.test.lib.util.ModuleInfoWriter;
import jdk.test.lib.util.JarUtils;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@Test
public class MultiReleaseJarTest {
private static final String MODULE_INFO = "module-info.class";
private static final int VERSION = Runtime.version().major();
// are multi-release JARs enabled?
private static final boolean MULTI_RELEASE;
static {
String s = System.getProperty("jdk.util.jar.enableMultiRelease");
MULTI_RELEASE = (s == null || Boolean.parseBoolean(s));
}
/**
* Basic test of a multi-release JAR.
*/
public void testBasic() throws Exception {
String name = "m1";
ModuleDescriptor descriptor = ModuleDescriptor.newModule(name)
.requires("java.base")
.build();
Path jar = new JarBuilder(name)
.moduleInfo("module-info.class", descriptor)
.resource("p/Main.class")
.resource("p/Helper.class")
.resource("META-INF/versions/" + VERSION + "/p/Helper.class")
.resource("META-INF/versions/" + VERSION + "/p/internal/Helper.class")
.build();
// find the module
ModuleFinder finder = ModuleFinder.of(jar);
Optional<ModuleReference> omref = finder.find(name);
assertTrue((omref.isPresent()));
ModuleReference mref = omref.get();
// check module packages
descriptor = mref.descriptor();
Set<String> packages = descriptor.packages();
assertTrue(packages.contains("p"));
if (MULTI_RELEASE) {
assertTrue(packages.size() == 2);
assertTrue(packages.contains("p.internal"));
} else {
assertTrue(packages.size() == 1);
}
}
/**
* Test a multi-release JAR with a module-info.class in the versioned
* section of the JAR.
*/
public void testModuleInfoInVersionedSection() throws Exception {
String name = "m1";
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule(name)
.requires("java.base")
.build();
// module descriptor for versioned section
ModuleDescriptor descriptor2 = ModuleDescriptor.newModule(name)
.requires("java.base")
.requires("jdk.unsupported")
.build();
Path jar = new JarBuilder(name)
.moduleInfo(MODULE_INFO, descriptor1)
.resource("p/Main.class")
.resource("p/Helper.class")
.moduleInfo("META-INF/versions/" + VERSION + "/" + MODULE_INFO, descriptor2)
.resource("META-INF/versions/" + VERSION + "/p/Helper.class")
.resource("META-INF/versions/" + VERSION + "/p/internal/Helper.class")
.build();
// find the module
ModuleFinder finder = ModuleFinder.of(jar);
Optional<ModuleReference> omref = finder.find(name);
assertTrue((omref.isPresent()));
ModuleReference mref = omref.get();
// ensure that the right module-info.class is loaded
ModuleDescriptor descriptor = mref.descriptor();
assertEquals(descriptor.name(), name);
if (MULTI_RELEASE) {
assertEquals(descriptor.requires(), descriptor2.requires());
} else {
assertEquals(descriptor.requires(), descriptor1.requires());
}
}
/**
* Test multi-release JAR as an automatic module.
*/
public void testAutomaticModule() throws Exception {
String name = "m";
Path jar = new JarBuilder(name)
.resource("p/Main.class")
.resource("p/Helper.class")
.resource("META-INF/versions/" + VERSION + "/p/Helper.class")
.resource("META-INF/versions/" + VERSION + "/p/internal/Helper.class")
.build();
// find the module
ModuleFinder finder = ModuleFinder.of(jar);
Optional<ModuleReference> omref = finder.find(name);
assertTrue((omref.isPresent()));
ModuleReference mref = omref.get();
// check module packages
ModuleDescriptor descriptor = mref.descriptor();
Set<String> packages = descriptor.packages();
if (MULTI_RELEASE) {
assertTrue(packages.size() == 2);
assertTrue(packages.contains("p.internal"));
} else {
assertTrue(packages.size() == 1);
}
}
/**
* Exercise ModuleReader on a multi-release JAR
*/
public void testModuleReader() throws Exception {
String name = "m1";
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule(name)
.requires("java.base")
.build();
// module descriptor for versioned section
ModuleDescriptor descriptor2 = ModuleDescriptor.newModule(name)
.requires("java.base")
.requires("jdk.unsupported")
.build();
Path jar = new JarBuilder(name)
.moduleInfo(MODULE_INFO, descriptor1)
.moduleInfo("META-INF/versions/" + VERSION + "/" + MODULE_INFO, descriptor2)
.build();
// find the module
ModuleFinder finder = ModuleFinder.of(jar);
Optional<ModuleReference> omref = finder.find(name);
assertTrue((omref.isPresent()));
ModuleReference mref = omref.get();
ModuleDescriptor expected;
if (MULTI_RELEASE) {
expected = descriptor2;
} else {
expected = descriptor1;
}
// test ModuleReader by reading module-info.class resource
try (ModuleReader reader = mref.open()) {
// open resource
Optional<InputStream> oin = reader.open(MODULE_INFO);
assertTrue(oin.isPresent());
try (InputStream in = oin.get()) {
checkRequires(ModuleDescriptor.read(in), expected);
}
// read resource
Optional<ByteBuffer> obb = reader.read(MODULE_INFO);
assertTrue(obb.isPresent());
ByteBuffer bb = obb.get();
try {
checkRequires(ModuleDescriptor.read(bb), expected);
} finally {
reader.release(bb);
}
// find resource
Optional<URI> ouri = reader.find(MODULE_INFO);
assertTrue(ouri.isPresent());
URI uri = ouri.get();
String expectedTail = "!/";
if (MULTI_RELEASE)
expectedTail += "META-INF/versions/" + VERSION + "/";
expectedTail += MODULE_INFO;
assertTrue(uri.toString().endsWith(expectedTail));
URLConnection uc = uri.toURL().openConnection();
uc.setUseCaches(false);
try (InputStream in = uc.getInputStream()) {
checkRequires(ModuleDescriptor.read(in), expected);
}
}
}
/**
* Check that two ModuleDescriptor have the same requires
*/
static void checkRequires(ModuleDescriptor md1, ModuleDescriptor md2) {
assertEquals(md1.requires(), md2.requires());
}
/**
* A builder of multi-release JAR files.
*/
static class JarBuilder {
private String name;
private Set<String> resources = new HashSet<>();
private Map<String, ModuleDescriptor> descriptors = new HashMap<>();
JarBuilder(String name) {
this.name = name;
}
/**
* Adds a module-info.class to the JAR file.
*/
JarBuilder moduleInfo(String name, ModuleDescriptor descriptor) {
descriptors.put(name, descriptor);
return this;
}
/**
* Adds a dummy resource to the JAR file.
*/
JarBuilder resource(String name) {
resources.add(name);
return this;
}
/**
* Create the multi-release JAR, returning its file path.
*/
Path build() throws Exception {
Path dir = Files.createTempDirectory(Paths.get(""), "jar");
List<Path> files = new ArrayList<>();
// write the module-info.class
for (Map.Entry<String, ModuleDescriptor> e : descriptors.entrySet()) {
String name = e.getKey();
ModuleDescriptor descriptor = e.getValue();
Path mi = Paths.get(name.replace('/', File.separatorChar));
Path parent = dir.resolve(mi).getParent();
if (parent != null)
Files.createDirectories(parent);
try (OutputStream out = Files.newOutputStream(dir.resolve(mi))) {
ModuleInfoWriter.write(descriptor, out);
}
files.add(mi);
}
// write the dummy resources
for (String name : resources) {
Path file = Paths.get(name.replace('/', File.separatorChar));
// create dummy resource
Path parent = dir.resolve(file).getParent();
if (parent != null)
Files.createDirectories(parent);
Files.createFile(dir.resolve(file));
files.add(file);
}
Manifest man = new Manifest();
Attributes attrs = man.getMainAttributes();
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
attrs.put(Attributes.Name.MULTI_RELEASE, "true");
Path jarfile = Paths.get(name + ".jar");
JarUtils.createJarFile(jarfile, man, dir, files.toArray(new Path[0]));
return jarfile;
}
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2020, 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
* @library /test/lib
* @build m/*
* @run main/othervm --add-modules m test.GetPackagesTest
* @summary test the packages returned by Module::getPackages for an unnamed
* module does not include the packages for named modules
*/
package test;
import java.util.Set;
import static jdk.test.lib.Asserts.*;
public class GetPackagesTest {
public static void main(String... args) throws Exception {
// module m contains the package "p"
Class<?> c = Class.forName("p.Main");
Module m = c.getModule();
Module test = GetPackagesTest.class.getModule();
// module m and unnamed module are defined by the same class loader
assertTrue(m.isNamed());
assertFalse(test.isNamed());
assertTrue(m.getClassLoader() == test.getClassLoader());
// verify Module::getPackages on an unnamed module only contains
// the packages defined to the unnamed module
assertEquals(m.getPackages(), Set.of("p"));
Set<String> pkgs = test.getPackages();
assertTrue(pkgs.contains("test"));
assertFalse(pkgs.contains("p"));
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2020, 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.
*/
module m {
exports p;
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2020, 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.
*/
package p;
/**
* Main class for dummy module.
*/
public class Main {
public static void main(String[] args) {
}
}

View file

@ -0,0 +1,177 @@
/*
* Copyright (c) 2015, 2021, 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
* @run testng VersionTest
* @summary Basic tests for java.lang.module.ModuleDescriptor.Version.
*/
import java.lang.module.ModuleDescriptor.Version;
import org.testng.annotations.Test;
import org.testng.annotations.DataProvider;
import static org.testng.Assert.*;
@Test
public class VersionTest {
// valid version strings
@DataProvider(name = "validVersions")
public Object[][] validVersions() {
return new Object[][]{
{ "1.0", null },
{ "1.0.0", null },
{ "1.0.0.0", null },
{ "99", null },
{ "99.99", null },
{ "99.99.99", null },
{ "1-SNAPSHOT", null },
{ "1.0-SNAPSHOT", null },
{ "1.0.0-SNAPSHOT", null },
{ "9-ea", null },
{ "9-ea+110", null },
{ "9.3.2.1+42-8839942", null}
};
}
// invalid version strings
@DataProvider(name = "invalidVersions")
public Object[][] invalidVersions() {
return new Object[][]{
{ null, null },
{ "", null },
{ "A1", null }, // does not start with number
{ "1.0-", null }, // empty branch
};
}
// Test parsing valid version strings
@Test(dataProvider = "validVersions")
public void testParseValidVersions(String vs, String ignore) {
Version v = Version.parse(vs);
assertEquals(v.toString(), vs);
}
// Test parsing an invalid version strings
@Test(dataProvider = "invalidVersions",
expectedExceptions = IllegalArgumentException.class )
public void testParseInvalidVersions(String vs, String ignore) {
Version.parse(vs);
}
// Test equals and hashCode
@Test(dataProvider = "validVersions")
public void testEqualsAndHashCode(String vs, String ignore) {
Version v1 = Version.parse(vs);
Version v2 = Version.parse(vs);
assertEquals(v1, v2);
assertEquals(v2, v1);
assertEquals(v1.hashCode(), v2.hashCode());
Version v3 = Version.parse("1.0-rhubarb");
assertNotEquals(v1, v3);
assertNotEquals(v2, v3);
assertNotEquals(v3, v1);
assertNotEquals(v3, v2);
}
// ordered version strings
@DataProvider(name = "orderedVersions")
public Object[][] orderedVersions() {
return new Object[][]{
{ "1.0", "2.0" },
{ "1.0-SNAPSHOT", "1.0" },
{ "1.0-SNAPSHOT2", "1.0" },
{ "1.2.3-ea", "1.2.3" },
{ "1.2.3-ea+104", "1.2.3-ea+105" },
{ "1.2.3-ea+104-4084552", "1.2.3-ea+104-4084552+8849330" },
{ "1+104", "1+105" },
{ "1.0-alpha1", "1.0-alpha2" }
};
}
/**
* Test compareTo with ordered versions.
*/
@Test(dataProvider = "orderedVersions")
public void testCompareOrderedVersions(String vs1, String vs2) {
Version v1 = Version.parse(vs1);
assertTrue(v1.compareTo(v1) == 0);
Version v2 = Version.parse(vs2);
assertTrue(v2.compareTo(v2) == 0);
// v1 < v2
assertTrue(v1.compareTo(v2) < 0);
assertTrue(v2.compareTo(v1) > 0);
}
// equal version strings
@DataProvider(name = "equalVersions")
public Object[][] equalVersions() {
return new Object[][]{
{ "1", "1.0.0" },
{ "1.0", "1.0.0" },
{ "1.0-beta", "1.0.0-beta" },
{ "1.0-1.1", "1.0-1..1" },
{ "1.0-1+1", "1.0-1.+1" },
{ "1.0-1+1.1", "1.0-1+1..1" },
};
}
/**
* Test compareTo with equal versions.
*/
@Test(dataProvider = "equalVersions")
public void testCompareEqualsVersions(String vs1, String vs2) {
Version v1 = Version.parse(vs1);
assertTrue(v1.compareTo(v1) == 0);
Version v2 = Version.parse(vs2);
assertTrue(v2.compareTo(v2) == 0);
assertTrue(v1.compareTo(v2) == 0);
assertTrue(v2.compareTo(v1) == 0);
assertEquals(v1, v2);
assertEquals(v2, v1);
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2020, 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
* @bug 8255542
* @summary Module attribute has incorrect length
* @library ..
* @build module-info
* @run main CheckBadModuleInfo
*/

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2020, 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.
*/
module {
0xCAFEBABE;
0; // minor version
55; // version
[] { // Constant Pool
; // first element is empty
Utf8 "module-info"; // #1
class #1; // #2
Utf8 "module-info.java"; // #3
Utf8 "m"; // #4
Module #4; // #5
Utf8 "ModuleMainClass"; // #6
Utf8 "p/C"; // #7
class #7; // #8
Utf8 "ModulePackages"; // #9
Utf8 "p"; // #10
Package #10; // #11
Utf8 "java.base"; // #12
Module #12; // #13
Utf8 "11.0.2"; // #14
Utf8 "SourceFile"; // #15
Utf8 "Module"; // #16
} // Constant Pool
0x8000; // access
#2;// this_cpx
#0;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // Fields
} // Fields
[] { // Methods
} // Methods
[] { // Attributes
Attr(#15) { // SourceFile
#3;
} // end SourceFile
;
Attr(#16, 256) { // Module incorrect attribute length
#5; // name_index
0x0000; // flags
#0; // version
[] { // requires
#13 0x8000 #14;
} // requires
[] { // exports
} // exports
[] { // opens
} // opens
[] { // uses
} // uses
[] { // provides
} // provides
} // end Module
;
Attr(#6) { // ModuleMainClass
0x0008;
} // end ModuleMainClass
;
Attr(#9) { // ModulePackages
[] {
#11;
}
} // end ModulePackages
} // Attributes
} // end module m

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2020, 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
* @bug 8255542
* @summary ModuleMain attribute has incorrect length
* @library ..
* @build module-info
* @run main CheckBadModuleInfo
*/

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2020, 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.
*/
module {
0xCAFEBABE;
0; // minor version
55; // version
[] { // Constant Pool
; // first element is empty
Utf8 "module-info"; // #1
class #1; // #2
Utf8 "module-info.java"; // #3
Utf8 "m"; // #4
Module #4; // #5
Utf8 "ModuleMainClass"; // #6
Utf8 "p/C"; // #7
class #7; // #8
Utf8 "ModulePackages"; // #9
Utf8 "p"; // #10
Package #10; // #11
Utf8 "java.base"; // #12
Module #12; // #13
Utf8 "11.0.2"; // #14
Utf8 "SourceFile"; // #15
Utf8 "Module"; // #16
} // Constant Pool
0x8000; // access
#2;// this_cpx
#0;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // Fields
} // Fields
[] { // Methods
} // Methods
[] { // Attributes
Attr(#15) { // SourceFile
#3;
} // end SourceFile
;
Attr(#16) { // Module
#5; // name_index
0x0000; // flags
#0; // version
[] { // requires
#13 0x8000 #14;
} // requires
[] { // exports
} // exports
[] { // opens
} // opens
[] { // uses
} // uses
[] { // provides
} // provides
} // end Module
;
Attr(#6, 3) { // ModuleMainClass attribute_length 3 instead of 2
0x0008;
} // end ModuleMainClass
;
Attr(#9) { // ModulePackages
[] {
#11;
}
} // end ModulePackages
} // Attributes
} // end module m

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2020, 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
* @bug 8255542
* @summary ModulePackages attribute has incorrect length
* @library ..
* @build module-info
* @run main CheckBadModuleInfo
*/

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2020, 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.
*/
module {
0xCAFEBABE;
0; // minor version
55; // version
[] { // Constant Pool
; // first element is empty
Utf8 "module-info"; // #1
class #1; // #2
Utf8 "module-info.java"; // #3
Utf8 "m"; // #4
Module #4; // #5
Utf8 "ModuleMainClass"; // #6
Utf8 "p/C"; // #7
class #7; // #8
Utf8 "ModulePackages"; // #9
Utf8 "p"; // #10
Package #10; // #11
Utf8 "java.base"; // #12
Module #12; // #13
Utf8 "11.0.2"; // #14
Utf8 "SourceFile"; // #15
Utf8 "Module"; // #16
} // Constant Pool
0x8000; // access
#2;// this_cpx
#0;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // Fields
} // Fields
[] { // Methods
} // Methods
[] { // Attributes
Attr(#15) { // SourceFile
#3;
} // end SourceFile
;
Attr(#16) { // Module
#5; // name_index
0x0000; // flags
#0; // version
[] { // requires
#13 0x8000 #14;
} // requires
[] { // exports
} // exports
[] { // opens
} // opens
[] { // uses
} // uses
[] { // provides
} // provides
} // end Module
;
Attr(#6) { // ModuleMainClass
0x0008;
} // end ModuleMainClass
;
Attr(#9, 6) { // ModulePackages attribute_length 6 instead of 4
[] {
#11;
}
} // end ModulePackages
} // Attributes
} // end module m

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, 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.
*/
import java.io.IOException;
import java.io.InputStream;
import java.lang.module.ModuleDescriptor;
import java.lang.module.InvalidModuleDescriptorException;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* Uses the ModuleDescriptor.read API to read the module-info.class in the
* ${test.classes} directory and expects InvalidModuleDescriptorException
* to be thrown.
*/
public class CheckBadModuleInfo {
public static void main(String[] args) throws IOException {
Path mi = Path.of(System.getProperty("test.classes"), "module-info.class");
try (InputStream in = Files.newInputStream(mi)) {
try {
ModuleDescriptor descriptor = ModuleDescriptor.read(in);
System.out.println(descriptor);
throw new RuntimeException("InvalidModuleDescriptorException expected");
} catch (InvalidModuleDescriptorException e) {
// expected
System.out.println(e);
}
}
}
}

View file

@ -0,0 +1,148 @@
/*
* Copyright (c) 2017, 2025, 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
* @bug 8178380 8282444
* @modules jdk.zipfs
* @library /test/lib
* @build ModulesInCustomFileSystem m1/* m2/*
* jdk.test.lib.util.JarUtils
* @run testng/othervm -Djava.io.tmpdir=. ModulesInCustomFileSystem
* @summary Test ModuleFinder to find modules in a custom file system
*/
import java.io.File;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
import java.lang.reflect.Method;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
import java.util.stream.Stream;
import jdk.test.lib.util.JarUtils;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@Test
public class ModulesInCustomFileSystem {
private static final Path HERE = Paths.get("");
/**
* Test exploded modules in a Zip file system.
*/
public void testExplodedModulesInZipFileSystem() throws Exception {
Path m1 = findModuleDirectory("m1");
Path m2 = findModuleDirectory("m2");
Path mlib = m1.getParent();
assertEquals(mlib, m2.getParent());
// create JAR file containing m1/** and m2/**
Path jar = Files.createTempDirectory(HERE, "mlib").resolve("modules.jar");
JarUtils.createJarFile(jar, mlib);
testZipFileSystem(jar);
}
/**
* Test modular JARs in a Zip file system.
*/
public void testModularJARsInZipFileSystem() throws Exception {
Path m1 = findModuleDirectory("m1");
Path m2 = findModuleDirectory("m2");
Path contents = Files.createTempDirectory(HERE, "contents");
JarUtils.createJarFile(contents.resolve("m1.jar"), m1);
JarUtils.createJarFile(contents.resolve("m2.jar"), m2);
// create JAR file containing m1.jar and m2.jar
Path jar = Files.createTempDirectory(HERE, "mlib").resolve("modules.jar");
JarUtils.createJarFile(jar, contents);
testZipFileSystem(jar);
}
/**
* Opens a JAR file as a file system
*/
private void testZipFileSystem(Path zip) throws Exception {
try (FileSystem fs = FileSystems.newFileSystem(zip)) {
// ModuleFinder to find modules in top-level directory
Path top = fs.getPath("/");
ModuleFinder finder = ModuleFinder.of(top);
// list the modules
listAllModules(finder);
// load modules into child layer, invoking m1/p.Main
loadAndRunModule(finder);
}
}
/**
* List all modules that the finder finds and the resources in the module.
*/
private void listAllModules(ModuleFinder finder) throws Exception {
for (ModuleReference mref : finder.findAll()) {
System.out.println(mref.descriptor());
try (ModuleReader reader = mref.open();
Stream<String> stream = reader.list()) {
stream.forEach(name -> System.out.format(" %s%n", name));
}
}
}
/**
* Creates a child layer with m1 and m2, invokes m1/p.Main to ensure that
* classes can be loaded.
*/
private void loadAndRunModule(ModuleFinder finder) throws Exception {
ModuleLayer bootLayer = ModuleLayer.boot();
Configuration cf = bootLayer.configuration()
.resolve(finder, ModuleFinder.of(), Set.of("m1"));
ClassLoader scl = ClassLoader.getSystemClassLoader();
ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
Class<?> c = layer.findLoader("m1").loadClass("p.Main");
Method m = c.getMethod("main", String[].class);
m.invoke(null, (Object)new String[0]);
}
/**
* Find the directory for a module on the module path
*/
private Path findModuleDirectory(String name) {
String mp = System.getProperty("jdk.module.path");
for (String element : mp.split(File.pathSeparator)) {
Path dir = Paths.get(element).resolve(name);
if (Files.exists(dir)) {
return dir;
}
}
assertFalse(true);
return null;
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 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.
*/
module m1 {
exports p;
requires m2;
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 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.
*/
package p;
public class Main {
public static void main(String[] args) {
q.r.Hello.hello();
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 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.
*/
module m2 {
exports q.r;
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 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.
*/
package q.r;
public class Hello {
public static void hello() {
System.out.println("hello");
}
}