Skip to content

Commit

Permalink
HV-441, HV-443: Pulling constraint origin adaption up to MetaDetaBuil…
Browse files Browse the repository at this point in the history
…der in order to adapt method constraints, too.
  • Loading branch information
gunnarmorling committed Sep 5, 2011
1 parent 54e185b commit 357ad14
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 113 deletions.
Expand Up @@ -464,12 +464,16 @@ public BeanMetaDataImpl<T> build() {

private static class BuilderDelegate {

private PropertyMetaData.Builder propertyBuilder;
private final ConstraintHelper constraintHelper;

private MetaDataBuilder propertyBuilder;

private MethodMetaData.Builder methodBuilder;

public BuilderDelegate(ConstrainedElement constrainedElement, ConstraintHelper constraintHelper) {

this.constraintHelper = constraintHelper;

switch ( constrainedElement.getConstrainedElementKind() ) {

case FIELD:
Expand All @@ -481,7 +485,7 @@ public BuilderDelegate(ConstrainedElement constrainedElement, ConstraintHelper c
case METHOD:

ConstrainedMethod constrainedMethod = (ConstrainedMethod) constrainedElement;
methodBuilder = new MethodMetaData.Builder( constrainedMethod );
methodBuilder = new MethodMetaData.Builder( constrainedMethod, constraintHelper );

if ( constrainedMethod.isGetterMethod() ) {
propertyBuilder = new PropertyMetaData.Builder( constrainedMethod, constraintHelper );
Expand Down Expand Up @@ -510,7 +514,10 @@ public boolean add(ConstrainedElement constrainedElement) {
propertyBuilder.add( constrainedElement );

if ( added == false && constrainedElement.getConstrainedElementKind() == ConstrainedElementKind.METHOD && methodBuilder == null ) {
methodBuilder = new MethodMetaData.Builder( (ConstrainedMethod) constrainedElement );
methodBuilder = new MethodMetaData.Builder(
(ConstrainedMethod) constrainedElement,
constraintHelper
);
}

added = true;
Expand Down
Expand Up @@ -24,7 +24,6 @@
import org.hibernate.validator.engine.ConstraintTree;
import org.hibernate.validator.engine.ValidationContext;
import org.hibernate.validator.engine.ValueContext;
import org.hibernate.validator.metadata.location.BeanConstraintLocation;
import org.hibernate.validator.metadata.location.ConstraintLocation;
import org.hibernate.validator.util.ReflectionHelper;

Expand Down Expand Up @@ -93,7 +92,7 @@ public ConstraintLocation getLocation() {
protected final Type typeOfAnnotatedElement() {
return location.typeOfAnnotatedElement();
}

/**
* @param o the object from which to retrieve the value.
*
Expand Down
Expand Up @@ -16,8 +16,13 @@
*/
package org.hibernate.validator.metadata;

import java.lang.annotation.Annotation;
import java.util.Set;

import org.hibernate.validator.metadata.constrained.ConstrainedElement;

import static org.hibernate.validator.util.CollectionHelper.newHashSet;

/**
* Builds {@link ConstraintMetaData} instances for the
* {@link ConstrainedElement} objects representing one method or property in a
Expand All @@ -27,6 +32,12 @@
*/
public abstract class MetaDataBuilder {

protected final ConstraintHelper constraintHelper;

protected MetaDataBuilder(ConstraintHelper constraintHelper) {
this.constraintHelper = constraintHelper;
}

/**
* Whether this builder allows to add the given element or not. This is the
* case if the specified element relates to the same property or method with
Expand Down Expand Up @@ -57,4 +68,76 @@ public abstract class MetaDataBuilder {
*/
public abstract ConstraintMetaData build();

}
/**
* Adapts the given constraints to the given bean type. In case a constraint
* is defined locally at the bean class the original constraint will be
* returned without any modifications. If a constraint is defined in the
* hierarchy (interface or super class) a new constraint will be returned
* with an origin of {@link ConstraintOrigin#DEFINED_IN_HIERARCHY}. If a
* constraint is defined on an interface, the interface type will
* additionally be part of the constraint's groups (implicit grouping).
*
* @param <A> The type of the constraint's annotation.
* @param beanClass The bean type to which the constraint shall be adapted.
* @param constraint The constraint that shall be adapted. This constraint itself
* will not be altered.
*
* @return A constraint adapted to the given bean type.
*/
protected Set<MetaConstraint<?>> adaptOriginsAndImplicitGroups(Class<?> beanClass,
Set<MetaConstraint<?>> constraints) {
Set<MetaConstraint<?>> adaptedConstraints = newHashSet();

for ( MetaConstraint<?> oneConstraint : constraints ) {
adaptedConstraints.add(
adaptOriginAndImplicitGroup(
beanClass, oneConstraint
)
);
}
return adaptedConstraints;
}

private <A extends Annotation> MetaConstraint<A> adaptOriginAndImplicitGroup(
Class<?> beanClass, MetaConstraint<A> constraint) {

ConstraintOrigin definedIn = definedIn( beanClass, constraint.getLocation().getBeanClass() );

if ( definedIn == ConstraintOrigin.DEFINED_LOCALLY ) {
return constraint;
}

Class<?> constraintClass = constraint.getLocation().getBeanClass();

ConstraintDescriptorImpl<A> descriptor = new ConstraintDescriptorImpl<A>(
(A) constraint.getDescriptor().getAnnotation(),
constraintHelper,
constraintClass.isInterface() ? constraintClass : null,
constraint.getElementType(),
definedIn
);

return new MetaConstraint<A>(
descriptor,
constraint.getLocation()
);
}

/**
* @param rootClass The root class. That is the class for which we currently
* create a {@code BeanMetaData}
* @param hierarchyClass The class on which the current constraint is defined on
*
* @return Returns {@code ConstraintOrigin.DEFINED_LOCALLY} if the
* constraint was defined on the root bean,
* {@code ConstraintOrigin.DEFINED_IN_HIERARCHY} otherwise.
*/
private ConstraintOrigin definedIn(Class<?> rootClass, Class<?> hierarchyClass) {
if ( hierarchyClass.equals( rootClass ) ) {
return ConstraintOrigin.DEFINED_LOCALLY;
}
else {
return ConstraintOrigin.DEFINED_IN_HIERARCHY;
}
}
}
Expand Up @@ -91,23 +91,22 @@ public static class Builder extends MetaDataBuilder {

private final Set<MetaConstraint<?>> returnValueConstraints = newHashSet();

private boolean isCascading;
private boolean isCascading = false;

private boolean isConstrained;
private boolean isConstrained = false;

/**
* Creates a new builder based on the given method meta data.
*
* @param constrainedMethod The base method for this builder. This is the lowest
* method with a given signature within a type hierarchy.
*/
public Builder(ConstrainedMethod constrainedMethod) {
public Builder(ConstrainedMethod constrainedMethod, ConstraintHelper constraintHelper) {

super( constraintHelper );

location = constrainedMethod.getLocation();
constrainedMethods.add( constrainedMethod );
isCascading = constrainedMethod.isCascading();
isConstrained = constrainedMethod.isConstrained();
returnValueConstraints.addAll( constrainedMethod.getConstraints() );
add( constrainedMethod );
}

/**
Expand Down Expand Up @@ -143,7 +142,7 @@ public MethodMetaData build() {
return
new MethodMetaData(
this,
returnValueConstraints,
adaptOriginsAndImplicitGroups( location.getBeanClass(), returnValueConstraints ),
findParameterMetaData(),
checkParameterConstraints(),
isCascading,
Expand All @@ -168,7 +167,13 @@ private List<ParameterMetaData> findParameterMetaData() {
parameterBuilders = newArrayList();

for ( ConstrainedParameter oneParameter : oneMethod.getAllParameterMetaData() ) {
parameterBuilders.add( new ParameterMetaData.Builder( oneParameter ) );
parameterBuilders.add(
new ParameterMetaData.Builder(
location.getBeanClass(),
oneParameter,
constraintHelper
)
);
}
}
else {
Expand Down
Expand Up @@ -63,16 +63,27 @@ public String getName() {

public static class Builder extends MetaDataBuilder {

private final Class<?> rootClass;

private final Class<?> parameterType;

private final int parameterIndex;

private final Set<MetaConstraint<?>> constraints = newHashSet();

private String name;

private ConstrainedParameter root;
private boolean isCascading = false;

private Set<ConstrainedParameter> parameters = newHashSet();
public Builder(Class<?> rootClass, ConstrainedParameter constrainedParameter, ConstraintHelper constraintHelper) {

public Builder(ConstrainedParameter constrainedParameter) {
this.root = constrainedParameter;
this.parameters.add( constrainedParameter );
this.name = root.getParameterName();
super( constraintHelper );

this.rootClass = rootClass;
this.parameterType = constrainedParameter.getLocation().getParameterType();
this.parameterIndex = constrainedParameter.getLocation().getParameterIndex();

add( constrainedParameter );
}

@Override
Expand All @@ -82,39 +93,32 @@ public boolean accepts(ConstrainedElement constrainedElement) {
return false;
}

ConstrainedParameter constrainedParameter = (ConstrainedParameter) constrainedElement;

return constrainedParameter.getLocation().getParameterIndex() == root.getLocation().getParameterIndex();
return ( (ConstrainedParameter) constrainedElement ).getLocation().getParameterIndex() == parameterIndex;
}

@Override
public void add(ConstrainedElement constrainedElement) {

ConstrainedParameter constrainedParameter = (ConstrainedParameter) constrainedElement;
parameters.add( constrainedParameter );

constraints.addAll( constrainedParameter.getConstraints() );

if ( name == null ) {
name = constrainedParameter.getParameterName();
}

isCascading = isCascading || constrainedParameter.isCascading();
}

@Override
public ParameterMetaData build() {

Set<MetaConstraint<?>> constraints = newHashSet();
boolean isCascading = false;

for ( ConstrainedParameter oneParameter : parameters ) {
constraints.addAll( oneParameter.getConstraints() );
isCascading = isCascading || oneParameter.isCascading();
}

return new ParameterMetaData(
constraints,
adaptOriginsAndImplicitGroups( rootClass, constraints ),
isCascading,
name,
root.getLocation().getParameterType(),
root.getLocation().getParameterIndex()
parameterType,
parameterIndex
);
}

Expand Down

0 comments on commit 357ad14

Please sign in to comment.