Skip to content

Commit

Permalink
[MSHADE-350] Enable ManifestResourceTransformer to rewrite the manife…
Browse files Browse the repository at this point in the history
…st with relocations
  • Loading branch information
rfscholte committed Feb 8, 2020
1 parent 799e02a commit 0aa56da
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 3 deletions.
Expand Up @@ -19,10 +19,9 @@
* under the License.
*/

import org.apache.maven.plugins.shade.relocation.Relocator;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
Expand All @@ -31,6 +30,8 @@
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

import org.apache.maven.plugins.shade.relocation.Relocator;

/**
* A resource processor that allows the arbitrary addition of attributes to
* the first MANIFEST.MF that is found in the set of JARs being processed, or
Expand All @@ -42,17 +43,39 @@
public class ManifestResourceTransformer
implements ResourceTransformer
{

private final List<String> defaultAttributes = Arrays.asList( "Export-Package",
"Import-Package",
"Provide-Capability",
"Require-Capability" );

// Configuration
private String mainClass;

private Map<String, Object> manifestEntries;

private List<String> additionalAttributes;

// Fields
private boolean manifestDiscovered;

private Manifest manifest;

public void setMainClass( String mainClass )
{
this.mainClass = mainClass;
}

public void setManifestEntries( Map<String, Object> manifestEntries )
{
this.manifestEntries = manifestEntries;
}

public void setAdditionalAttributes( List<String> additionalAttributes )
{
this.additionalAttributes = additionalAttributes;
}

@Override
public boolean canTransformResource( String resource )
{
if ( JarFile.MANIFEST_NAME.equalsIgnoreCase( resource ) )
Expand All @@ -63,6 +86,7 @@ public boolean canTransformResource( String resource )
return false;
}

@Override
public void processResource( String resource, InputStream is, List<Relocator> relocators )
throws IOException
{
Expand All @@ -72,15 +96,46 @@ public void processResource( String resource, InputStream is, List<Relocator> re
if ( !manifestDiscovered )
{
manifest = new Manifest( is );

if ( relocators != null && !relocators.isEmpty() )
{
final Attributes attributes = manifest.getMainAttributes();

for ( final String attribute : defaultAttributes )
{
final String attributeValue = attributes.getValue( attribute );
if ( attributeValue != null )
{
String newValue = relocate( attributeValue, relocators );
attributes.putValue( attribute, newValue );
}
}

if ( additionalAttributes != null )
{
for ( final String attribute : additionalAttributes )
{
final String attributeValue = attributes.getValue( attribute );
if ( attributeValue != null )
{
String newValue = relocate( attributeValue, relocators );
attributes.putValue( attribute, newValue );
}
}
}
}

manifestDiscovered = true;
}
}

@Override
public boolean hasTransformedResource()
{
return true;
}

@Override
public void modifyOutputStream( JarOutputStream jos )
throws IOException
{
Expand Down Expand Up @@ -108,4 +163,20 @@ public void modifyOutputStream( JarOutputStream jos )
jos.putNextEntry( new JarEntry( JarFile.MANIFEST_NAME ) );
manifest.write( jos );
}

private String relocate( String originalValue, List<Relocator> relocators )
{
String newValue = originalValue;
for ( Relocator relocator : relocators )
{
String value;
do
{
value = newValue;
newValue = relocator.relocateClass( value );
}
while ( !value.equals( newValue ) );
}
return newValue;
}
}
12 changes: 12 additions & 0 deletions src/site/apt/examples/resource-transformers.apt.vm
Expand Up @@ -387,6 +387,18 @@ Transformers in <<<org.apache.maven.plugins.shade.resource>>>

* the <<<X-Compile-Target-JDK>>> entry to the value of the <<<maven.compile.target>>> property.

By default the <<<ManifestResourceTransformer>>> will relocate the following attributes:

* Export-Package

* Import-Package

* Provide-Capability

* Require-Capability

With <<<additionalAttributes>>> you can specify the attributes that need to be relocated too.


+-----
<project>
Expand Down
@@ -0,0 +1,170 @@
package org.apache.maven.plugins.shade.resource;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import static org.junit.Assert.assertEquals;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

import org.apache.maven.plugins.shade.relocation.Relocator;
import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
import org.junit.Before;
import org.junit.Test;

public class ManifestResourceTransformerTest
{
private ManifestResourceTransformer transformer;

@Before
public void setUp()
{
transformer = new ManifestResourceTransformer();
}

@Test
public void rewriteDefaultAttributes() throws Exception
{
final Manifest manifest = new Manifest();
final Attributes attributes = manifest.getMainAttributes();
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
attributes.putValue("Export-Package",
"javax.decorator;version=\"2.0\";uses:=\"javax.enterprise.inject\"," +
"javax.enterprise.context;version=\"2.0\";uses:=\"javax.enterprise.util,javax.inject\"");
attributes.putValue("Import-Package",
"javax.el,javax.enterprise.context;version=\"[2.0,3)\"");
attributes.putValue("Provide-Capability",
"osgi.contract;osgi.contract=JavaCDI;uses:=\"" +
"javax.enterprise.context,javax.enterprise.context.spi,javax.enterprise.context.control," +
"javax.enterprise.util,javax.enterprise.inject,javax.enterprise.inject.spi," +
"javax.enterprise.inject.spi.configurator,javax.enterprise.inject.literal," +
"javax.enterprise.inject.se,javax.enterprise.event,javax.decorator\";" +
"version:List<Version>=\"2.0,1.2,1.1,1.0\"");
attributes.putValue("Require-Capability",
"osgi.serviceloader;" +
"filter:=\"(osgi.serviceloader=javax.enterprise.inject.se.SeContainerInitializer)\";" +
"cardinality:=multiple," +
"osgi.serviceloader;" +
"filter:=\"(osgi.serviceloader=javax.enterprise.inject.spi.CDIProvider)\";" +
"cardinality:=multiple,osgi.extender;" +
"filter:=\"(osgi.extender=osgi.serviceloader.processor)\"," +
"osgi.contract;osgi.contract=JavaEL;filter:=\"(&(osgi.contract=JavaEL)(version=2.2.0))\"," +
"osgi.contract;osgi.contract=JavaInterceptor;" +
"filter:=\"(&(osgi.contract=JavaInterceptor)(version=1.2.0))\"," +
"osgi.contract;osgi.contract=JavaInject;" +
"filter:=\"(&(osgi.contract=JavaInject)(version=1.0.0))\"," +
"osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=1.8))\"");

List<Relocator> relocators =
Collections.<Relocator>singletonList( new SimpleRelocator( "javax", "jakarta",
Collections.<String>emptyList(),
Collections.<String>emptyList() ) );

final ByteArrayOutputStream out = transform( manifest, relocators );

try ( final JarInputStream jis = new JarInputStream( new ByteArrayInputStream( out.toByteArray() ) ) )
{
final Attributes attrs = jis.getManifest().getMainAttributes();
assertEquals(
"jakarta.decorator;version=\"2.0\";uses:=\"jakarta.enterprise.inject\"," +
"jakarta.enterprise.context;version=\"2.0\";uses:=\"jakarta.enterprise.util," +
"jakarta.inject\"",
attrs.getValue("Export-Package"));
assertEquals("jakarta.el,jakarta.enterprise.context;version=\"[2.0,3)\"",
attrs.getValue("Import-Package"));
assertEquals(
"osgi.contract;osgi.contract=JavaCDI;" +
"uses:=\"jakarta.enterprise.context," +
"jakarta.enterprise.context.spi,jakarta.enterprise.context.control," +
"jakarta.enterprise.util,jakarta.enterprise.inject,jakarta.enterprise.inject.spi," +
"jakarta.enterprise.inject.spi.configurator,jakarta.enterprise.inject.literal," +
"jakarta.enterprise.inject.se,jakarta.enterprise.event," +
"jakarta.decorator\";version:List<Version>=\"2.0,1.2,1.1,1.0\"",
attrs.getValue("Provide-Capability"));
assertEquals(
"osgi.serviceloader;" +
"filter:=\"(osgi.serviceloader=jakarta.enterprise.inject.se.SeContainerInitializer)\";" +
"cardinality:=multiple,osgi.serviceloader;" +
"filter:=\"(osgi.serviceloader=jakarta.enterprise.inject.spi.CDIProvider)\";" +
"cardinality:=multiple,osgi.extender;" +
"filter:=\"(osgi.extender=osgi.serviceloader.processor)\"," +
"osgi.contract;osgi.contract=JavaEL;filter:=\"(&(osgi.contract=JavaEL)(version=2.2.0))\"," +
"osgi.contract;osgi.contract=JavaInterceptor;" +
"filter:=\"(&(osgi.contract=JavaInterceptor)(version=1.2.0))\"," +
"osgi.contract;osgi.contract=JavaInject;" +
"filter:=\"(&(osgi.contract=JavaInject)(version=1.0.0))\"," +
"osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=1.8))\"",
attrs.getValue("Require-Capability"));
}
}

@Test
public void rewriteAdditionalAttributes() throws Exception
{
final Manifest manifest = new Manifest();
final Attributes attributes = manifest.getMainAttributes();
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
attributes.putValue("description-custom",
"This jar uses javax packages");

List<Relocator> relocators =
Collections.<Relocator>singletonList( new SimpleRelocator( "javax", "jakarta",
Collections.<String>emptyList(),
Collections.<String>emptyList() ) );

transformer.setAdditionalAttributes( Arrays.asList("description-custom", "attribute-unknown") );
final ByteArrayOutputStream out = transform( manifest, relocators );

try ( final JarInputStream jis = new JarInputStream( new ByteArrayInputStream( out.toByteArray() ) ) )
{
final Attributes attrs = jis.getManifest().getMainAttributes();
assertEquals( "This jar uses jakarta packages", attrs.getValue( "description-custom" ) );
}
}

private ByteArrayOutputStream transform( final Manifest manifest, List<Relocator> relocators )
throws IOException
{
final ByteArrayOutputStream mboas = new ByteArrayOutputStream();
try ( final OutputStream mos = mboas )
{
manifest.write( mos );
}
transformer.processResource( JarFile.MANIFEST_NAME, new ByteArrayInputStream( mboas.toByteArray() ),
relocators );

final ByteArrayOutputStream out = new ByteArrayOutputStream();
try ( final JarOutputStream jarOutputStream = new JarOutputStream( out ) )
{
transformer.modifyOutputStream( jarOutputStream );
}
return out;
}
}

0 comments on commit 0aa56da

Please sign in to comment.