[GRADLE-2695] java.lang.ClassFormatError: Duplicate method name&signature in custom task's class file after upgrading to Gradle 1.3 Created: 27/Feb/13 Updated: 18/Nov/13 Resolved: 18/Nov/13 |
|
Status: | Resolved |
Project: | Gradle |
Affects Version/s: | None |
Fix Version/s: | 1.10-rc-1 |
Type: | Bug | ||
Reporter: | Gradle Forums | Assignee: | Unassigned |
Resolution: | Fixed | Votes: | 2 |
Description |
Hi there, I'm a bit late to the party this time But I'm currently upgrading our project builds to Gradle 1.3. I'm having issues with one of our tasks. I didn't change its code between 1.1 and 1.3 and it compiles fine under all three versions. However, when I reference it in a build file as simple as this one: buildscript { dependencies { import com.mycompany.MyTask apply plugin: 'java' task somTask (type: MyTask) { gradle aborts during configuration with the following error:
BUILD FAILED I read that you switched ASM versions in Gradle 1.2, but when I use 1.2 at runtime, everything works fine. The problems start when using Gradle 1.3 for building projects that rely on the custom task. Any idea? Best regards, |
Comments |
Comment by Gradle Forums [ 27/Feb/13 ] |
Do you get the same error when compiling the plugin against 1.3, and then using that in a 1.3 build? |
Comment by Gradle Forums [ 27/Feb/13 ] |
Yes I do; it looks as if the runtime is relevant, not the compiled class file. |
Comment by Gradle Forums [ 27/Feb/13 ] |
Can you provide a reproducible example? Then we can have a closer look. |
Comment by Gradle Forums [ 27/Feb/13 ] |
Okay, so I compiled my task into a jar and created a minimal project reproducing the error. If you just run "gradle tasks" with gradle 1.2, it works. If you run it with gradle 1.3, it fails. Here's the project archive: Edit the task class was compiled with Gradle 1.3 btw. |
Comment by Gradle Forums [ 27/Feb/13 ] |
Update: tested with Gradle 1.4: same result as with 1.3, even when compiling the task with 1.4 |
Comment by Gradle Forums [ 27/Feb/13 ] |
Any update here? This is really a blocker for us... |
Comment by Gradle Forums [ 27/Feb/13 ] |
At the moment, it isn't clear to me that the problem is on Gradle's side. If you can provide a minimal reproducible example that allows to build the task from source, I might have another look. |
Comment by Gradle Forums [ 27/Feb/13 ] |
Hi, Can you please provide the source for the task class. I can't proceed without it. |
Comment by Gradle Forums [ 27/Feb/13 ] |
Oh, sure, here's the gradle project that builds the "failingTask.jar" file used in the sample project above. [1]https://docs.google.com/file/d/0B6hxw... |
Comment by Gradle Forums [ 27/Feb/13 ] |
push |
Comment by Gradle Forums [ 27/Feb/13 ] |
Hi, I tried out the example and run into the same problem. I would be interested in the solution, too. Is there an example of a Java-Task class? |
Comment by Gradle Forums [ 27/Feb/13 ] |
I haven't worked out exactly why, but it's the `fileMapping(File, File)` and `fileMapping(File)` methods that trigger this. If you rename them it should work. I'm still looking into exactly why this happens. |
Comment by Gradle Forums [ 27/Feb/13 ] |
Thanks, Luke. On my side it is working now if I rename the methods like you suggested. |
Comment by Gradle Forums [ 27/Feb/13 ] |
Thanks for pointing us at the right method and coming up with a workaround, Luke. Changing that method's name would break the task's "api" though, and force all our projects to not only update to a new version of the task but also change actual project build files when migrating to the newer gradle versions... I still hope you can find the cause for this and maybe fix it for 1.5 ... I think we might migrate directly from 1.2 to 1.5 if it fixes the issue without having to adapt all project build files. Looking forward to hearing from you! |
Comment by Gradle Forums [ 27/Feb/13 ] |
Hi, as a newbie to gradle I found this topic very interesting. So I re-arranged your example to have a buildSrc directory: [1]www.gradle.org/docs/current/userguide... With this I only have to rename one method: Perhaps you can replace all fileMapping(file) calls with fileMapping(file, null) ? No pretty solution either. |
Comment by Gradle Forums [ 27/Feb/13 ] |
Unfortunately this won't make 1.5, which is close to RC stage. |
Comment by Daz DeBoer [ 06/May/13 ] |
From forum user 'netmikey': I found that renaming the member variable and its accessor methods also solves the problem, (almost) without affecting its public interface |
Comment by Andrew Oberstar [ 23/Oct/13 ] |
This workaround does end up affecting the public API of a task, so it's not feasible if you have a heavily used task. We really need an actual fix. |
Comment by Andrew Oberstar [ 23/Oct/13 ] |
Using a git bisect, I narrowed the issue down to this commit. Looking at the diff, the significant break comes in AbstractClassGenerator lines 151. Instead of only dealing with single-arg methods, it was changed to apply to any non-zero arg methods, in order to provide decoration of methods whose last argument is an Action to also provide a method that takes a Closure. The important thing to note up there is that any methods with the name of a property are added to the Multimap "methods". So in the case of a class with an "environment" property and two methods "environment(String)" and "environment(String, String, String)" both will be added to the list. Looking farther down in the generate method you see a for loop over settable properties. Since in this case the environment property has two methods in the Multimap, it will call "builder.overrideSetMethod()" twice. Now looking at the AsmBackedClassGenerator's implementation of overrideSetMethod, note the comment at line 748 and the surrounding lines. Regardless of how many arguments the metaMethod argument has, only the first one will be grabbed and a new implementation that takes one arg will be added. So now in our example, we have passed in both "environment(String)" and "environment(String, String, String)" both of which will try to add a "environment(String)" implementation to the generated class. My belief (as a complete layman when it comes to ASM) is that adding these two implementations is what causes the failure. The fix would probably involve updating overrideSetMethod to return if the metaMethod doesn't have 1 argument. |
Comment by Andrew Oberstar [ 23/Oct/13 ] |
That does seem to work: diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/AsmBackedC index 06ec955..3a9c6e5 100644 --- a/subprojects/core/src/main/groovy/org/gradle/api/internal/AsmBackedClassGen +++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/AsmBackedClassGen @@ -784,7 +784,7 @@ public class AsmBackedClassGenerator extends AbstractClassGe } public void overrideSetMethod(MetaBeanProperty property, MetaMethod met - if (!extensible) { + if (!extensible || metaMethod.getParameterTypes().length != 1) { return; } Type paramType = Type.getType(metaMethod.getParameterTypes()[0].get |
Comment by Andrew Oberstar [ 23/Oct/13 ] |
Any chance that this could get into 1.9? It is just a bug fix. |