<div dir="ltr"><div><div><div><div><div><div><div><b>Summary</b><br>This proposal suggests allowing annotations on module directives in a module-info, similar to how module declarations can currently be annotated. This enhancement, while narrow in scope, would give developers more flexibility when designing libraries deeply integrated with Java's built-in module system. I have built a proof of concept on <a href="https://github.com/Auties00/jdk/tree/module_directives_annotations">Github</a> which is already fully working and completely backwards compatible. I still haven't:<br></div><div><ol><li>Build automated integration tests</li><li>Added support for the new <a href="https://openjdk.org/jeps/457">ClassFile API</a> </li></ol>Before doing that though I wanted to collect some feedback on my implementation, especially on:<ol><li>Whether this change makes sense to the maintainers</li><li>The new bytecode instructions I introduced and whether better alternatives exist<br></li><li>The uses() accessor in ModuleDescriptor</li></ol><div>All changes I made are documented in the respective commits I made, but if you have any questions please let me know.<br><br></div></div><b>Bytecode</b><br></div></div><div>My implementation introduces two new bytecode attributes:<br><ul><li>ModuleDirectivesRuntimeInvisibleAnnotations</li><li>ModuleDirectivesRuntimeVisibleAnnotations</li></ul><div>which both contain, for each type of module directive, the number of directives that were annotated and for each directive that was annotated:<br></div><div><ol><li>The index of the directive relative to all the directives of the same type that are present in the module<br></li><li>The number of annotations that were attached to the directive</li><li>The metadata of the annotation in the standard format used in the bytecode</li></ol></div><div>Before working on this implementation, I had never designed bytecode instructions so my approach might be suboptimal, so if any better alternatives exist, I'll implement the changes as soon as possible. Other approaches I considered:<br><ul><li>Using RuntimeInvisibleAnnotations and RuntimeVisibleAnnotations <br>Module directives are stored in the Module attribute alongside the module name, flags and version, instead of in a specialized table like class fields or local variables. For this reason, they cannot declare their own attributes(nested attributes are not supported by the JVM). </li><li>Modifying the Module attribute to contain the annotations directly in the existing directives metadata<br>While this approach doesn't require additional bytecode attributes, it breaks completely existing tooling that parses a module-info because of the same constraints explained for the previous approach.<br></li></ul><div>In conclusion, while my proposed implementation is fully backwards compatible, it introduces two new bytecode attributes.<br></div><div><br></div><div><b>Public API changes<br></b></div><div>All changes are backwards-compatible, but I've included some reasoning on some design choices I made.<b><br></b><b>javax.lang.model.element.ModuleElement$Directive</b></div><div><ul><li>Implement AnnotatedConstruct to support annotations during compile-time processing</li><li>Directive does not currently implement Element and cannot do so in the future as it already defines a method named getKind which clashes with Element's getKind because of their different return types(DirectiveKind and ElementKind respectively). Implementing Element would also require ElementVisitor to implement DirectiveVisitor. I don't think that it's necessary for Directive to implement Element as it wasn't intended to do so when Java 9 was introduced, so I see no reason or backwards-compatible way to do so.</li></ul></div><div><b>java.lang.module.ModuleDescriptor</b></div><div><ul><li>Added a new sealed common class named Directive that Exports, Requires, Opens, Uses and Provides extend. This class contains an annotations() accessor to allow callers to access annotations</li><li>Added a new Uses class that represents uses directives. This introduces a slight backwards compatibility issue as an accessor named uses() already exists in ModuleDescriptor and it returns a Set<String> instead of a Set<Uses>. For now I added an accessor named used() that returns a Set<Uses>, but usedServices could be a better name. I don't think that changing uses() to return Set<Uses> is an option as that would break backwards compatibility and having an odd-named accessor shouldn't be that much of an issue if we find a fitting name.</li></ul></div></div></div></div></div></div></div></div>