/* * Hibernate Validator, declare and validate application constraints * * License: Apache License, Version 2.0 * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>. */ package org.hibernate.validator.test.internal.util.annotationfactory; import static org.assertj.core.api.Assertions.assertThat; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.hibernate.validator.internal.util.annotationfactory.AnnotationDescriptor; import org.hibernate.validator.internal.util.annotationfactory.AnnotationFactory; import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredMethods; /** * @author Gunnar Morling */ public class AnnotationProxyTest { private MyAnno realAnnotation; private AnnotationDescriptor<MyAnno> descriptor; @BeforeMethod public void setupAnnotations() throws Exception { realAnnotation = Foo.class.getAnnotation( MyAnno.class ); descriptor = getDescriptorFromAnnotation( realAnnotation ); } @Test public void testEqualsAnnotationsAreEqual() { MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isEqualTo( realAnnotation ); assertThat( realAnnotation ).isEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsAnnotationsAreSame() { MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsCheckNull() { MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( null ); } @Test public void testEqualsAnnotationTypesDiffer() { MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); MyOtherAnno anotherAnnotation = Baz.class.getAnnotation( MyOtherAnno.class ); AnnotationDescriptor<MyOtherAnno> anotherDescriptor = getDescriptorFromAnnotation( anotherAnnotation ); MyOtherAnno anotherProxiedAnnotation = AnnotationFactory.create( anotherDescriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( anotherProxiedAnnotation ); assertThat( anotherProxiedAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( anotherProxiedAnnotation ).isNotEqualTo( realAnnotation ); } @Test public void testEqualsPrimitiveMembersDiffer() { descriptor.setValue( "int_", 42 ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsDoubleNaNEqualsItself() throws Exception { realAnnotation = Bar.class.getMethod( "nanDouble" ).getAnnotation( MyAnno.class ); descriptor = getDescriptorFromAnnotation( realAnnotation ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isEqualTo( realAnnotation ); assertThat( realAnnotation ).isEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsDoubleZeroNotEqualToMinusZero() throws Exception { realAnnotation = Bar.class.getMethod( "zeroDouble" ).getAnnotation( MyAnno.class ); descriptor = getDescriptorFromAnnotation( realAnnotation ); descriptor.setValue( "double_", -0.0 ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsFloatNaNEqualsItself() throws Exception { realAnnotation = Bar.class.getMethod( "nanFloat" ).getAnnotation( MyAnno.class ); descriptor = getDescriptorFromAnnotation( realAnnotation ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isEqualTo( realAnnotation ); assertThat( realAnnotation ).isEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsFloatZeroNotEqualToMinusZero() throws Exception { realAnnotation = Bar.class.getMethod( "zeroFloat" ).getAnnotation( MyAnno.class ); descriptor = getDescriptorFromAnnotation( realAnnotation ); descriptor.setValue( "float_", -0.0f ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsStringMembersDiffer() { descriptor.setValue( "string", "Bar" ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsClassMembersDiffer() { descriptor.setValue( "class_", Integer.class ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsBooleanArrayMembersDiffer() { descriptor.setValue( "booleans", new boolean[] { } ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsByteArrayMembersDiffer() { descriptor.setValue( "bytes", new byte[] { } ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsCharArrayMembersDiffer() { descriptor.setValue( "chars", new char[] { } ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsDoubleArrayMembersDiffer() { descriptor.setValue( "doubles", new double[] { } ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsFloatArrayMembersDiffer() { descriptor.setValue( "floats", new float[] { } ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsIntArrayMembersDiffer() { descriptor.setValue( "ints", new int[] { } ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsLongArrayMembersDiffer() { descriptor.setValue( "longs", new long[] { } ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsShortArrayMembersDiffer() { descriptor.setValue( "shorts", new short[] { } ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testEqualsClassArrayMembersDiffer() { descriptor.setValue( "classes", new Class<?>[] { } ); MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation ).isNotEqualTo( realAnnotation ); assertThat( realAnnotation ).isNotEqualTo( proxiedAnnotation ); assertThat( proxiedAnnotation ).isEqualTo( proxiedAnnotation ); } @Test public void testHashCode() { MyAnno proxiedAnnotation = AnnotationFactory.create( descriptor ); assertThat( proxiedAnnotation.hashCode() ).isEqualTo( realAnnotation.hashCode() ); } /** * Returns an {@link AnnotationDescriptor} representing the given annotation. * * @param annotation The annotation to represent. * * @return A descriptor for the given annotation. */ private <A extends Annotation> AnnotationDescriptor<A> getDescriptorFromAnnotation(A annotation) { @SuppressWarnings("unchecked") Class<A> annotationType = (Class<A>) annotation.annotationType(); AnnotationDescriptor<A> descriptor = new AnnotationDescriptor<A>( annotationType ); for ( Method method : GetDeclaredMethods.action( annotationType ).run() ) { try { descriptor.setValue( method.getName(), method.invoke( annotation ) ); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException( e ); } } return descriptor; } @MyAnno private static class Foo { } private static class Bar { @MyAnno(double_ = Double.NaN) public void nanDouble() { } @MyAnno(double_ = 0.0) public void zeroDouble() { } @MyAnno(float_ = Float.NaN) public void nanFloat() { } @MyAnno(float_ = 0.0f) public void zeroFloat() { } } @MyOtherAnno private static class Baz { } @Retention(RetentionPolicy.RUNTIME) public @interface MyAnno { //primitive types boolean boolean_() default false; byte byte_() default Byte.MAX_VALUE; char char_() default 'A'; double double_() default Double.MAX_VALUE; float float_() default Float.MAX_VALUE; int int_() default Integer.MAX_VALUE; long long_() default Long.MAX_VALUE; short short_() default Short.MAX_VALUE; //reference types String string() default "Foo"; MyEnum myEnum() default MyEnum.FOO; Class<?> class_() default Object.class; MyOtherAnno myOtherAnno() default @MyOtherAnno; //primitive array types boolean[] booleans() default { false, true }; byte[] bytes() default { Byte.MIN_VALUE, -1, 0, 1, Byte.MAX_VALUE }; char[] chars() default { 'A', 'B', 'C' }; double[] doubles() default { Double.NEGATIVE_INFINITY, Double.MIN_VALUE, -1, 0, 1, Double.MAX_VALUE, Double.POSITIVE_INFINITY, Double.NaN }; float[] floats() default { Float.NEGATIVE_INFINITY, Float.MIN_VALUE, -1, 0, 1, Float.MAX_VALUE, Float.POSITIVE_INFINITY, Float.NaN }; int[] ints() default { Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE }; long[] longs() default { Long.MIN_VALUE, -1, 0, 1, Long.MAX_VALUE }; short[] shorts() default { Short.MIN_VALUE, -1, 0, 1, Short.MAX_VALUE }; //reference array types String[] strings() default { "Foo", "Bar" }; MyEnum[] myEnums() default { MyEnum.FOO, MyEnum.BAR }; Class<?>[] classes() default { Object.class, Integer.class }; MyOtherAnno[] myOtherAnnos() default { @MyOtherAnno, @MyOtherAnno }; } @Retention(RetentionPolicy.RUNTIME) public @interface MyOtherAnno { //primitive types boolean boolean_() default false; byte byte_() default Byte.MAX_VALUE; char char_() default 'A'; double double_() default Double.MAX_VALUE; float float_() default Float.MAX_VALUE; int int_() default Integer.MAX_VALUE; long long_() default Long.MAX_VALUE; short short_() default Short.MAX_VALUE; //reference types String string() default "Foo"; MyEnum myEnum() default MyEnum.FOO; Class<?> class_() default Object.class; //primitive array types boolean[] booleans() default { false, true }; byte[] bytes() default { Byte.MIN_VALUE, -1, 0, 1, Byte.MAX_VALUE }; char[] chars() default { 'A', 'B', 'C' }; double[] doubles() default { Double.NEGATIVE_INFINITY, Double.MIN_VALUE, -1, 0, 1, Double.MAX_VALUE, Double.POSITIVE_INFINITY, Double.NaN }; float[] floats() default { Float.NEGATIVE_INFINITY, Float.MIN_VALUE, -1, 0, 1, Float.MAX_VALUE, Float.POSITIVE_INFINITY, Float.NaN }; int[] ints() default { Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE }; long[] longs() default { Long.MIN_VALUE, -1, 0, 1, Long.MAX_VALUE }; short[] shorts() default { Short.MIN_VALUE, -1, 0, 1, Short.MAX_VALUE }; //reference array types String[] strings() default { "Foo", "Bar" }; MyEnum[] myEnums() default { MyEnum.FOO, MyEnum.BAR }; Class<?>[] classes() default { Object.class, Integer.class }; } public enum MyEnum { FOO, BAR; } }