How to stop maven-shade-plugin from blocking java.util.ServiceLoader initialization of opensaml-impl types

吃可爱长大的小学妹 提交于 2019-12-10 09:45:52

问题


When using OpenSAML 3, you must first load components from the opensaml-saml-impl artifact with the following line of code:

InitializationService.initialize();

This uses java.util.ServiceLoader to load any type which implements Initializer.

When I write a test and run it with mvn integration-test, this works fine, and I can see that everything has loaded:

Assert.assertTrue(
    XMLObjectProviderRegistrySupport
        .getUnmarshallerFactory()
        .getUnmarshallers()
        .size() > 400);

However, my project uses maven-shade-plugin. The condition above is not true if I package the code into an uber-jar:

mvn package
java -jar /path/to/my.jar

In this case I observe that only 9 unmarshallers have loaded (those in opensaml-core, as opposed to those in opensaml-saml-impl. However, when I watch the output of mvn package, I can see that the types are included in the shaded jar:

[INFO] Including org.opensaml:opensaml-saml-impl:jar:3.2.0 in the shaded jar.
[INFO] Including org.opensaml:opensaml-profile-api:jar:3.2.0 in the shaded jar.
[INFO] Including org.opensaml:opensaml-messaging-api:jar:3.2.0 in the shaded jar.
[INFO] Including org.opensaml:opensaml-saml-api:jar:3.2.0 in the shaded jar.
[INFO] Including org.opensaml:opensaml-xmlsec-api:jar:3.2.0 in the shaded jar.
[INFO] Including org.opensaml:opensaml-soap-api:jar:3.2.0 in the shaded jar.
[INFO] Including org.opensaml:opensaml-storage-api:jar:3.2.0 in the shaded jar.
[INFO] Including org.opensaml:opensaml-security-impl:jar:3.2.0 in the shaded jar.
[INFO] Including org.opensaml:opensaml-security-api:jar:3.2.0 in the shaded jar.

I can work around this issue with the following dumb code:

private static void initManuallyInsteadOfWithInitializationServiceSoThatMavenShadePluginDoesNotRemoveThem() throws InitializationException {
    new ApacheXMLSecurityInitializer().init();
    new ClientTLSValidationConfiguratonInitializer().init();
    new GlobalAlgorithmRegistryInitializer().init();
    new GlobalParserPoolInitializer().init();
    new GlobalSecurityConfigurationInitializer().init();
    new JavaCryptoValidationInitializer().init();
    new SAMLConfigurationInitializer().init();
    new org.opensaml.core.xml.config.XMLObjectProviderInitializer().init();
    new org.opensaml.xmlsec.config.XMLObjectProviderInitializer().init();
    new XMLObjectProviderInitializer().init();
}

This utterly defeats the point of the plugin system, but it does allow my program to function.

For reference, here's the relevant bits of pom.xml:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.3</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer
                            implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <manifestEntries>
                            <Main-Class>com.example.Server</Main-Class>
                        </manifestEntries>
                    </transformer>
                    <transformer
                            implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/services/io.vertx.core.spi.VerticleFactory</resource>
                    </transformer>
                </transformers>
                <artifactSet>
                </artifactSet>
                <outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar
                </outputFile>
                <filters>
                    <filter>
                        <!-- Fix java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
                             when server starts inside Docker container due to inclusion of OpenSAML and use of
                             uber-jar / maven-shade-plugin. See http://stackoverflow.com/a/6743609 -->
                        <artifact>*:*</artifact>
                        <excludes>
                            <exclude>META-INF/*.SF</exclude>
                            <exclude>META-INF/*.DSA</exclude>
                            <exclude>META-INF/*.RSA</exclude>
                        </excludes>
                    </filter>
                    <filter>
                        <!-- This was one of my attempts to fix the problem.
                             Unfortunately, it doesn't work. -->
                        <artifact>org.opensaml:opensaml-saml-impl</artifact>
                        <includes>
                            <include>**</include>
                        </includes>
                    </filter>
                </filters>
            </configuration>
        </execution>
    </executions>
</plugin>

回答1:


When you're using the Maven Shade Plugin with dependencies using the ServiceLoader API, you should use the ServicesResourceTransformer, which is dedicated to merge together the files. If the plugin is relocating classes, it will also relocate properly the class names in each service file, unlike the AppendingTransformer.

So you can just replace your current AppendingTransformer with

<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>

It will make sure that every service file under META-INF/services of your dependencies are merged, without the need to declare them all.



来源:https://stackoverflow.com/questions/42540485/how-to-stop-maven-shade-plugin-from-blocking-java-util-serviceloader-initializat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!