48 * Utility class to extend a module-info.class with additional attributes.
49 */
50
51 public final class ModuleInfoExtender {
52
53 // the input stream to read the original module-info.class
54 private final InputStream in;
55
56 // the packages in the ModulePackages attribute
57 private Set<String> packages;
58
59 // the value for the module version in the Module attribute
60 private Version version;
61
62 // the value of the ModuleMainClass attribute
63 private String mainClass;
64
65 // the values for the ModuleTarget attribute
66 private String osName;
67 private String osArch;
68 private String osVersion;
69
70 // the hashes for the ModuleHashes attribute
71 private ModuleHashes hashes;
72
73 // the value of the ModuleResolution attribute
74 private ModuleResolution moduleResolution;
75
76 private ModuleInfoExtender(InputStream in) {
77 this.in = in;
78 }
79
80 /**
81 * Sets the packages for the ModulePackages attribute
82 *
83 * @apiNote This method does not check that the package names are legal
84 * package names or that the set of packages is a super set of the
85 * packages in the module.
86 */
87 public ModuleInfoExtender packages(Set<String> packages) {
88 this.packages = Collections.unmodifiableSet(packages);
94 */
95 public ModuleInfoExtender version(Version version) {
96 this.version = version;
97 return this;
98 }
99
100 /**
101 * Sets the value of the ModuleMainClass attribute.
102 *
103 * @apiNote This method does not check that the main class is a legal
104 * class name in a named package.
105 */
106 public ModuleInfoExtender mainClass(String mainClass) {
107 this.mainClass = mainClass;
108 return this;
109 }
110
111 /**
112 * Sets the values for the ModuleTarget attribute.
113 */
114 public ModuleInfoExtender targetPlatform(String osName,
115 String osArch,
116 String osVersion) {
117 this.osName = osName;
118 this.osArch = osArch;
119 this.osVersion = osVersion;
120 return this;
121 }
122
123 /**
124 * The ModuleHashes attribute will be emitted to the module-info with
125 * the hashes encapsulated in the given {@code ModuleHashes}
126 * object.
127 */
128 public ModuleInfoExtender hashes(ModuleHashes hashes) {
129 this.hashes = hashes;
130 return this;
131 }
132
133 /**
134 * Sets the value for the ModuleResolution attribute.
135 */
136 public ModuleInfoExtender moduleResolution(ModuleResolution mres) {
137 this.moduleResolution = mres;
138 return this;
139 }
186 }
187
188 /**
189 * Returns the bytes of the modified module-info.class.
190 * Once this method has been called then the Extender object should
191 * be discarded.
192 */
193 public byte[] toByteArray() throws IOException {
194 ClassWriter cw
195 = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
196
197 AttributeAddingClassVisitor cv
198 = new AttributeAddingClassVisitor(Opcodes.ASM5, cw);
199
200 ClassReader cr = new ClassReader(in);
201
202 if (packages != null)
203 cv.addAttribute(new ModulePackagesAttribute(packages));
204 if (mainClass != null)
205 cv.addAttribute(new ModuleMainClassAttribute(mainClass));
206 if (osName != null || osArch != null || osVersion != null)
207 cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
208 if (hashes != null)
209 cv.addAttribute(new ModuleHashesAttribute(hashes));
210 if (moduleResolution != null)
211 cv.addAttribute(new ModuleResolutionAttribute(moduleResolution.value()));
212
213 List<Attribute> attrs = new ArrayList<>();
214
215 // prototypes of attributes that should be parsed
216 attrs.add(new ModuleAttribute(version));
217 attrs.add(new ModulePackagesAttribute());
218 attrs.add(new ModuleMainClassAttribute());
219 attrs.add(new ModuleTargetAttribute());
220 attrs.add(new ModuleHashesAttribute());
221
222 cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
223
224 // add any attributes that didn't replace previous attributes
225 cv.finish();
226
227 return cw.toByteArray();
|
48 * Utility class to extend a module-info.class with additional attributes.
49 */
50
51 public final class ModuleInfoExtender {
52
53 // the input stream to read the original module-info.class
54 private final InputStream in;
55
56 // the packages in the ModulePackages attribute
57 private Set<String> packages;
58
59 // the value for the module version in the Module attribute
60 private Version version;
61
62 // the value of the ModuleMainClass attribute
63 private String mainClass;
64
65 // the values for the ModuleTarget attribute
66 private String osName;
67 private String osArch;
68
69 // the hashes for the ModuleHashes attribute
70 private ModuleHashes hashes;
71
72 // the value of the ModuleResolution attribute
73 private ModuleResolution moduleResolution;
74
75 private ModuleInfoExtender(InputStream in) {
76 this.in = in;
77 }
78
79 /**
80 * Sets the packages for the ModulePackages attribute
81 *
82 * @apiNote This method does not check that the package names are legal
83 * package names or that the set of packages is a super set of the
84 * packages in the module.
85 */
86 public ModuleInfoExtender packages(Set<String> packages) {
87 this.packages = Collections.unmodifiableSet(packages);
93 */
94 public ModuleInfoExtender version(Version version) {
95 this.version = version;
96 return this;
97 }
98
99 /**
100 * Sets the value of the ModuleMainClass attribute.
101 *
102 * @apiNote This method does not check that the main class is a legal
103 * class name in a named package.
104 */
105 public ModuleInfoExtender mainClass(String mainClass) {
106 this.mainClass = mainClass;
107 return this;
108 }
109
110 /**
111 * Sets the values for the ModuleTarget attribute.
112 */
113 public ModuleInfoExtender targetPlatform(String osName, String osArch) {
114 this.osName = osName;
115 this.osArch = osArch;
116 return this;
117 }
118
119 /**
120 * The ModuleHashes attribute will be emitted to the module-info with
121 * the hashes encapsulated in the given {@code ModuleHashes}
122 * object.
123 */
124 public ModuleInfoExtender hashes(ModuleHashes hashes) {
125 this.hashes = hashes;
126 return this;
127 }
128
129 /**
130 * Sets the value for the ModuleResolution attribute.
131 */
132 public ModuleInfoExtender moduleResolution(ModuleResolution mres) {
133 this.moduleResolution = mres;
134 return this;
135 }
182 }
183
184 /**
185 * Returns the bytes of the modified module-info.class.
186 * Once this method has been called then the Extender object should
187 * be discarded.
188 */
189 public byte[] toByteArray() throws IOException {
190 ClassWriter cw
191 = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
192
193 AttributeAddingClassVisitor cv
194 = new AttributeAddingClassVisitor(Opcodes.ASM5, cw);
195
196 ClassReader cr = new ClassReader(in);
197
198 if (packages != null)
199 cv.addAttribute(new ModulePackagesAttribute(packages));
200 if (mainClass != null)
201 cv.addAttribute(new ModuleMainClassAttribute(mainClass));
202 if (osName != null || osArch != null)
203 cv.addAttribute(new ModuleTargetAttribute(osName, osArch));
204 if (hashes != null)
205 cv.addAttribute(new ModuleHashesAttribute(hashes));
206 if (moduleResolution != null)
207 cv.addAttribute(new ModuleResolutionAttribute(moduleResolution.value()));
208
209 List<Attribute> attrs = new ArrayList<>();
210
211 // prototypes of attributes that should be parsed
212 attrs.add(new ModuleAttribute(version));
213 attrs.add(new ModulePackagesAttribute());
214 attrs.add(new ModuleMainClassAttribute());
215 attrs.add(new ModuleTargetAttribute());
216 attrs.add(new ModuleHashesAttribute());
217
218 cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
219
220 // add any attributes that didn't replace previous attributes
221 cv.finish();
222
223 return cw.toByteArray();
|