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.nio.charset.StandardCharsets;
24 import java.util.HashMap;
25 import java.util.LinkedHashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Scanner;
29 import java.util.Set;
30 import java.util.jar.JarEntry;
31 import java.util.jar.JarOutputStream;
32
33 import org.apache.commons.io.IOUtils;
34 import org.apache.maven.plugins.shade.relocation.Relocator;
35
36
37
38
39
40
41
42
43 public class ServicesResourceTransformer extends AbstractCompatibilityTransformer {
44 private static final String SERVICES_PATH = "META-INF/services";
45
46 private final Map<String, Set<String>> serviceEntries = new HashMap<>();
47
48 private long time = Long.MIN_VALUE;
49
50 @Override
51 public boolean canTransformResource(String resource) {
52 return resource.startsWith(SERVICES_PATH);
53 }
54
55 @Override
56 public void processResource(String resource, InputStream is, final List<Relocator> relocators, long time)
57 throws IOException {
58 resource = resource.substring(SERVICES_PATH.length() + 1);
59 for (Relocator relocator : relocators) {
60 if (relocator.canRelocateClass(resource)) {
61 resource = relocator.relocateClass(resource);
62 break;
63 }
64 }
65 resource = SERVICES_PATH + '/' + resource;
66
67 Set<String> out = serviceEntries.computeIfAbsent(resource, k -> new LinkedHashSet<>());
68
69 Scanner scanner = new Scanner(is, StandardCharsets.UTF_8.name());
70 while (scanner.hasNextLine()) {
71 String relContent = scanner.nextLine();
72 for (Relocator relocator : relocators) {
73 if (relocator.canRelocateClass(relContent)) {
74 relContent = relocator.applyToSourceContent(relContent);
75 }
76 }
77 out.add(relContent);
78 }
79
80 if (time > this.time) {
81 this.time = time;
82 }
83 }
84
85 @Override
86 public boolean hasTransformedResource() {
87 return !serviceEntries.isEmpty();
88 }
89
90 @Override
91 public void modifyOutputStream(JarOutputStream jos) throws IOException {
92 for (Map.Entry<String, Set<String>> entry : serviceEntries.entrySet()) {
93 String key = entry.getKey();
94 Set<String> data = entry.getValue();
95
96 JarEntry jarEntry = new JarEntry(key);
97 jarEntry.setTime(time);
98 jos.putNextEntry(jarEntry);
99
100 IOUtils.writeLines(data, "\n", jos, StandardCharsets.UTF_8);
101 jos.flush();
102 data.clear();
103 }
104 }
105 }