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

Handle @EmbeddedId annotation #228

Closed
giacgbj opened this issue Dec 28, 2018 · 6 comments
Closed

Handle @EmbeddedId annotation #228

giacgbj opened this issue Dec 28, 2018 · 6 comments
Labels

Comments

@giacgbj
Copy link

giacgbj commented Dec 28, 2018

Is there a way to natively handle @EmbeddedId annotation?

I'm currently using the following code to evaluate both @Id and @EmbeddedId annotations:

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;

import org.apache.commons.lang3.reflect.FieldUtils;

import io.github.classgraph.ClassInfoList;
import nl.jqno.equalsverifier.EqualsVerifier;


final ClassInfoList entities = [OMISSIS];
for (final Class<?> classToCheck : entities.loadClasses()) {
    final List<Field> singleValuePrimaryKeyList = FieldUtils.getFieldsListWithAnnotation(classToCheck, Id.class);
    final List<Field> compositePrimaryKeyList = FieldUtils.getFieldsListWithAnnotation(classToCheck, EmbeddedId.class);
    final List<String> primaryKeyFields = new ArrayList<>();
    primaryKeyFields.addAll(singleValuePrimaryKeyList.stream().map(f -> f.getName()).collect(Collectors.toList()));
    primaryKeyFields.addAll(compositePrimaryKeyList.stream().map(f -> f.getName()).collect(Collectors.toList()));
    EqualsVerifier.forClass(classToCheck).withOnlyTheseFields(primaryKeyFields.toArray(new String[0])).withIgnoredAnnotations(Id.class).verify();

    if (!compositePrimaryKeyList.isEmpty()) {
        final Field compositePKField = compositePrimaryKeyList.get(0);
        final Class<?> compositePKClazz = compositePKField.getType();
        EqualsVerifier.forClass(compositePKClazz).verify();
    }
}
@jqno
Copy link
Owner

jqno commented Dec 28, 2018

Sure!

Can you give me an example of what a class would look like that uses @EmbeddedId?

Also, should EqualsVerifier handle fields marked with @EmbeddedId in the same way that it handles @Id, or are there differences?

@giacgbj
Copy link
Author

giacgbj commented Dec 28, 2018

The classes would look like this (I omitted all the parts not regarding this specific issue):

@Entity
@Table
public class X {

    @EmbeddedId
    private XCompositePrimaryKey id;

    @Column
    private String value;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (id == null ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof X)) {
            return false;
        }
        final X other = (X) obj;
        if (id == null) {
            if (other.id != null) {
                return false;
            }
        } else if (!id.equals(other.id)) {
            return false;
        }
        return true;
    }

}

@Embeddable
public class XCompositePrimaryKey {

    @Column
    private String a;

    @Column
    private String b;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (b == null ? 0 : b.hashCode());
        result = prime * result + (a == null ? 0 : a.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof XCompositePrimaryKey)) {
            return false;
        }
        final XCompositePrimaryKey other = (XCompositePrimaryKey) obj;

        if (b == null) {
            if (other.b != null) {
                return false;
            }
        } else if (!b.equals(other.b)) {
            return false;
        }
        if (a == null) {
            if (other.a != null) {
                return false;
            }
        } else if (!a.equals(other.a)) {
            return false;
        }
        return true;
    }

}

Regarding the second question, I probably use it in a different way, as you can see in the code I wrote in the first post: I consider two classes equal if their primary key (single or composite) is equal.

@jqno
Copy link
Owner

jqno commented Dec 29, 2018

Thanks!
What I meant to ask is, by default EqualsVerifier checks that fields marked with @Id should not be used in equals and hashCode, except when Warning.SURROGATE_KEY is suppressed: in this case it checks that only the fields maeked with @Id are used. Should EqualsVerifier treat @EmbeddedId in the same way? Or is the use case different?

@giacgbj
Copy link
Author

giacgbj commented Dec 29, 2018

Thanks for your prompt answers!

According to your description, I think it should be treated the same way as @Id, so in my case I should add Warning.SURROGATE_KEY to check that only the fields with @Id or @EmbeddedId annotations are used.

@jqno jqno added the accepted label Dec 30, 2018
@jqno
Copy link
Owner

jqno commented Dec 30, 2018

OK, thanks for the answer. I'll make EqualsVerifier treat them the same way then. I'm not sure when I can release it but I'll let you know when I do.

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

jqno commented Dec 31, 2018

I just released version 3.1.4 with support for @EmbeddedId. Please let me know what you think!

@jqno jqno closed this as completed Dec 31, 2018
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
Projects
None yet
Development

No branches or pull requests

2 participants