2525import java .util .HashMap ;
2626import java .util .List ;
2727import java .util .Map ;
28+ import java .util .Objects ;
2829import java .util .jar .JarEntry ;
2930import java .util .jar .JarOutputStream ;
3031import org .apache .maven .plugins .shade .relocation .Relocator ;
3738 * and entries. This is used during shading to prevent conflicts between the shaded and unshaded
3839 * versions of the same library.
3940 *
40- * <p>The prefix {@code e1723a08afd7bca35570fd31a7656f59.} is added to:
41+ * <p>A unique shading prefix is added to:
4142 *
4243 * <ul>
4344 * <li>Service file names (e.g., META-INF/services/MyService becomes
44- * META-INF/services/e1723a08afd7bca35570fd31a7656f59. MyService)
45+ * META-INF/services/{@code <prefix>} MyService)
4546 * <li>Service implementation class names within the files
4647 * </ul>
4748 *
49+ * <p>The prefix is configured by the Maven Shade plugin via the {@code <prefix>}
50+ * element; it is generated at build time so that each build uses a fresh
51+ * namespace. The default prefix is retained for backwards compatibility when
52+ * no prefix is configured.
53+ *
4854 * <p>This class is used during the Maven build process and is not used at runtime.
4955 */
5056public class CustomServiceTransformer implements ResourceTransformer {
5157
58+ /**
59+ * Default prefix to add to service names and entries when none is configured.
60+ */
61+ private static final String DEFAULT_PREFIX = "e1723a08afd7bca35570fd31a7656f59." ;
62+
5263 /**
5364 * Prefix to add to service names and entries.
5465 */
55- private static final String PREFIX = "e1723a08afd7bca35570fd31a7656f59." ;
66+ private String prefix = DEFAULT_PREFIX ;
5667
5768 /**
5869 * META-INF services directory path.
@@ -73,6 +84,15 @@ public CustomServiceTransformer() {
7384 // Intentionally empty
7485 }
7586
87+ /**
88+ * Sets the prefix to add to service names and entries.
89+ *
90+ * @param prefix the prefix to add, must not be {@code null}
91+ */
92+ public void setPrefix (String prefix ) {
93+ this .prefix = Objects .requireNonNull (prefix );
94+ }
95+
7696 /**
7797 * Determines whether the resource is a META-INF/services file that should be transformed.
7898 *
@@ -105,7 +125,7 @@ public void processResource(String resource, InputStream is, List<Relocator> rel
105125 .filter (line -> !line .isEmpty ())
106126 .map (line -> {
107127 // Avoid double prefixing
108- return line .startsWith (PREFIX ) ? line : PREFIX + line ;
128+ return line .startsWith (prefix ) ? line : prefix + line ;
109129 })
110130 .forEach (line -> {
111131 if (!entries .contains (line )) {
@@ -129,7 +149,7 @@ public boolean hasTransformedResource() {
129149 * Writes the collected service entries to the JAR with prefixed filenames and entries.
130150 *
131151 * <p>Each service file is written to a new path where the service name is prefixed with
132- * {@value #PREFIX }, and all implementation class entries within the file are also prefixed.
152+ * {@link #prefix }, and all implementation class entries within the file are also prefixed.
133153 *
134154 * @param jos the JAR output stream to write to
135155 * @throws IOException if writing to the JAR fails
@@ -140,7 +160,7 @@ public void modifyOutputStream(JarOutputStream jos) throws IOException {
140160 String originalPath = entry .getKey ();
141161 List <String > lines = entry .getValue ();
142162
143- String newPath = SERVICES_DIR + PREFIX + originalPath .substring (SERVICES_DIR .length ());
163+ String newPath = SERVICES_DIR + prefix + originalPath .substring (SERVICES_DIR .length ());
144164
145165 jos .putNextEntry (new JarEntry (newPath ));
146166 for (String line : lines ) {
0 commit comments