7

How would you implement this method:

public boolean equal(Annotation a1, Annotation a2) {
   ...
}

Sample input ():

@First(name="1", value="1"), @Second(name="1", value="1")
@First(value="2"),           @First(name="2")
@First(value="3"),           @First(value="3")
@Second(name="4", value="4), @Second(name="4", value="4")

Sample output:

false
false
true
true

As you can see, the expected behavior of equal is clear and similar to expected behavior of standard equals method of regular objects in java (the problem is that we cannot override equals for annotations).

Are there any libs or standard implementations?

Roman
  • 64,384
  • 92
  • 238
  • 332
  • 2
    `a1.equals(a2);` will work. This is the default behavior for annotations - it checks that the annotations are of the same type and that each of the annotation fields are equal. No special work arounds required. – rees Oct 27 '13 at 19:28

3 Answers3

2

Doesn't the overriden equals for Annotation work? Maybe I don't understand your question.

Petar Minchev
  • 46,889
  • 11
  • 103
  • 119
  • could you please show me how would you override `equals` on annotation class (let's take `@Sample` annotation as a start point; `equals` body doesn't really matter, just show where would you write it). thx. – Roman Jul 26 '11 at 06:42
  • It is already in Java for the annotations. Doesn't the default work for you? Have you looked at the link I provided? Maybe there is some misunderstanding... – Petar Minchev Jul 26 '11 at 06:47
  • maybe you're right, I'll investigate it (it's just not obvious how does it work since the actual `equals` implementation is somewhere else but not inside `Annotation` class). – Roman Jul 26 '11 at 06:48
1

If you want to check whether a1 and a2 are the same annotation. Try this: a1.annotationType().equals(a2.annotationType())

Guitar
  • 21
  • 2
0

The annoying part of my answer is I can not extend a custom annotation (in the sense of inheritance). That would have simplified the equals method.

First.java

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface First  {
  String name() default "";
  String value() default "";
}

Second.java

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Second {
    String name() default "";
    String value() default "";
}

Thing1.java

public class Thing1 {
     @First(name = "1", value ="1")
     Object leftSideCase1;
     @Second(name = "1", value ="1")
     Object rightSideCase1;

     @First(value ="2")
     Object leftSideCase2;
     @First(name = "2")
     Object rightSideCase2;

     @First(value ="3")
     Object leftSideCase3;
     @First(value ="3")
     Object rightSideCase3;

     @First(name = "4", value ="4")
     Object leftSideCase4;
     @First(name = "4", value ="4")
     Object rightSideCase4;
}

Example.java

public class Example {


    public static void main(String[] args) throws NoSuchFieldException {
        String [][] fieldNameOfCases = {
                {"leftSideCase1","rightSideCase1"},
                {"leftSideCase2","rightSideCase2"},
                {"leftSideCase3","rightSideCase3"},
                {"leftSideCase4","rightSideCase4"},
        };

        // Loop through the list of field names, paired up by test case
        // Note: It's the construction of Thing1 that matches your question's
        // "sample input():"
        for(int index=0; index < fieldNameOfCases.length; index++) {
            Annotation leftSideAnnotation = getAnnotation(Thing1.class, fieldNameOfCases[index][0]);
            Annotation rightSideAnnotation = getAnnotation(Thing1.class, fieldNameOfCases[index][1]);
            System.out.println(equal(leftSideAnnotation, rightSideAnnotation));
        }
    }

    private static Annotation getAnnotation(Class<Thing1> thing1Class, String fieldName) throws NoSuchFieldException {
        Field classMemberField = Thing1.class.getDeclaredField(fieldName);
        Annotation[] annotations = classMemberField.getAnnotations();
        // ASSUME ONE ANNOTATION PER FIELD
        return annotations[0];
    }

    // This is my solution to the question
    public static boolean equal(Annotation a1, Annotation a2) {
       if(a1.getClass() != a2.getClass()) {
           return false;
       }
       if(a1 instanceof First) {
           if( ((First)a1).name().equals(((First)a2).name())  &&
               ((First)a1).value().equals(((First)a2).value()) ) {
               return true;
           }
           return false;
       }
       // Its annoying we can't leverage inheritance with the custom annotation
       // to remove duplicate code!! 
       if(a1 instanceof Second) {
            if( ((Second)a1).name().equals(((Second)a2).name())  &&
                ((Second)a1).value().equals(((Second)a2).value()) ) {
                return true;
            }
            return false;
        }
        return false;
    }
}

Note: I did not introduce a NamePairValue holder to use within First, and Second (custom annotation) because this didn't match the "sample input():" exactly!

See this Stack Trace for details for this style / solution. How to extend Java annotation?

This question is 10 years old but the question was not answered as asked by Roman. With 4k views, I hope this helps someone!!

JET
  • 11
  • 2