diff --git a/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java b/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java index a07b78b17fd..5837df040ff 100644 --- a/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java +++ b/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java @@ -17,10 +17,15 @@ import java.io.File; import java.io.IOException; import java.io.Writer; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -37,9 +42,6 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.file.ProjectLayout; import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.java.archives.Attributes; -import org.gradle.api.java.archives.ManifestException; -import org.gradle.api.java.archives.ManifestMergeSpec; import org.gradle.api.java.archives.internal.DefaultManifest; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; @@ -66,7 +68,6 @@ import aQute.lib.io.IO; import aQute.lib.strings.Strings; import aQute.lib.utf8properties.UTF8Properties; -import groovy.lang.Closure; /** * BundleTaskExtension for Gradle. @@ -100,7 +101,7 @@ public class BundleTaskExtension { private final ConfigurableFileCollection classpath; private final Provider bnd; private final MapProperty properties; - private final EffectiveManifest effectiveManifest; + private final Optional effectiveManifest; /** * The bndfile property. @@ -217,10 +218,15 @@ public BundleTaskExtension(org.gradle.api.tasks.bundling.Jar task) { properties = objects.mapProperty(String.class, Object.class) .convention(Maps.of("project", "__convention__")); // Wrap manifest - org.gradle.api.java.archives.Manifest manifest = task.getManifest(); - effectiveManifest = new EffectiveManifest(manifest); - if (manifest != null) { - task.setManifest(effectiveManifest); + org.gradle.api.java.archives.Manifest delegate = task.getManifest(); + if (delegate != null) { + EffectiveManifest em = new EffectiveManifest(delegate); + effectiveManifest = Optional.of(em); + org.gradle.api.java.archives.Manifest manifest = (org.gradle.api.java.archives.Manifest) Proxy + .newProxyInstance(em.classLoader(), em.interfaces(), em); + task.setManifest(manifest); + } else { + effectiveManifest = Optional.empty(); } // need to programmatically add to inputs since @InputFiles in a // extension is not processed @@ -515,7 +521,8 @@ public void execute(Task t) { long now = System.currentTimeMillis(); archiveFile.setLastModified(now); // Set effective manifest to generated manifest - effectiveManifest.setEffectiveManifest(builtJar.getManifest()); + Manifest manifest = builtJar.getManifest(); + effectiveManifest.ifPresent(em -> em.setEffectiveManifest(manifest)); logReport(builder, getTask().getLogger()); if (!builder.isOk()) { failTask("Bundle " + archiveFileName + " has errors", archiveFile); @@ -537,12 +544,14 @@ private boolean isEmpty(String header) { } } - static final class EffectiveManifest implements org.gradle.api.java.archives.Manifest { + static final class EffectiveManifest implements InvocationHandler { final org.gradle.api.java.archives.Manifest delegate; + final Class delegateClass; Manifest effectiveManifest; EffectiveManifest(org.gradle.api.java.archives.Manifest delegate) { this.delegate = delegate; + this.delegateClass = delegate.getClass(); this.effectiveManifest = null; } @@ -550,64 +559,61 @@ void setEffectiveManifest(Manifest effectiveManifest) { this.effectiveManifest = effectiveManifest; } - @Override - public org.gradle.api.java.archives.Manifest attributes(Map attributes) throws ManifestException { - delegate.attributes(attributes); - return this; + ClassLoader classLoader() { + return delegateClass.getClassLoader(); } - @Override - public org.gradle.api.java.archives.Manifest attributes(Map attributes, String sectionName) - throws ManifestException { - delegate.attributes(attributes, sectionName); - return this; + Class[] interfaces() { + return collectInterfaces(delegateClass, new LinkedHashSet<>()).toArray(new Class[0]); } - @Override - public org.gradle.api.java.archives.Manifest from(Object... mergePath) { - delegate.from(mergePath); - return this; - } - - @Override - public org.gradle.api.java.archives.Manifest from(Object mergePath, Closure closure) { - delegate.from(mergePath, closure); - return this; - } - - @Override - public org.gradle.api.java.archives.Manifest from(Object mergePath, Action action) { - delegate.from(mergePath, action); - return this; + private static Set> collectInterfaces(Class c, Set> found) { + while (c != null) { + for (Class i : c.getInterfaces()) { + if (found.add(i)) { + collectInterfaces(i, found); + } + } + c = c.getSuperclass(); + } + return found; } @Override - public Attributes getAttributes() { - return delegate.getAttributes(); - } + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String name = method.getName(); + Class[] parameterTypes = method.getParameterTypes(); + Class returnType = method.getReturnType(); - @Override - public org.gradle.api.java.archives.Manifest getEffectiveManifest() { Manifest effectiveManifest = this.effectiveManifest; - if (effectiveManifest == null) { - return delegate.getEffectiveManifest(); + if ((effectiveManifest != null) && name.equals("getEffectiveManifest") && (parameterTypes.length == 0)) { + org.gradle.api.java.archives.Manifest result = new DefaultManifest(null); + result.attributes(new AttributesMap(effectiveManifest.getMainAttributes())); + effectiveManifest.getEntries() + .forEach((section, attrs) -> result.attributes(new AttributesMap(attrs), section)); + return result; } - org.gradle.api.java.archives.Manifest result = new DefaultManifest(null); - result.attributes(new AttributesMap(effectiveManifest.getMainAttributes())); - effectiveManifest.getEntries() - .forEach((section, attrs) -> result.attributes(new AttributesMap(attrs), section)); - return result; - } - - @Override - public Map getSections() { - return delegate.getSections(); - } - @Override - public org.gradle.api.java.archives.Manifest writeTo(Object path) { - getEffectiveManifest().writeTo(path); - return this; + Method delegateMethod; + try { + delegateMethod = delegateClass.getMethod(name, parameterTypes); + } catch (NoSuchMethodException e) { + throw new UnsupportedOperationException(e); + } + try { + Object result = delegateMethod.invoke(delegate, args); + if (returnType.equals(org.gradle.api.java.archives.Manifest.class) + && !(name.equals("getEffectiveManifest") && (parameterTypes.length == 0))) { + return proxy; + } + return result; + } catch (InvocationTargetException e) { + Throwable t = e; + for (Throwable cause; (t instanceof InvocationTargetException) && ((cause = t.getCause()) != null);) { + t = cause; + } + throw t; + } } }