paparazzi icon indicating copy to clipboard operation
paparazzi copied to clipboard

Duplicate field name

Open costular opened this issue 1 year ago • 4 comments

First of all, thank you for taking the time to have a look a this 🙏🏼

Description According to the issue, when I execute the Paparazzi tasks every test fails with the same exception.

java.lang.ClassFormatError: Duplicate field name "AddContentButton_android_text" with signature "I" in class file com/jobandtalent/components/R$styleable
	at java.base/java.lang.Class.getDeclaredClasses0(Native Method)
	at java.base/java.lang.Class.getDeclaredClasses(Class.java:2196)
	at app.cash.paparazzi.internal.PaparazziCallback.initResources(PaparazziCallback.kt:63)
	at app.cash.paparazzi.Paparazzi.prepare(Paparazzi.kt:152)
	at app.cash.paparazzi.Paparazzi$apply$statement$1.evaluate(Paparazzi.kt:122)
	at app.cash.paparazzi.agent.AgentTestRule$apply$1.evaluate(AgentTestRule.kt:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
	at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

If I look for that attribute, we can find the next:

 <declare-styleable name="AddContentButton">
        <attr name="android:text" />
    </declare-styleable>

as soon as I remove the android namespace it starts working properly.

Just to give more context, we have an Android library module that contains some design system components. They're a mix of Composables and custom views, that's why we have custom attributes.

Any clue?

Additional information:

  • Paparazzi Version: 1.0.0
  • OS: Macos Monterrey
  • Compile SDK:
  • Gradle Version: 7.4.2
  • Android Gradle Plugin Version: 7.2.1

costular avatar Jun 30 '22 19:06 costular

@costular thanks for reporting! Could you take a look on paparazzi-gradle-plugin/src/test/projects and see if you can provide a testing sample that mimics your issue?

fcduarte avatar Jul 27 '22 04:07 fcduarte

@costular to help us effectively troubleshoot, we'll need a sample repro project. is there anything you can share either here or via DM/email?

jrodbx avatar Aug 01 '22 20:08 jrodbx

Hey guys, I'll try to find a shareable code with the reproducible bug in order to help you out as soon as possible!

costular avatar Aug 02 '22 16:08 costular

@costular have you had a chance to reproduce in something sharable?

jrodbx avatar Aug 08 '22 05:08 jrodbx

Closing since no repro

jrodbx avatar Sep 05 '22 05:09 jrodbx

Hi @jrodbx @fcduarte! 👋

We're also experiencing this issue at my company. I threw together a branch which reproduces the issue in the sample app in this repo:

https://github.com/cashapp/paparazzi/compare/master...martinpdd8:paparazzi:paulm/example-duplicate-field-name-error?expand=1

This yields the exception:

Duplicate field name "MyButton_android_background" with signature "I" in class file app/cash/paparazzi/sample/R$styleable
java.lang.ClassFormatError: Duplicate field name "MyButton_android_background" with signature "I" in class file app/cash/paparazzi/sample/R$styleable
	at java.base/java.lang.ClassLoader.defineClass1(Native Method)
	at java.base/java.lang.ClassLoader.defineClass(Unknown Source)
	at java.base/java.security.SecureClassLoader.defineClass(Unknown Source)
	at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(Unknown Source)
	at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(Unknown Source)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(Unknown Source)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
	at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
	at java.base/java.lang.Class.getDeclaredClasses0(Native Method)
	at java.base/java.lang.Class.getDeclaredClasses(Unknown Source)
	at app.cash.paparazzi.internal.PaparazziCallback.initResources(PaparazziCallback.kt:64)
	at app.cash.paparazzi.Paparazzi.prepare(Paparazzi.kt:151)
	at app.cash.paparazzi.Paparazzi$apply$statement$1.evaluate(Paparazzi.kt:121)
	at app.cash.paparazzi.agent.AgentTestRule$apply$1.evaluate(AgentTestRule.kt:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
	at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

We would love to adopt paparazzi but this issue is currently blocking us. Should I open a new issue or is it possible to re-open this one?

Thanks for a really cool library by the way!

martinpdd8 avatar Oct 12 '22 13:10 martinpdd8

I'm taking a look into this issue. Using your provided sample, I see that the resource for MyButton is in-fact duplicated in the R.jar file that is generated in build/intermediates/compile_and_runtime_not_namespaced_r_class_jar/debugUnitTest/R.jar

public final class R {
  private R() {
  }

  public static final class color {
    public static int bolt;
    public static int cameraBody;
    public static int keypadDarkGrey;
    public static int keypadGreen;
    public static int launchBackground;
    public static int vector_tint_color;
    public static int vector_tint_theme_color;

    private color() {
    }
  }

 ......

  public static final class styleable {
    public static int[] MyButton = new int[]{16842964, 16842964};
    public static int MyButton_android_background;
    public static int MyButton_android_background;

    private styleable() {
    }
  }
}

Strange because in build/intermediates/compile_r_class_jar/debug/R.jar does not have the duplicate entry.

geoff-powell avatar Jan 17 '23 15:01 geoff-powell

Seems like it's an Android Gradle Plugin bug. I logged an issue here in issue tracker: https://issuetracker.google.com/issues/265713285

I also created a separate repo without paparazzi artifacts to verify the issue still occurs. https://github.com/geoff-powell/SampleUnitTestRBug

geoff-powell avatar Jan 17 '23 17:01 geoff-powell

Confirmed:

$ javap -classpath sample/build/intermediates/compile_and_runtime_not_namespaced_r_class_jar/debugUnitTest/R.jar app.cash.paparazzi.sample.R\$styleable
public final class app.cash.paparazzi.sample.R$styleable {
  public static int[] MyButton;
  public static int MyButton_android_background;
  public static int MyButton_android_background;
  public static {};
}
$ javap -classpath sample/build/intermediates/compile_r_class_jar/debug/R.jar app.cash.paparazzi.sample.R\$styleable
public final class app.cash.paparazzi.sample.R$styleable {
  public static int[] MyButton;
  public static int MyButton_android_background;
  public static {};
}

While this might be an AGP bug, we also have custom styleables in CashApp and this configuration seems to be the reason why we avoid this issue:

// in your views/composable module's build script
android {
  ...
  testOptions {
    unitTests {
      includeAndroidResources true
    }
  }
}

I've confirmed that applying this config to @martinpdd8's repro resolves the issue.

@costular @martinpdd8 Can you try adding this snippet to your respective repos and confirm this issue as fixed? I'll leave this open and move to 1.3 milestone to unblock the 1.2 release.

jrodbx avatar Jan 18 '23 04:01 jrodbx

Ok, closing this as resolved per the previous comment. Please file another issue (and ideally reference this one) if this has not been fixed!

jrodbx avatar Mar 25 '23 02:03 jrodbx

Did anyone file an issue on AGP?

ansman avatar Mar 19 '24 12:03 ansman

Looks like Geoff did: https://github.com/cashapp/paparazzi/issues/481#issuecomment-1385769818

jrodbx avatar Mar 19 '24 15:03 jrodbx

Ah my bad, missed that link

ansman avatar Mar 19 '24 15:03 ansman