Skip to content

Commit a8b43e7

Browse files
committed
Add support for writing out module information from type writer.
1 parent cbead69 commit a8b43e7

File tree

2 files changed

+262
-2
lines changed

2 files changed

+262
-2
lines changed

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@
2323
import net.bytebuddy.utility.dispatcher.JavaDispatcher;
2424
import net.bytebuddy.utility.nullability.AlwaysNull;
2525
import net.bytebuddy.utility.nullability.MaybeNull;
26+
import org.objectweb.asm.ClassVisitor;
27+
import org.objectweb.asm.ModuleVisitor;
2628
import org.objectweb.asm.Opcodes;
2729

2830
import java.lang.reflect.AnnotatedElement;
2931
import java.security.PrivilegedAction;
32+
import java.util.Iterator;
3033
import java.util.LinkedHashMap;
3134
import java.util.LinkedHashSet;
3235
import java.util.List;
@@ -46,6 +49,13 @@ public interface ModuleDescription extends NamedElement,
4649
@AlwaysNull
4750
ModuleDescription UNDEFINED = null;
4851

52+
/**
53+
* Writes this module description as meta data to the provided {@link ClassVisitor}.
54+
*
55+
* @param classVisitor The class visitor to write to.
56+
*/
57+
void accept(ClassVisitor classVisitor);
58+
4959
/**
5060
* Returns the version of this module.
5161
*
@@ -454,6 +464,49 @@ public Set<String> getProviders() {
454464
*/
455465
abstract class AbstractBase extends ModifierReviewable.AbstractBase implements ModuleDescription {
456466

467+
/**
468+
* {@inheritDoc}
469+
*/
470+
public void accept(ClassVisitor classVisitor) {
471+
ModuleVisitor moduleVisitor = classVisitor.visitModule(getActualName(), getModifiers(), getVersion());
472+
if (moduleVisitor != null) {
473+
String mainClass = getMainClass();
474+
if (mainClass != null) {
475+
moduleVisitor.visitMainClass(mainClass.replace('.', '/'));
476+
}
477+
for (String aPackage : getPackages()) {
478+
moduleVisitor.visitPackage(aPackage.replace('.', '/'));
479+
}
480+
for (Map.Entry<String, ModuleDescription.Requires> entry : getRequires().entrySet()) {
481+
moduleVisitor.visitRequire(entry.getKey(), entry.getValue().getModifiers(), entry.getValue().getVersion());
482+
}
483+
for (Map.Entry<String, ModuleDescription.Exports> entry : getExports().entrySet()) {
484+
moduleVisitor.visitExport(entry.getKey().replace('.', '/'),
485+
entry.getValue().getModifiers(),
486+
entry.getValue().getTargets().isEmpty() ? null : entry.getValue().getTargets().toArray(new String[0]));
487+
}
488+
for (Map.Entry<String, ModuleDescription.Opens> entry : getOpens().entrySet()) {
489+
moduleVisitor.visitOpen(entry.getKey().replace('.', '/'),
490+
entry.getValue().getModifiers(),
491+
entry.getValue().getTargets().isEmpty() ? null : entry.getValue().getTargets().toArray(new String[0]));
492+
}
493+
for (String use : getUses()) {
494+
moduleVisitor.visitUse(use.replace('.', '/'));
495+
}
496+
for (Map.Entry<String, ModuleDescription.Provides> entry : getProvides().entrySet()) {
497+
String[] provider = entry.getValue().getProviders().isEmpty() ? null : new String[entry.getValue().getProviders().size()];
498+
if (provider != null) {
499+
Iterator<String> iterator = entry.getValue().getProviders().iterator();
500+
for (int index = 0; index < provider.length; index++) {
501+
provider[index] = iterator.next().replace('.', '/');
502+
}
503+
}
504+
moduleVisitor.visitProvide(entry.getKey().replace('.', '/'), provider);
505+
}
506+
moduleVisitor.visitEnd();
507+
}
508+
}
509+
457510
@Override
458511
public int hashCode() {
459512
return 17 * getActualName().hashCode();

byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/TypeWriter.java

Lines changed: 209 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import net.bytebuddy.description.method.ParameterList;
3131
import net.bytebuddy.description.modifier.ModifierContributor;
3232
import net.bytebuddy.description.modifier.Visibility;
33+
import net.bytebuddy.description.module.ModuleDescription;
3334
import net.bytebuddy.description.type.PackageDescription;
3435
import net.bytebuddy.description.type.RecordComponentDescription;
3536
import net.bytebuddy.description.type.RecordComponentList;
@@ -79,6 +80,7 @@
7980
import org.objectweb.asm.Handle;
8081
import org.objectweb.asm.Label;
8182
import org.objectweb.asm.MethodVisitor;
83+
import org.objectweb.asm.ModuleVisitor;
8284
import org.objectweb.asm.Opcodes;
8385
import org.objectweb.asm.RecordComponentVisitor;
8486
import org.objectweb.asm.Type;
@@ -100,6 +102,7 @@
100102
import java.util.LinkedHashMap;
101103
import java.util.LinkedHashSet;
102104
import java.util.List;
105+
import java.util.Map;
103106
import java.util.Set;
104107

105108
import static net.bytebuddy.matcher.ElementMatchers.is;
@@ -6076,7 +6079,7 @@ public ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int
60766079
fields,
60776080
methods,
60786081
asmVisitorWrapper.mergeWriter(writerFlags),
6079-
asmVisitorWrapper.mergeReader(readerFlags)), implementationContext), implementationContext);
6082+
asmVisitorWrapper.mergeReader(readerFlags)), implementationContext, instrumentedType.toModuleDescription()), implementationContext);
60806083
}
60816084

