Skip to content

Commit

Permalink
HV-626 use #getDeclaredAnnotations instead of #getAnnotations when pr…
Browse files Browse the repository at this point in the history
…ocessing member/class metadata
  • Loading branch information
gunnarmorling committed Nov 27, 2012
1 parent 2f7367b commit d6a95a3
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -59,10 +59,11 @@
import static org.hibernate.validator.internal.util.ReflectionHelper.newInstance;

/**
* {@code MetaDataProvider} which reads the metadata from annotations which is the default configuration source.
*
* @author Gunnar Morling
* @author Hardy Ferentschik
*/
@SuppressWarnings("deprecation")
public class AnnotationMetaDataProvider implements MetaDataProvider {
private static final Log log = LoggerFactory.make();
/**
Expand All @@ -84,17 +85,19 @@ public AnnotationMetaDataProvider(ConstraintHelper constraintHelper, AnnotationP
);
}

@Override
public AnnotationProcessingOptions getAnnotationProcessingOptions() {
return new AnnotationProcessingOptions();
}

@Override
public <T> List<BeanConfiguration<? super T>> getBeanConfigurationForHierarchy(Class<T> beanClass) {
List<BeanConfiguration<? super T>> configurations = newArrayList();

for ( Class<?> oneHierarchyClass : ReflectionHelper.computeClassHierarchy( beanClass, true ) ) {
for ( Class<?> hierarchyClass : ReflectionHelper.computeClassHierarchy( beanClass, true ) ) {
@SuppressWarnings("unchecked")
BeanConfiguration<? super T> configuration = (BeanConfiguration<? super T>) getBeanConfiguration(
oneHierarchyClass
hierarchyClass
);
if ( configuration != null ) {
configurations.add( configuration );
Expand Down Expand Up @@ -358,11 +361,9 @@ private List<ConstrainedParameter> getParameterMetaData(Method method) {
*
* @return A list of constraint descriptors for all constraint specified for the given field or method.
*/
private List<ConstraintDescriptorImpl<?>> findConstraints(Member member, ElementType type) {
assert member instanceof Field || member instanceof Method;

private List<ConstraintDescriptorImpl<?>> findConstraints(AccessibleObject member, ElementType type) {
List<ConstraintDescriptorImpl<?>> metaData = new ArrayList<ConstraintDescriptorImpl<?>>();
for ( Annotation annotation : ( (AnnotatedElement) member ).getAnnotations() ) {
for ( Annotation annotation : member.getDeclaredAnnotations() ) {
metaData.addAll( findConstraintAnnotations( annotation, type ) );
}

Expand All @@ -379,7 +380,7 @@ private List<ConstraintDescriptorImpl<?>> findConstraints(Member member, Element
*/
private List<ConstraintDescriptorImpl<?>> findClassLevelConstraints(Class<?> beanClass) {
List<ConstraintDescriptorImpl<?>> metaData = new ArrayList<ConstraintDescriptorImpl<?>>();
for ( Annotation annotation : beanClass.getAnnotations() ) {
for ( Annotation annotation : beanClass.getDeclaredAnnotations() ) {
metaData.addAll( findConstraintAnnotations( annotation, ElementType.TYPE ) );
}
return metaData;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2012, Red Hat, Inc. and/or its affiliates, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hibernate.validator.test.internal.metadata.provider;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.List;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.metadata.ConstraintDescriptor;

import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import org.hibernate.validator.constraints.ScriptAssert;
import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptions;
import org.hibernate.validator.internal.metadata.core.ConstraintHelper;
import org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider;
import org.hibernate.validator.internal.metadata.raw.BeanConfiguration;
import org.hibernate.validator.internal.metadata.raw.ConstrainedElement;
import org.hibernate.validator.internal.metadata.raw.ConstrainedType;
import org.hibernate.validator.testutil.TestForIssue;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertIterableSize;
import static org.testng.Assert.assertEquals;

/**
* Unit test for {@link AnnotationMetaDataProvider}.
*
* @author Gunnar Morling
*/
public class AnnotationMetaDataProviderTest {

private AnnotationMetaDataProvider provider;

@BeforeMethod
public void setUpProvider() {
provider = new AnnotationMetaDataProvider(
new ConstraintHelper(),
new AnnotationProcessingOptions()
);
}

@Test
@TestForIssue(jiraKey = "HV-626")
public void onlyLocallyDefinedConstraintsAreConsidered() {

List<BeanConfiguration<? super Person>> beanConfigurations = provider.getBeanConfigurationForHierarchy( Person.class );

ConstrainedType personType = findConstrainedType( beanConfigurations, Person.class );
assertIterableSize( personType.getConstraints(), 1 );
ConstraintDescriptor<?> constraintInSubType = personType.getConstraints()
.iterator()
.next()
.getDescriptor();
assertEquals( constraintInSubType.getAnnotation().annotationType(), ScriptAssert.class );

ConstrainedType personBaseType = findConstrainedType( beanConfigurations, PersonBase.class );
assertIterableSize( personBaseType.getConstraints(), 1 );

ConstraintDescriptor<?> constraintInSuperType = personBaseType.getConstraints()
.iterator()
.next()
.getDescriptor();
assertEquals( constraintInSuperType.getAnnotation().annotationType(), ClassLevelConstraint.class );
}

private <T> ConstrainedType findConstrainedType(Iterable<BeanConfiguration<? super T>> beanConfigurations, Class<? super T> type) {
for ( BeanConfiguration<?> oneConfiguration : beanConfigurations ) {
for ( ConstrainedElement constrainedElement : oneConfiguration.getConstrainedElements() ) {
if ( constrainedElement.getLocation().getElementType() == ElementType.TYPE ) {
ConstrainedType constrainedType = (ConstrainedType) constrainedElement;
if ( constrainedType.getLocation().getBeanClass().equals( type ) ) {
return constrainedType;
}
}
}
}

throw new RuntimeException( "Found no constrained element for type " + type );
}

@ClassLevelConstraint("some script")
private static class PersonBase {
}

@ScriptAssert(lang = "javascript", script = "some script")
private static class Person extends PersonBase {
}

@Target({ TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = { })
@Documented
@Inherited
public @interface ClassLevelConstraint {

String message() default "{ClassLevelConstraint.message}";

Class<?>[] groups() default { };

Class<? extends Payload>[] payload() default { };

String value();
}
}

0 comments on commit d6a95a3

Please sign in to comment.