Skip to content

Commit 51e7b7b

Browse files
committed
Improve module handling.
1 parent f0e35ef commit 51e7b7b

File tree

5 files changed

+308
-23
lines changed

5 files changed

+308
-23
lines changed

byte-buddy-dep/src/main/java/net/bytebuddy/description/module/ModuleDescription.java

Lines changed: 128 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,6 @@ public interface ModuleDescription extends NamedElement,
6666
*/
6767
Set<String> getPackages();
6868

69-
/**
70-
* Returns all service types that this module uses.
71-
*
72-
* @return A set of service class names that this module uses.
73-
*/
74-
Set<String> getUses();
75-
7669
/**
7770
* Returns all package exports of this module.
7871
*
@@ -94,6 +87,13 @@ public interface ModuleDescription extends NamedElement,
9487
*/
9588
Map<String, Requires> getRequires();
9689

90+
/**
91+
* Returns all service types that this module uses.
92+
*
93+
* @return A set of service class names that this module uses.
94+
*/
95+
Set<String> getUses();
96+
9797
/**
9898
* Returns all service implementations provided by this module.
9999
*
@@ -133,6 +133,27 @@ abstract class AbstractBase extends ModifierReviewable.AbstractBase implements E
133133
public boolean isQualified() {
134134
return !getTargets().isEmpty();
135135
}
136+
137+
@Override
138+
public int hashCode() {
139+
int hashCode = getModifiers();
140+
return hashCode + 17 * getTargets().hashCode();
141+
}
142+
143+
@Override
144+
public boolean equals(Object other) {
145+
if (!(other instanceof Exports)) return false;
146+
Exports exports = (Exports) other;
147+
return getModifiers() == exports.getModifiers() && getTargets().equals(exports.getTargets());
148+
}
149+
150+
@Override
151+
public String toString() {
152+
return "Opens{"
153+
+ "targets=" + getTargets()
154+
+ ",modifiers=" + getModifiers()
155+
+ '}';
156+
}
136157
}
137158

138159
/**
@@ -208,6 +229,27 @@ abstract class AbstractBase extends ModifierReviewable.AbstractBase implements O
208229
public boolean isQualified() {
209230
return !getTargets().isEmpty();
210231
}
232+
233+
@Override
234+
public int hashCode() {
235+
int hashCode = getModifiers();
236+
return hashCode + 17 * getTargets().hashCode();
237+
}
238+
239+
@Override
240+
public boolean equals(Object other) {
241+
if (!(other instanceof Opens)) return false;
242+
Opens opens = (Opens) other;
243+
return getModifiers() == opens.getModifiers() && getTargets().equals(opens.getTargets());
244+
}
245+
246+
@Override
247+
public String toString() {
248+
return "Opens{"
249+
+ "targets=" + getTargets()
250+
+ ",modifiers=" + getModifiers()
251+
+ '}';
252+
}
211253
}
212254

213255
/**
@@ -243,13 +285,6 @@ public Set<String> getTargets() {
243285
return targets;
244286
}
245287

246-
/**
247-
* {@inheritDoc}
248-
*/
249-
public boolean isQualified() {
250-
return !targets.isEmpty();
251-
}
252-
253288
/**
254289
* {@inheritDoc}
255290
*/
@@ -273,10 +308,40 @@ interface Requires extends ModifierReviewable.ForModuleRequirement {
273308
@MaybeNull
274309
String getVersion();
275310

311+
/**
312+
* An abstract base implementation of {@link Requires}.
313+
*/
314+
abstract class AbstractBase extends ModifierReviewable.AbstractBase implements Requires {
315+
316+
@Override
317+
public int hashCode() {
318+
int hashCode = getModifiers();
319+
String version = getVersion();
320+
return version == null ? hashCode : (hashCode + 17 * version.hashCode());
321+
}
322+
323+
@Override
324+
public boolean equals(Object other) {
325+
if (!(other instanceof Requires)) return false;
326+
Requires requires = (Requires) other;
327+
String version = getVersion();
328+
return getModifiers() == requires.getModifiers() && version == null ? requires.getVersion() == null : version.equals(requires.getVersion());
329+
}
330+
331+
@Override
332+
public String toString() {
333+
String version = getVersion();
334+
return "Requires{"
335+
+ "version=" + (version == null ? "" : '"' + version + '\'')
336+
+ ",modifiers=" + getModifiers()
337+
+ '}';
338+
}
339+
}
340+
276341
/**
277342
* A simple implementation of {@link Requires}.
278343
*/
279-
class Simple extends ModifierReviewable.AbstractBase implements Requires {
344+
class Simple extends AbstractBase {
280345

281346
/**
282347
* The version of the required module.
@@ -330,10 +395,33 @@ interface Provides {
330395
*/
331396
Set<String> getProviders();
332397

398+
/**
399+
* An abstract base implementation of {@link Provides}.
400+
*/
401+
abstract class AbstractBase implements Provides {
402+
403+
@Override
404+
public int hashCode() {
405+
return getProviders().hashCode();
406+
}
407+
408+
@Override
409+
public boolean equals(Object other) {
410+
if (!(other instanceof Provides)) return false;
411+
Provides provides = (Provides) other;
412+
return getProviders().equals(provides.getProviders());
413+
}
414+
415+
@Override
416+
public String toString() {
417+
return "Provides{providers=" + getProviders() + '}';
418+
}
419+
}
420+
333421
/**
334422
* A simple implementation of {@link Provides}.
335423
*/
336-
class Simple implements Provides {
424+
class Simple extends AbstractBase {
337425

338426
/**
339427
* The implementation classes that provide the service.
@@ -358,12 +446,35 @@ public Set<String> getProviders() {
358446
}
359447
}
360448

449+
/**
450+
* An abstract base implementation of a {@link ModuleDescription}.
451+
*/
452+
abstract class AbstractBase extends ModifierReviewable.AbstractBase implements ModuleDescription {
453+
454+
@Override
455+
public int hashCode() {
456+
return 17 * getActualName().hashCode();
457+
}
458+
459+
@Override
460+
public boolean equals(Object other) {
461+
if (!(other instanceof ModuleDescription)) return false;
462+
ModuleDescription module = (ModuleDescription) other;
463+
return getActualName().equals(module.getActualName());
464+
}
465+
466+
@Override
467+
public String toString() {
468+
return "module " + getActualName();
469+
}
470+
}
471+
361472
/**
362473
* A {@link ModuleDescription} implementation that represents a loaded Java module.
363474
* This implementation uses reflection and Java dispatchers to access module information
364475
* from the runtime module system.
365476
*/
366-
class ForLoadedModule extends ModifierReviewable.AbstractBase implements ModuleDescription {
477+
class ForLoadedModule extends AbstractBase {
367478

368479
/**
369480
* A dispatcher for accessing {@code java.lang.Module} methods.

byte-buddy-dep/src/main/java/net/bytebuddy/pool/TypePool.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7871,7 +7871,7 @@ public TypeList asErasures() {
78717871
/**
78727872
* A lazy description of a module.
78737873
*/
7874-
private class LazyModuleDescription extends ModifierReviewable.AbstractBase implements ModuleDescription {
7874+
private class LazyModuleDescription extends ModuleDescription.AbstractBase {
78757875

78767876
/**
78777877
* The name of the module.
@@ -9454,7 +9454,7 @@ public void visitMainClass(String mainClass) {
94549454

94559455
@Override
94569456
public void visitPackage(String aPackage) {
9457-
super.visitPackage(aPackage);
9457+
packages.add(aPackage);
94589458
}
94599459

94609460
@Override
@@ -9463,13 +9463,17 @@ public void visitRequire(String module, int access, @MaybeNull String version) {
94639463
}
94649464

94659465
@Override
9466-
public void visitExport(String aPackage, int modifiers, String[] modules) {
9467-
exports.put(aPackage, new ModuleDescription.Exports.Simple(new LinkedHashSet<String>(Arrays.asList(modules)), modifiers));
9466+
public void visitExport(String aPackage, int modifiers, @MaybeNull String[] modules) {
9467+
exports.put(aPackage, new ModuleDescription.Exports.Simple(modules == null
9468+
? Collections.<String>emptySet()
9469+
: new LinkedHashSet<String>(Arrays.asList(modules)), modifiers));
94689470
}
94699471

94709472
@Override
9471-
public void visitOpen(String aPackage, int modifiers, String[] modules) {
9472-
opens.put(aPackage, new ModuleDescription.Opens.Simple(new LinkedHashSet<String>(Arrays.asList(modules)), modifiers));
9473+
public void visitOpen(String aPackage, int modifiers, @MaybeNull String[] modules) {
9474+
opens.put(aPackage, new ModuleDescription.Opens.Simple(modules == null
9475+
? Collections.<String>emptySet()
9476+
: new LinkedHashSet<String>(Arrays.asList(modules)), modifiers));
94739477
}
94749478

94759479
@Override
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package net.bytebuddy.description.module;
2+
3+
import jdk.internal.org.objectweb.asm.Type;
4+
import net.bytebuddy.utility.AsmClassWriter;
5+
import org.junit.After;
6+
import org.junit.AfterClass;
7+
import org.junit.Before;
8+
import org.junit.Test;
9+
import org.objectweb.asm.ClassVisitor;
10+
import org.objectweb.asm.ModuleVisitor;
11+
import org.objectweb.asm.Opcodes;
12+
13+
import java.io.File;
14+
import java.io.FileOutputStream;
15+
import java.util.Collections;
16+
import java.util.jar.JarEntry;
17+
import java.util.jar.JarOutputStream;
18+
19+
import static org.hamcrest.CoreMatchers.is;
20+
import static org.hamcrest.MatcherAssert.assertThat;
21+
22+
public abstract class AbstractModuleDescriptionTest {
23+
24+
protected static final String FOO = "foo", BAR = "bar", QUX = "qux", BAZ = "baz";
25+
26+
protected File jar;
27+
28+
@Before
29+
public void setUp() throws Exception {
30+
jar = File.createTempFile("sample", ".jar");
31+
JarOutputStream outputStream = new JarOutputStream(new FileOutputStream(jar));
32+
try {
33+
{
34+
outputStream.putNextEntry(new JarEntry("module-info.class"));
35+
AsmClassWriter classWriter = AsmClassWriter.Factory.Default.IMPLICIT.make(0);
36+
ClassVisitor classVisitor = classWriter.getVisitor();
37+
classVisitor.visit(Opcodes.V9, Opcodes.ACC_MODULE, "module-info", null, null, null);
38+
ModuleVisitor moduleVisitor = classVisitor.visitModule(FOO, 0, BAR);
39+
moduleVisitor.visitMainClass(QUX);
40+
moduleVisitor.visitPackage(FOO);
41+
moduleVisitor.visitUse(BAR);
42+
moduleVisitor.visitProvide(QUX, BAZ);
43+
moduleVisitor.visitExport(FOO, 0, BAR);
44+
moduleVisitor.visitOpen(QUX, 0, BAZ);
45+
moduleVisitor.visitRequire(FOO + BAR, 0, QUX + BAZ);
46+
moduleVisitor.visitEnd();
47+
classVisitor.visitEnd();
48+
outputStream.write(classWriter.getBinaryRepresentation());
49+
outputStream.closeEntry();
50+
}
51+
{
52+
outputStream.putNextEntry(new JarEntry(FOO + "/" + BAR + ".class"));
53+
AsmClassWriter classWriter = AsmClassWriter.Factory.Default.IMPLICIT.make(0);
54+
ClassVisitor classVisitor = classWriter.getVisitor();
55+
classVisitor.visit(Opcodes.V9, Opcodes.ACC_PUBLIC, FOO + "." + BAR, null, Type.getInternalName(Object.class), null);
56+
classVisitor.visitEnd();
57+
outputStream.write(classWriter.getBinaryRepresentation());
58+
outputStream.closeEntry();
59+
}
60+
} finally {
61+
outputStream.close();
62+
}
63+
}
64+
65+
@After
66+
public void tearDown() throws Exception {
67+
assertThat(jar.delete(), is(true));
68+
}
69+
70+
protected abstract ModuleDescription toModuleDescription() throws Exception;
71+
72+
@Test
73+
public void testModuleDescription() throws Exception {
74+
ModuleDescription moduleDescription = toModuleDescription();
75+
assertThat(moduleDescription.getActualName(), is(FOO));
76+
assertThat(moduleDescription.getMainClass(), is(QUX));
77+
assertThat(moduleDescription.getPackages(), is(Collections.singleton(FOO)));
78+
assertThat(moduleDescription.getUses(), is(Collections.singleton(BAR)));
79+
assertThat(moduleDescription.getProvides(), is(Collections.<String, ModuleDescription.Provides>singletonMap(
80+
QUX,
81+
new ModuleDescription.Provides.Simple(Collections.singleton(BAZ)))));
82+
assertThat(moduleDescription.getExports(), is(Collections.<String, ModuleDescription.Exports>singletonMap(
83+
FOO,
84+
new ModuleDescription.Exports.Simple(Collections.singleton(BAR), 0))));
85+
assertThat(moduleDescription.getOpens(), is(Collections.<String, ModuleDescription.Opens>singletonMap(
86+
QUX,
87+
new ModuleDescription.Opens.Simple(Collections.singleton(BAZ), 0))));
88+
assertThat(moduleDescription.getRequires(), is(Collections.<String, ModuleDescription.Requires>singletonMap(
89+
FOO + BAR,
90+
new ModuleDescription.Requires.Simple(QUX + BAZ, 0))));
91+
assertThat(moduleDescription.hashCode(), is(toModuleDescription().hashCode()));
92+
assertThat(moduleDescription, is(toModuleDescription()));
93+
assertThat(moduleDescription.toString(), is("module " + moduleDescription.getActualName()));
94+
}
95+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package net.bytebuddy.description.module;
2+
3+
import net.bytebuddy.test.utility.JavaVersionRule;
4+
import org.junit.After;
5+
import org.junit.Before;
6+
import org.junit.Rule;
7+
import org.junit.rules.MethodRule;
8+
9+
import java.io.Closeable;
10+
import java.net.URL;
11+
import java.net.URLClassLoader;
12+
13+
public class ModuleDescriptionForLoadedModuleTest extends AbstractModuleDescriptionTest {
14+
15+
@Rule
16+
public MethodRule javaVersionRule = new JavaVersionRule();
17+
18+
private ClassLoader classLoader;
19+
20+
@Before
21+
public void setUp() throws Exception {
22+
super.setUp();
23+
classLoader = new URLClassLoader(new URL[]{jar.toURI().toURL()}, AbstractModuleDescriptionTest.class.getClassLoader());
24+
}
25+
26+
@After
27+
public void tearDown() throws Exception {
28+
super.tearDown();
29+
if (classLoader instanceof Closeable) {
30+
((Closeable) classLoader).close();
31+
}
32+
}
33+
34+
@Override
35+
protected ModuleDescription toModuleDescription() throws Exception {
36+
Class<?> type = classLoader.loadClass(FOO + "." + BAR);
37+
Object module = Class.class.getMethod("getModule").invoke(type);
38+
return ModuleDescription.ForLoadedModule.of(module);
39+
}
40+
41+
@Override
42+
@JavaVersionRule.Enforce(9)
43+
public void testModuleDescription() throws Exception {
44+
super.testModuleDescription();
45+
}
46+
}

0 commit comments

Comments
 (0)