60826085
@Override
@@ -6108,6 +6111,10 @@ protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction
61086111
? TypeDescription.ForLoadedType.of(Object.class)
61096112
: instrumentedType.getSuperClass().asErasure()).getInternalName(),
61106113
instrumentedType.getInterfaces().asErasures().toInternalNames());
6114+
ModuleDescription moduleDescription = instrumentedType.toModuleDescription();
6115+
if (moduleDescription != null) {
6116+
moduleDescription.accept(classVisitor);
6117+
}
61116118
if (!instrumentedType.isNestHost()) {
61126119
classVisitor.visitNestHost(instrumentedType.getNestHost().getInternalName());
61136120
}
@@ -6181,6 +6188,12 @@ protected class CreationClassVisitor extends MetadataAwareClassVisitor {
61816188
*/
61826189
private final Implementation.Context.ExtractableView implementationContext;
61836190

6191+
/**
6192+
* The underlying module information or {@code null} if no such information is provided.
6193+
*/
6194+
@MaybeNull
6195+
private final ModuleDescription moduleDescription;
6196+
61846197
/**
61856198
* The declared types that have been visited.
61866199
*/
@@ -6201,10 +6214,29 @@ protected class CreationClassVisitor extends MetadataAwareClassVisitor {
62016214
*
62026215
* @param classVisitor The class visitor being wrapped.
62036216
* @param implementationContext The implementation context to apply.
6217+
* @param moduleDescription The underlying module information or {@code null} if no such information is provided.
62046218
*/
6205-
protected CreationClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
6219+
protected CreationClassVisitor(ClassVisitor classVisitor,
6220+
Implementation.Context.ExtractableView implementationContext,
6221+
@MaybeNull ModuleDescription moduleDescription) {
62066222
super(OpenedClassReader.ASM_API, classVisitor);
62076223
this.implementationContext = implementationContext;
6224+
this.moduleDescription = moduleDescription;
6225+
}
6226+
6227+
@Override
6228+
protected void onModule() {
6229+
if (moduleDescription != null) {
6230+
moduleDescription.accept(cv);
6231+
}
6232+
}
6233+
6234+
@Override
6235+
@MaybeNull
6236+
protected ModuleVisitor onVisitModule(String name, int modifiers, @MaybeNull String version) {
6237+
return moduleDescription == null ? null : new PatchingModuleVisitor(cv.visitModule(moduleDescription.getActualName(),
6238+
moduleDescription.getModifiers(),
6239+
moduleDescription.getVersion()), moduleDescription);
62086240
}
62096241

62106242
@Override
@@ -6263,6 +6295,181 @@ protected void onVisitEnd() {
62636295
}
62646296
}
62656297

6298+
/**
6299+
* A class visitor that applies the subclass creation as a wrapper.
6300+
*/
6301+
protected static class PatchingModuleVisitor extends ModuleVisitor {
6302+
6303+
/**
6304+
* The internal name of the main class or {@code null} if no main class is defined.
6305+
*/
6306+
@MaybeNull
6307+
private String mainClass;
6308+
6309+
/**
6310+
* The internal name of all packages of the module.
6311+
*/
6312+
private final Set<String> packages;
6313+
6314+
/**
6315+
* A mapping of required modules to their configuration.
6316+
*/
6317+
private final Map<String, ModuleDescription.Requires> requires;
6318+
6319+
/**
6320+
* A mapping of the internal names of exported packages to their configuration.
6321+
*/
6322+
private final Map<String, ModuleDescription.Exports> exports;
6323+
6324+
/**
6325+
* A mapping of the internal names of opened packages to their configuration.
6326+
*/
6327+
private final Map<String, ModuleDescription.Opens> opens;
6328+
6329+
/**
6330+
* A collection of internal names of used services.
6331+
*/
6332+
private final Set<String> uses;
6333+
6334+
/**
6335+
* A mapping of the internal names of provided services to the internal names of the provided implementations.
6336+
*/
6337+
private final Map<String, Set<String>> provides;
6338+
6339+
/**
6340+
* Creates a module visitor that patches the module implementation.
6341+
*
6342+
* @param moduleVisitor The module visitor to which the data is delegated to.
6343+
* @param moduleDescription A description of the module.
6344+
*/
6345+
protected PatchingModuleVisitor(ModuleVisitor moduleVisitor, ModuleDescription moduleDescription) {
6346+
super(OpenedClassReader.ASM_API, moduleVisitor);
6347+
mainClass = moduleDescription.getMainClass();
6348+
if (mainClass != null) {
6349+
mainClass = mainClass.replace('.', '/');
6350+
}
6351+
packages = new LinkedHashSet<String>();
6352+
for (String aPackage : moduleDescription.getPackages()) {
6353+
packages.add(aPackage.replace('.', '/'));
6354+
}
6355+
requires = new LinkedHashMap<String, ModuleDescription.Requires>(moduleDescription.getRequires());
6356+
exports = new LinkedHashMap<String, ModuleDescription.Exports>();
6357+
for (Map.Entry<String, ModuleDescription.Exports> entry : moduleDescription.getExports().entrySet()) {
6358+
exports.put(entry.getKey().replace('.', '/'), entry.getValue());
6359+
}
6360+
opens = new LinkedHashMap<String, ModuleDescription.Opens>();
6361+
for (Map.Entry<String, ModuleDescription.Opens> entry : moduleDescription.getOpens().entrySet()) {
6362+
opens.put(entry.getKey().replace('.', '/'), entry.getValue());
6363+
}
6364+
uses = new LinkedHashSet<String>();
6365+
for (String use : moduleDescription.getUses()) {
6366+
uses.add(use.replace('.', '/'));
6367+
}
6368+
provides = new LinkedHashMap<String, Set<String>>();
6369+
for (Map.Entry<String, ModuleDescription.Provides> entry : moduleDescription.getProvides().entrySet()) {
6370+
Set<String> providers = new LinkedHashSet<String>();
6371+
for (String provider : entry.getValue().getProviders()) {
6372+
providers.add(provider.replace('.', '/'));
6373+
}
6374+
provides.put(entry.getKey().replace('.', '/'), providers);
6375+
}
6376+
}
6377+
6378+
@Override
6379+
public void visitMainClass(String mainClass) {
6380+
if (this.mainClass != null) {
6381+
super.visitMainClass(this.mainClass);
6382+
this.mainClass = null;
6383+
}
6384+
}
6385+
6386+
@Override
6387+
public void visitPackage(String aPackage) {
6388+
super.visitPackage(aPackage);
6389+
packages.remove(aPackage);
6390+
}
6391+
6392+
@Override
6393+
public void visitRequire(String module, int modifiers, @MaybeNull String version) {
6394+
ModuleDescription.Requires requires = this.requires.remove(module);
6395+
if (requires != null) {
6396+
super.visitRequire(module, requires.getModifiers(), requires.getVersion());
6397+
} else {
6398+
super.visitRequire(module, modifiers, version);
6399+
}
6400+
}
6401+
6402+
@Override
6403+
public void visitExport(String aPackage, int modifiers, @MaybeNull String... module) {
6404+
ModuleDescription.Exports exports = this.exports.remove(aPackage);
6405+
if (exports != null) {
6406+
super.visitExport(aPackage, exports.getModifiers(), exports.getTargets().isEmpty()
6407+
? null
6408+
: exports.getTargets().toArray(new String[0]));
6409+
} else {
6410+
super.visitExport(aPackage, modifiers, module);
6411+
}
6412+
}
6413+
6414+
@Override
6415+
public void visitOpen(String aPackage, int modifiers, @MaybeNull String... module) {
6416+
ModuleDescription.Opens opens = this.opens.remove(aPackage);
6417+
if (opens != null) {
6418+
super.visitOpen(aPackage, opens.getModifiers(), opens.getTargets().isEmpty()
6419+
? null
6420+
: opens.getTargets().toArray(new String[0]));
6421+
} else {
6422+
super.visitOpen(aPackage, modifiers, module);
6423+
}
6424+
}
6425+
6426+
@Override
6427+
public void visitUse(String service) {
6428+
uses.remove(service);
6429+
super.visitUse(service);
6430+
}
6431+
6432+
@Override
6433+
public void visitProvide(String service, String... provider) {
6434+
Set<String> providers = this.provides.remove(service);
6435+
if (providers != null) {
6436+
super.visitProvide(service, providers.toArray(new String[0]));
6437+
} else {
6438+
super.visitProvide(service, provider);
6439+
}
6440+
}
6441+
6442+
@Override
6443+
public void visitEnd() {
6444+
if (mainClass != null) {
6445+
super.visitMainClass(mainClass);
6446+
}
6447+
for (String aPackage : packages) {
6448+
super.visitPackage(aPackage);
6449+
}
6450+
for (Map.Entry<String, ModuleDescription.Requires> entry : requires.entrySet()) {
6451+
super.visitRequire(entry.getKey(), entry.getValue().getModifiers(), entry.getValue().getVersion());
6452+
}
6453+
for (Map.Entry<String, ModuleDescription.Exports> entry : exports.entrySet()) {
6454+
super.visitExport(entry.getKey(),
6455+
entry.getValue().getModifiers(),
6456+
entry.getValue().getTargets().isEmpty() ? null : entry.getValue().getTargets().toArray(new String[0]));
6457+
}
6458+
for (Map.Entry<String, ModuleDescription.Opens> entry : opens.entrySet()) {
6459+
super.visitOpen(entry.getKey(),
6460+
entry.getValue().getModifiers(),
6461+
entry.getValue().getTargets().isEmpty() ? null : entry.getValue().getTargets().toArray(new String[0]));
6462+
}
6463+
for (String use : uses) {
6464+
super.visitUse(use);
6465+
}
6466+
for (Map.Entry<String, Set<String>> entry : provides.entrySet()) {
6467+
super.visitProvide(entry.getKey(), entry.getValue().isEmpty() ? null : entry.getValue().toArray(new String[0]));
6468+
}
6469+
super.visitEnd();
6470+
}
6471+
}
6472+
62666473
/**
62676474
* A context class visitor based on an {@link Implementation.Context}.
62686475
*/

0 commit comments

Comments
 (0)