53 // the input stream to read the original module-info.class 54 private final InputStream in; 55 56 // the packages in the Packages attribute 57 private Set<String> packages; 58 59 // the value of the Version attribute 60 private Version version; 61 62 // the value of the MainClass attribute 63 private String mainClass; 64 65 // the values for the TargetPlatform attribute 66 private String osName; 67 private String osArch; 68 private String osVersion; 69 70 // the hashes for the Hashes attribute 71 private ModuleHashes hashes; 72 73 private ModuleInfoExtender(InputStream in) { 74 this.in = in; 75 } 76 77 /** 78 * Sets the set of packages for the Packages attribute 79 */ 80 public ModuleInfoExtender packages(Set<String> packages) { 81 this.packages = Collections.unmodifiableSet(packages); 82 return this; 83 } 84 85 /** 86 * Sets the value of the Version attribute. 87 */ 88 public ModuleInfoExtender version(Version version) { 89 this.version = version; 90 return this; 91 } 92 104 public ModuleInfoExtender targetPlatform(String osName, 105 String osArch, 106 String osVersion) { 107 this.osName = osName; 108 this.osArch = osArch; 109 this.osVersion = osVersion; 110 return this; 111 } 112 113 /** 114 * The Hashes attribute will be emitted to the module-info with 115 * the hashes encapsulated in the given {@code ModuleHashes} 116 * object. 117 */ 118 public ModuleInfoExtender hashes(ModuleHashes hashes) { 119 this.hashes = hashes; 120 return this; 121 } 122 123 /** 124 * A ClassVisitor that supports adding class file attributes. If an 125 * attribute already exists then the first occurence of the attribute 126 * is replaced. 127 */ 128 private static class AttributeAddingClassVisitor extends ClassVisitor { 129 private Map<String, Attribute> attrs = new HashMap<>(); 130 131 AttributeAddingClassVisitor(int api, ClassVisitor cv) { 132 super(api, cv); 133 } 134 135 void addAttribute(Attribute attr) { 136 attrs.put(attr.type, attr); 137 } 138 139 @Override 140 public void visitAttribute(Attribute attr) { 141 String name = attr.type; 142 Attribute replacement = attrs.get(name); 143 if (replacement != null) { 166 // emit to the output stream 167 out.write(toByteArray()); 168 } 169 170 /** 171 * Returns the bytes of the modified module-info.class. 172 * Once this method has been called then the Extender object should 173 * be discarded. 174 */ 175 public byte[] toByteArray() throws IOException { 176 ClassWriter cw 177 = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); 178 179 AttributeAddingClassVisitor cv 180 = new AttributeAddingClassVisitor(Opcodes.ASM5, cw); 181 182 ClassReader cr = new ClassReader(in); 183 184 if (packages != null) 185 cv.addAttribute(new ModulePackagesAttribute(packages)); 186 if (version != null) 187 cv.addAttribute(new ModuleVersionAttribute(version)); 188 if (mainClass != null) 189 cv.addAttribute(new ModuleMainClassAttribute(mainClass)); 190 if (osName != null || osArch != null || osVersion != null) 191 cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion)); 192 if (hashes != null) 193 cv.addAttribute(new ModuleHashesAttribute(hashes)); 194 195 List<Attribute> attrs = new ArrayList<>(); 196 197 // prototypes of attributes that should be parsed 198 attrs.add(new ModuleAttribute()); 199 attrs.add(new ModulePackagesAttribute()); 200 attrs.add(new ModuleVersionAttribute()); 201 attrs.add(new ModuleMainClassAttribute()); 202 attrs.add(new ModuleTargetAttribute()); 203 attrs.add(new ModuleHashesAttribute()); 204 205 cr.accept(cv, attrs.toArray(new Attribute[0]), 0); 206 207 // add any attributes that didn't replace previous attributes 208 cv.finish(); 209 210 return cw.toByteArray(); 211 } 212 213 /** 214 * Returns an {@code Extender} that may be used to add additional 215 * attributes to the module-info.class read from the given input 216 * stream. 217 */ 218 public static ModuleInfoExtender newExtender(InputStream in) { 219 return new ModuleInfoExtender(in); 220 } | 53 // the input stream to read the original module-info.class 54 private final InputStream in; 55 56 // the packages in the Packages attribute 57 private Set<String> packages; 58 59 // the value of the Version attribute 60 private Version version; 61 62 // the value of the MainClass attribute 63 private String mainClass; 64 65 // the values for the TargetPlatform attribute 66 private String osName; 67 private String osArch; 68 private String osVersion; 69 70 // the hashes for the Hashes 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 set of packages for the Packages attribute 82 */ 83 public ModuleInfoExtender packages(Set<String> packages) { 84 this.packages = Collections.unmodifiableSet(packages); 85 return this; 86 } 87 88 /** 89 * Sets the value of the Version attribute. 90 */ 91 public ModuleInfoExtender version(Version version) { 92 this.version = version; 93 return this; 94 } 95 107 public ModuleInfoExtender targetPlatform(String osName, 108 String osArch, 109 String osVersion) { 110 this.osName = osName; 111 this.osArch = osArch; 112 this.osVersion = osVersion; 113 return this; 114 } 115 116 /** 117 * The Hashes attribute will be emitted to the module-info with 118 * the hashes encapsulated in the given {@code ModuleHashes} 119 * object. 120 */ 121 public ModuleInfoExtender hashes(ModuleHashes hashes) { 122 this.hashes = hashes; 123 return this; 124 } 125 126 /** 127 * Sets the value for the ModuleResolution attribute. 128 */ 129 public ModuleInfoExtender moduleResolution(ModuleResolution mres) { 130 this.moduleResolution = mres; 131 return this; 132 } 133 134 /** 135 * A ClassVisitor that supports adding class file attributes. If an 136 * attribute already exists then the first occurence of the attribute 137 * is replaced. 138 */ 139 private static class AttributeAddingClassVisitor extends ClassVisitor { 140 private Map<String, Attribute> attrs = new HashMap<>(); 141 142 AttributeAddingClassVisitor(int api, ClassVisitor cv) { 143 super(api, cv); 144 } 145 146 void addAttribute(Attribute attr) { 147 attrs.put(attr.type, attr); 148 } 149 150 @Override 151 public void visitAttribute(Attribute attr) { 152 String name = attr.type; 153 Attribute replacement = attrs.get(name); 154 if (replacement != null) { 177 // emit to the output stream 178 out.write(toByteArray()); 179 } 180 181 /** 182 * Returns the bytes of the modified module-info.class. 183 * Once this method has been called then the Extender object should 184 * be discarded. 185 */ 186 public byte[] toByteArray() throws IOException { 187 ClassWriter cw 188 = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); 189 190 AttributeAddingClassVisitor cv 191 = new AttributeAddingClassVisitor(Opcodes.ASM5, cw); 192 193 ClassReader cr = new ClassReader(in); 194 195 if (packages != null) 196 cv.addAttribute(new ModulePackagesAttribute(packages)); 197 if (mainClass != null) 198 cv.addAttribute(new ModuleMainClassAttribute(mainClass)); 199 if (osName != null || osArch != null || osVersion != null) 200 cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion)); 201 if (hashes != null) 202 cv.addAttribute(new ModuleHashesAttribute(hashes)); 203 if (moduleResolution != null) 204 cv.addAttribute(new ModuleResolutionAttribute(moduleResolution.value())); 205 206 List<Attribute> attrs = new ArrayList<>(); 207 208 // prototypes of attributes that should be parsed 209 attrs.add(new ModuleAttribute(version)); 210 attrs.add(new ModulePackagesAttribute()); 211 attrs.add(new ModuleMainClassAttribute()); 212 attrs.add(new ModuleTargetAttribute()); 213 attrs.add(new ModuleHashesAttribute()); 214 215 cr.accept(cv, attrs.toArray(new Attribute[0]), 0); 216 217 // add any attributes that didn't replace previous attributes 218 cv.finish(); 219 220 return cw.toByteArray(); 221 } 222 223 /** 224 * Returns an {@code Extender} that may be used to add additional 225 * attributes to the module-info.class read from the given input 226 * stream. 227 */ 228 public static ModuleInfoExtender newExtender(InputStream in) { 229 return new ModuleInfoExtender(in); 230 } |