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 verifying a kotlin data class (annotation containing int array). #227

Closed
calvarez-ov opened this issue Dec 26, 2018 · 4 comments

Comments

@calvarez-ov
Copy link

What steps will reproduce the problem?

  • Update equalsverifier from 3.0.3 to 3.1.1
  • Run verify() on a kotlin data class.

What is the code that triggers this problem?

The code is a generated java file from a kotlin file. I don't have an example app yet, and this is a closed-source app. But I'll provide some snippets for now, and try to find time to create a standalone example to illustrate the problem.

The kotlin file is a data class:

data class Platform(@JvmField val name: String,
                    ...)

The generated java file (produced by gradle) starts out like this:

@kotlin.Metadata(mv = {1, 1, 13}, bv = {1, 0, 3}, k = 1, ...)
public final class Platform {

The test code is this:

EqualsVerifier.forClass(clazz).withRedefinedSuperclass().suppress(Warning.NONFINAL_FIELDS).verify();

What error message or stack trace does EqualsVerifier give?

java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;

What did you expect?

No ClassCastException

Which version of EqualsVerifier are you using?

3.1 and 3.1.1 have this problem.
3.0.3 doesn't appear to have the problem.

Please provide any additional information below.

The equalsverifier lib crashes here:

    private AnnotationProperties buildAnnotationProperties(AnnotationDescription annotation) {
        AnnotationProperties props = new AnnotationProperties(annotation.getAnnotationType().getCanonicalName());
        annotation.getAnnotationType().getDeclaredMethods().forEach(m -> {
            Object val = annotation.getValue(m).resolve();
            if (val.getClass().isArray()) {
                Object[] array = (Object[])val;  <---- crashes here
                Set<String> values = new HashSet<>();
                for (Object obj : array) {
                    if (obj instanceof TypeDescription) {
                        values.add(((TypeDescription)obj).getName());
                    }
                    else {
                        values.add(obj.toString());
                    }
                }
                props.putArrayValues(m.getName(), values);
            }
        });
        return props;
    }

Stacktrace:

java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.lambda$buildAnnotationProperties$18(AnnotationCacheBuilder.java:137)
	at java.lang.Iterable.forEach(Iterable.java:75)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.buildAnnotationProperties(AnnotationCacheBuilder.java:134)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.cacheSupportedAnnotations(AnnotationCacheBuilder.java:123)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.lambda$visitClass$3(AnnotationCacheBuilder.java:87)
	at java.lang.Iterable.forEach(Iterable.java:75)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.visitClass(AnnotationCacheBuilder.java:87)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.visitType(AnnotationCacheBuilder.java:46)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.build(AnnotationCacheBuilder.java:35)
	at nl.jqno.equalsverifier.internal.util.Configuration.buildAnnotationCache(Configuration.java:79)
	at nl.jqno.equalsverifier.internal.util.Configuration.build(Configuration.java:67)
	at nl.jqno.equalsverifier.EqualsVerifierApi.buildConfig(EqualsVerifierApi.java:354)
	at nl.jqno.equalsverifier.EqualsVerifierApi.performVerification(EqualsVerifierApi.java:346)
	at nl.jqno.equalsverifier.EqualsVerifierApi.verify(EqualsVerifierApi.java:302)
	at com.example.classstructure.DataObjectsTest.testDataObjectClass(DataObjectsTest.java:94)

My understanding is that the annotation in the generated java file has an array of int, which can't be cast to an Object[].

@calvarez-ov
Copy link
Author

Here are some more specific steps to reproduce the issue (sorry no sample github repo at this time, but it's only 2 classes and a couple of commands).

data class InputClass(@JvmField val name: String)
  • Create a test java class which executes equalsverifier, TestEqualsVerifier.java:
import nl.jqno.equalsverifier.EqualsVerifier;
import nl.jqno.equalsverifier.Warning;

public class TestEqualsVerifier {
    public static void main(String[] args) {
        EqualsVerifier.forClass(InputClass.class).withRedefinedSuperclass().suppress(Warning.NONFINAL_FIELDS).verify();
    }
}
  • Compile the kotlin data class: /path/to/kotlinc/bin/kotlinc InputClass.kt
  • Compile the java test class:
javac -cp /path/to/equalsverifier-3.1.1.jar:. TestEqualsVerifier.java
  • Run the test class:
java -cp /path/to/equalsverifier-3.1.1.jar:/path/to/kotlinc/lib/kotlin-stdlib.jar:. TestEqualsVerifier

Expected behavior: no output
Actual behavior:

Exception in thread "main" java.lang.AssertionError: EqualsVerifier found a problem in class InputClass.
-> [I cannot be cast to [Ljava.lang.Object;

For more information, go to: http://www.jqno.nl/equalsverifier/errormessages
	at nl.jqno.equalsverifier.EqualsVerifierApi.verify(EqualsVerifierApi.java:308)
	at TestEqualsVerifier.main(TestEqualsVerifier.java:6)
Caused by: java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.lambda$buildAnnotationProperties$18(AnnotationCacheBuilder.java:137)
	at java.lang.Iterable.forEach(Iterable.java:75)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.buildAnnotationProperties(AnnotationCacheBuilder.java:134)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.cacheSupportedAnnotations(AnnotationCacheBuilder.java:123)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.lambda$visitClass$3(AnnotationCacheBuilder.java:87)
	at java.lang.Iterable.forEach(Iterable.java:75)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.visitClass(AnnotationCacheBuilder.java:87)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.visitType(AnnotationCacheBuilder.java:46)
	at nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCacheBuilder.build(AnnotationCacheBuilder.java:35)
	at nl.jqno.equalsverifier.internal.util.Configuration.buildAnnotationCache(Configuration.java:79)
	at nl.jqno.equalsverifier.internal.util.Configuration.build(Configuration.java:67)
	at nl.jqno.equalsverifier.EqualsVerifierApi.buildConfig(EqualsVerifierApi.java:354)
	at nl.jqno.equalsverifier.EqualsVerifierApi.performVerification(EqualsVerifierApi.java:346)
	at nl.jqno.equalsverifier.EqualsVerifierApi.verify(EqualsVerifierApi.java:302)
	... 1 more

jqno added a commit that referenced this issue Dec 26, 2018
@jqno
Copy link
Owner

jqno commented Dec 26, 2018

Hi Carmen,

Thanks for the elaborate bug report! It was very helpful to find the cause quickly.
I've just released a fix (version 3.1.2). I guess I should have waited a bit before releasing 3.1.1 😉. It's syncing with Maven Central as we speak.

@jqno jqno closed this as completed Dec 26, 2018
@calvarez-ov
Copy link
Author

Hahah cool, I'll check it out as soon as it's ready.
I was in the process of making another sample java-only class to reproduce it, but you made a fix faster than I could finish this example 😆

@jqno
Copy link
Owner

jqno commented Dec 26, 2018

Haha 😄
I really appreciate all the effort you've put into reporting this issue. Many people don't bother, but it really really helps. Thank you!

akhalikov pushed a commit to akhalikov/equalsverifier that referenced this issue Nov 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants