1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.shade.resource;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.Arrays;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.jar.Attributes;
27 import java.util.jar.JarEntry;
28 import java.util.jar.JarFile;
29 import java.util.jar.JarOutputStream;
30 import java.util.jar.Manifest;
31
32 import org.apache.maven.plugins.shade.relocation.Relocator;
33
34
35
36
37
38
39
40
41
42 public class ManifestResourceTransformer extends AbstractCompatibilityTransformer {
43 private final List<String> defaultAttributes =
44 Arrays.asList("Export-Package", "Import-Package", "Provide-Capability", "Require-Capability");
45
46
47 private String mainClass;
48
49 private Map<String, Object> manifestEntries;
50
51 private List<String> additionalAttributes;
52
53
54 private boolean manifestDiscovered;
55
56 private Manifest manifest;
57
58 private long time = Long.MIN_VALUE;
59
60 private String shade;
61
62 public void setMainClass(String mainClass) {
63 this.mainClass = mainClass;
64 }
65
66 public void setManifestEntries(Map<String, Object> manifestEntries) {
67 this.manifestEntries = manifestEntries;
68 }
69
70 public void setAdditionalAttributes(List<String> additionalAttributes) {
71 this.additionalAttributes = additionalAttributes;
72 }
73
74 @Override
75 public boolean canTransformResource(String resource) {
76 return JarFile.MANIFEST_NAME.equalsIgnoreCase(resource);
77 }
78
79 @Override
80 public void processResource(String resource, InputStream is, List<Relocator> relocators, long time)
81 throws IOException {
82
83
84
85 if (!manifestDiscovered) {
86 manifest = new Manifest(is);
87
88 if (relocators != null && !relocators.isEmpty()) {
89 final Attributes attributes = manifest.getMainAttributes();
90
91 for (final String attribute : defaultAttributes) {
92 final String attributeValue = attributes.getValue(attribute);
93 if (attributeValue != null) {
94 String newValue = relocate(attributeValue, relocators);
95 attributes.putValue(attribute, newValue);
96 }
97 }
98
99 if (additionalAttributes != null) {
100 for (final String attribute : additionalAttributes) {
101 final String attributeValue = attributes.getValue(attribute);
102 if (attributeValue != null) {
103 String newValue = relocate(attributeValue, relocators);
104 attributes.putValue(attribute, newValue);
105 }
106 }
107 }
108 }
109
110 manifestDiscovered = true;
111
112 if (time > this.time) {
113 this.time = time;
114 }
115 }
116 }
117
118 @Override
119 public boolean hasTransformedResource() {
120 return true;
121 }
122
123 @Override
124 public void modifyOutputStream(JarOutputStream jos) throws IOException {
125
126 if (manifest == null) {
127 manifest = new Manifest();
128 }
129
130 Attributes attributes = manifest.getMainAttributes();
131
132 if (mainClass != null) {
133 attributes.put(Attributes.Name.MAIN_CLASS, mainClass);
134 }
135
136 if (manifestEntries != null) {
137 for (Map.Entry<String, Object> entry : manifestEntries.entrySet()) {
138 if (entry.getValue() == null) {
139 attributes.remove(new Attributes.Name(entry.getKey()));
140 } else {
141 attributes.put(new Attributes.Name(entry.getKey()), entry.getValue());
142 }
143 }
144 }
145
146 JarEntry jarEntry = new JarEntry(JarFile.MANIFEST_NAME);
147 jarEntry.setTime(time);
148 jos.putNextEntry(jarEntry);
149 manifest.write(jos);
150 }
151
152 private String relocate(String originalValue, List<Relocator> relocators) {
153 String newValue = originalValue;
154 for (Relocator relocator : relocators) {
155 String value;
156 do {
157 value = newValue;
158 newValue = relocator.relocateClass(value);
159 } while (!value.equals(newValue));
160 }
161 return newValue;
162 }
163
164
165
166
167
168
169 public void setForShade(String shade) {
170 this.shade = shade;
171 }
172
173 public boolean isForShade(String shade) {
174 return isUsedForDefaultShading() || this.shade.equalsIgnoreCase(shade);
175 }
176
177 public boolean isUsedForDefaultShading() {
178 return this.shade == null || this.shade.isEmpty();
179 }
180 }