Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClassCastException in Gradle build after upgrade to 6.3.0 #5275

Closed
marcphilipp opened this issue Jun 3, 2022 · 6 comments · Fixed by #5276
Closed

ClassCastException in Gradle build after upgrade to 6.3.0 #5275

marcphilipp opened this issue Jun 3, 2022 · 6 comments · Fixed by #5276
Assignees
Labels
maint-candidate Issues or pull requests that are candidates for a maintenance release

Comments

@marcphilipp
Copy link
Contributor

marcphilipp commented Jun 3, 2022

I tried updating the JUnit 5 build to 6.3.0 but it resulted in the following failure:

Failed to apply plugin 'shadow-conventions'.
> Could not create task ':junit-platform-console:shadowJar'.
  > class aQute.bnd.gradle.BundleTaskExtension$EffectiveManifest cannot be cast to class com.github.jengelman.gradle.plugins.shadow.tasks.InheritManifest (aQute.bnd.gradle.BundleTaskExtension$EffectiveManifest and com.github.jengelman.gradle.plugins.shadow.tasks.InheritManifest are in unnamed module of loader org.gradle.internal.classloader.VisitableURLClassLoader @a6bd1fc)

Stacktrace: https://ge.junit.org/s/jgs5agcbr2obq/failure#1

It looks like both the BND and the Shadow plugin replace manifest with their own implementation. Is that something that was introduced in 6.3.0?

@bjhargrave
Copy link
Member

Is that something that was introduced in 6.3.0?

Yes. Per a user request from a user migrating from the old Gradle osgi support, I added 9feea15

In looking at the shadow plugin code

https://github.com/johnrengelman/shadow/blob/2b44f7b874ccc8c01c020195e0f762bb2171be6f/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy#L71

it assumes the task's manifest object implements the shadow plugin's InheritManifest type as set in

https://github.com/johnrengelman/shadow/blob/2b44f7b874ccc8c01c020195e0f762bb2171be6f/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.java#L60

The ClassCastException occurs here:

https://github.com/johnrengelman/shadow/blob/2b44f7b874ccc8c01c020195e0f762bb2171be6f/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.java#L110

It would seem that a jar task cannot both be a bundle task and a shadow task since they both set the manifest to a custom implementation and shadow assumes the manifest object always implements its own InheritManifest type.

There is not a great way to handle this as gradle does not have a means for a plugin/task to influence the effective manifest besides using a custom manifest implementation (and still using internal gradle types).

I suppose one thing Bnd could do is inspect the type of the manifest object returned by getManifest() and only replace it when it is not a custom type.

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 a07b78b17..c35a16cc7 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
@@ -219,7 +219,10 @@ public class BundleTaskExtension {
                // Wrap manifest
                org.gradle.api.java.archives.Manifest manifest = task.getManifest();
                effectiveManifest = new EffectiveManifest(manifest);
-               if (manifest != null) {
+               // Only set manifest if no one else has set a custom implementation
+               if ((manifest != null) && manifest.getClass()
+                       .getName()
+                       .startsWith("org.gradle.")) {
                        task.setManifest(effectiveManifest);
                }

Note: I don't test for DefaultManifest to allow for some wiggle room should Gradle change some implementation details. This test only assumes the any default manifest implementation will come from a org.gradle package.

@marcphilipp
Copy link
Contributor Author

Could the manifest be generated by a separate task or made available via an extension registered on the task instead?

bjhargrave added a commit to bjhargrave/bnd that referenced this issue Jun 3, 2022
We use a proxy over all the interfaces of the existing manifest object
so that if someone has set it to a custom type with custom interfaces,
the custom interfaces will be preserved.

See bndtools#5275

Signed-off-by: BJ Hargrave <bj@hargrave.dev>
@bjhargrave
Copy link
Member

bjhargrave commented Jun 3, 2022

Could the manifest be generated by a separate task or made available via an extension registered on the task instead?

The manifest is generated by the action of the BundleTaskExtension and only "lives" in the output jar file after the action completes. So I don't think a separate task makes sense.

The effective manifest could be made available as a new output property from BundleTaskExtension. But I think the life cycle is a mismatch as the property value is not available at end of configuration time. It is only available at after task execution.

I chose to use the task's effective manifest as that makes sense (since it is the actual effective manifest in the output jar) and also what users of the old Gradle osgi plugin did.

I made a different solution, #5276, which uses proxies to support the custom interface used by shadow. When testing on your JUnit 5 marc/bnd-6.3.0 branch, it avoids the exception you identified but then runs into gradle/gradle#20928 where the Manifest merging support does not support any Manifest implementation. It requires the Manifest be an instanceof DefaultManifest. I submitted gradle/gradle#20929 to fix the Gradle bug.

bjhargrave added a commit to bjhargrave/bnd that referenced this issue Jun 3, 2022
We use a proxy over all the interfaces of the existing manifest object
so that if someone has set it to a custom type with custom interfaces,
the custom interfaces will be preserved.

See bndtools#5275

Signed-off-by: BJ Hargrave <bj@hargrave.dev>
bjhargrave added a commit to bjhargrave/bnd that referenced this issue Jun 3, 2022
We use a proxy over all the interfaces of the existing manifest object
so that if someone has set it to a custom type with custom interfaces,
the custom interfaces will be preserved.

See bndtools#5275

Signed-off-by: BJ Hargrave <bj@hargrave.dev>
bjhargrave added a commit to bjhargrave/bnd that referenced this issue Jun 4, 2022
Instead of setting a manifest object in the task so that we can
set the effective manifest, after building we merge the generated
manifest into the existing manifest object.

Fixes bndtools#5275

Signed-off-by: BJ Hargrave <bj@hargrave.dev>
bjhargrave added a commit to bjhargrave/bnd that referenced this issue Jun 4, 2022
Rather than setting a manifest object in the task so that we can
set the effective manifest after building, we instead merge the
generated manifest into the existing manifest object.

Fixes bndtools#5275

Signed-off-by: BJ Hargrave <bj@hargrave.dev>
@bjhargrave
Copy link
Member

I made a different solution, #5276, which uses proxies to support the custom interface used by shadow.

Upon further thought, I completely redid the code to use the existing manifest merge support to merge the built manifest into the existing task manifest object.

With the update, the fix now works on the marc/bnd-6.3.0 branch.

@bjhargrave bjhargrave added the maint-candidate Issues or pull requests that are candidates for a maintenance release label Jun 4, 2022
@bjhargrave bjhargrave self-assigned this Jun 4, 2022
bjhargrave added a commit to bjhargrave/bnd that referenced this issue Jun 4, 2022
Rather than setting a manifest object in the task so that we can
set the effective manifest after building, we instead merge the
generated manifest into the existing manifest object.

Fixes bndtools#5275

Signed-off-by: BJ Hargrave <bj@hargrave.dev>
@bjhargrave
Copy link
Member

I marked this issue for a possible 6.3.1 release.

@marcphilipp
Copy link
Contributor Author

Thanks for the quick turnaround! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maint-candidate Issues or pull requests that are candidates for a maintenance release
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants