Skip to content

Commit f4fd2cb

Browse files
committedFeb 23, 2024
8290041: ModuleDescriptor.hashCode is inconsistent
Backport-of: 4cc6cb9d9ddbcc540baac7b81398f2af83f93340
1 parent e8f7eae commit f4fd2cb

File tree

2 files changed

+120
-6
lines changed

2 files changed

+120
-6
lines changed
 

‎src/java.base/share/classes/java/lang/module/ModuleDescriptor.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -2553,7 +2553,7 @@ private static <M> String toString(Set<M> mods, String what) {
25532553
private static int modsHashCode(Iterable<? extends Enum<?>> enums) {
25542554
int h = 0;
25552555
for (Enum<?> e : enums) {
2556-
h = h * 43 + Objects.hashCode(e.name());
2556+
h += e.name().hashCode();
25572557
}
25582558
return h;
25592559
}

‎test/jdk/java/lang/module/ModuleDescriptorHashCodeTest.java

+119-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -21,22 +21,24 @@
2121
* questions.
2222
*/
2323

24-
import org.testng.annotations.Test;
25-
2624
import java.io.IOException;
2725
import java.io.InputStream;
2826
import java.lang.module.ModuleDescriptor;
27+
import java.lang.module.ModuleDescriptor.Exports;
28+
import java.lang.module.ModuleDescriptor.Opens;
29+
import java.lang.module.ModuleDescriptor.Requires;
2930
import java.util.Set;
3031

32+
import org.testng.annotations.Test;
3133
import static org.testng.Assert.assertEquals;
3234
import static org.testng.Assert.assertNotSame;
3335

3436
/**
3537
* @test
36-
* @bug 8275509
38+
* @bug 8275509 8290041
39+
* @summary Tests the ModuleDescriptor.hashCode()
3740
* @run testng ModuleDescriptorHashCodeTest
3841
* @run testng/othervm -Xshare:off ModuleDescriptorHashCodeTest
39-
* @summary Tests the ModuleDescriptor.hashCode() for boot layer modules
4042
*/
4143
public class ModuleDescriptorHashCodeTest {
4244

@@ -63,6 +65,99 @@ public void testBootModuleDescriptor() throws Exception {
6365
}
6466
}
6567

68+
/**
69+
* Verifies that two "equal" module descriptors which only differ in the order of
70+
* {@link ModuleDescriptor.Opens.Modifier opens modifiers}, that were used to construct the
71+
* descriptors, have the same hashcode.
72+
*/
73+
@Test
74+
public void testOpensModifiersOrdering() throws Exception {
75+
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
76+
final Set<Opens.Modifier> mods1 = Set.of(Opens.Modifier.SYNTHETIC, Opens.Modifier.MANDATED);
77+
final ModuleDescriptor desc1 = createModuleDescriptor(mods1, null, null);
78+
79+
// create the same module descriptor again and this time just change the order of the
80+
// "opens" modifiers' Set.
81+
82+
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
83+
final Set<Opens.Modifier> mods2 = Set.of(Opens.Modifier.MANDATED, Opens.Modifier.SYNTHETIC);
84+
final ModuleDescriptor desc2 = createModuleDescriptor(mods2, null, null);
85+
86+
// basic verification of the modifiers themselves before we check the module descriptors
87+
assertEquals(mods1, mods2, "Modifiers were expected to be equal");
88+
89+
// now verify the module descriptors
90+
assertEquals(desc1, desc2, "Module descriptors were expected to be equal");
91+
assertEquals(desc1.compareTo(desc2), 0, "compareTo was expected to return" +
92+
" 0 for module descriptors that are equal");
93+
System.out.println(desc1 + " hashcode = " + desc1.hashCode());
94+
System.out.println(desc2 + " hashcode = " + desc2.hashCode());
95+
assertEquals(desc1.hashCode(), desc2.hashCode(), "Module descriptor hashcodes" +
96+
" were expected to be equal");
97+
}
98+
99+
/**
100+
* Verifies that two "equal" module descriptors which only differ in the order of
101+
* {@link ModuleDescriptor.Exports.Modifier exports modifiers}, that were used to construct the
102+
* descriptors, have the same hashcode.
103+
*/
104+
@Test
105+
public void testExportsModifiersOrdering() throws Exception {
106+
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
107+
final Set<Exports.Modifier> mods1 = Set.of(Exports.Modifier.SYNTHETIC, Exports.Modifier.MANDATED);
108+
final ModuleDescriptor desc1 = createModuleDescriptor(null, null, mods1);
109+
110+
// create the same module descriptor again and this time just change the order of the
111+
// "exports" modifiers' Set.
112+
113+
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
114+
final Set<Exports.Modifier> mods2 = Set.of(Exports.Modifier.MANDATED, Exports.Modifier.SYNTHETIC);
115+
final ModuleDescriptor desc2 = createModuleDescriptor(null, null, mods2);
116+
117+
// basic verification of the modifiers themselves before we check the module descriptors
118+
assertEquals(mods1, mods2, "Modifiers were expected to be equal");
119+
120+
// now verify the module descriptors
121+
assertEquals(desc1, desc2, "Module descriptors were expected to be equal");
122+
assertEquals(desc1.compareTo(desc2), 0, "compareTo was expected to return" +
123+
" 0 for module descriptors that are equal");
124+
System.out.println(desc1 + " hashcode = " + desc1.hashCode());
125+
System.out.println(desc2 + " hashcode = " + desc2.hashCode());
126+
assertEquals(desc1.hashCode(), desc2.hashCode(), "Module descriptor hashcodes" +
127+
" were expected to be equal");
128+
}
129+
130+
/**
131+
* Verifies that two "equal" module descriptors which only differ in the order of
132+
* {@link ModuleDescriptor.Requires.Modifier requires modifiers}, that were used to construct the
133+
* descriptors, have the same hashcode.
134+
*/
135+
@Test
136+
public void testRequiresModifiersOrdering() throws Exception {
137+
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
138+
final Set<Requires.Modifier> mods1 = Set.of(Requires.Modifier.SYNTHETIC, Requires.Modifier.MANDATED);
139+
final ModuleDescriptor desc1 = createModuleDescriptor(null, mods1, null);
140+
141+
// create the same module descriptor again and this time just change the order of the
142+
// "exports" modifiers' Set.
143+
144+
// important to use Set.of() (i.e. backed by immutable set) to reproduce the issue
145+
final Set<Requires.Modifier> mods2 = Set.of(Requires.Modifier.MANDATED, Requires.Modifier.SYNTHETIC);
146+
final ModuleDescriptor desc2 = createModuleDescriptor(null, mods2, null);
147+
148+
// basic verification of the modifiers themselves before we check the module descriptors
149+
assertEquals(mods1, mods2, "Modifiers were expected to be equal");
150+
151+
// now verify the module descriptors
152+
assertEquals(desc1, desc2, "Module descriptors were expected to be equal");
153+
assertEquals(desc1.compareTo(desc2), 0, "compareTo was expected to return" +
154+
" 0 for module descriptors that are equal");
155+
System.out.println(desc1 + " hashcode = " + desc1.hashCode());
156+
System.out.println(desc2 + " hashcode = " + desc2.hashCode());
157+
assertEquals(desc1.hashCode(), desc2.hashCode(), "Module descriptor hashcodes" +
158+
" were expected to be equal");
159+
}
160+
66161
// Returns a ModuleDescriptor parsed out of the module-info.class of the passed Module
67162
private static ModuleDescriptor fromModuleInfoClass(Module module) throws IOException {
68163
try (InputStream moduleInfo = module.getResourceAsStream("module-info.class")) {
@@ -73,4 +168,23 @@ private static ModuleDescriptor fromModuleInfoClass(Module module) throws IOExce
73168
return ModuleDescriptor.read(moduleInfo);
74169
}
75170
}
171+
172+
// creates a module descriptor with passed (optional) opens/exports/requires modifiers
173+
private static ModuleDescriptor createModuleDescriptor(
174+
Set<Opens.Modifier> opensModifiers,
175+
Set<Requires.Modifier> reqsModifiers,
176+
Set<Exports.Modifier> expsModifiers) {
177+
178+
final ModuleDescriptor.Builder builder = ModuleDescriptor.newModule("foobar");
179+
if (opensModifiers != null) {
180+
builder.opens(opensModifiers, "a.p1", Set.of("a.m1"));
181+
}
182+
if (reqsModifiers != null) {
183+
builder.requires(reqsModifiers, "a.m2");
184+
}
185+
if (expsModifiers != null) {
186+
builder.exports(expsModifiers, "a.b.c", Set.of("a.m3"));
187+
}
188+
return builder.build();
189+
}
76190
}

1 commit comments

Comments
 (1)

openjdk-notifier[bot] commented on Feb 23, 2024

@openjdk-notifier[bot]
Please sign in to comment.