org.hibernate.validator.cfg.AnnotationDef Maven / Gradle / Ivy
Show all versions of hibernate-validator Show documentation
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or .
*/
package org.hibernate.validator.cfg;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.internal.util.annotation.AnnotationDescriptor;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
/**
* Base class for all annotation definition types.
*
* Note that any protected member in this type and its subtypes are not part of the public API and are only meant for internal use.
*
* @param The type of a concrete sub type. Following to the
* "self referencing generic type" pattern each sub type has to be
* parametrized with itself.
* @param The constraint annotation type represented by a concrete sub type.
*
* @author Hardy Ferentschik
* @author Gunnar Morling
* @author Marko Bekhta
* @author Guillaume Smet
*/
public abstract class AnnotationDef, A extends Annotation> {
private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
// Note on visibility of members: These members are intentionally made
// protected and published by a sub-class for internal use. There aren't
// public getters as they would pollute the fluent definition API.
/**
* The annotation descriptor builder.
*/
private final AnnotationDescriptor.Builder annotationDescriptorBuilder;
/**
* A map with annotation parameters of this definition which are annotations
* on their own. Keys are property names of this definition's annotation
* type, values are annotation parameter values of the appropriate annotation
* types described via {@link AnnotationDef}. If an array of annotations is
* needed it should be represented via {@link java.util.List} of corresponding
* {@link AnnotationDef}s.
*/
private final Map>> annotationsAsParameters;
/**
* A map of annotation types that are added to {@link AnnotationDef#annotationsAsParameters}.
* For the same key form {@link AnnotationDef#annotationsAsParameters} you'll get an annotation
* type represented by corresponding {@link AnnotationDef}
*/
private final Map> annotationsAsParametersTypes;
protected AnnotationDef(Class annotationType) {
this.annotationDescriptorBuilder = new AnnotationDescriptor.Builder<>( annotationType );
this.annotationsAsParameters = new HashMap<>();
this.annotationsAsParametersTypes = new HashMap<>();
}
protected AnnotationDef(AnnotationDef, A> original) {
this.annotationDescriptorBuilder = original.annotationDescriptorBuilder;
this.annotationsAsParameters = original.annotationsAsParameters;
this.annotationsAsParametersTypes = original.annotationsAsParametersTypes;
}
@SuppressWarnings("unchecked")
private C getThis() {
return (C) this;
}
protected C addParameter(String key, Object value) {
annotationDescriptorBuilder.setAttribute( key, value );
return getThis();
}
protected C addAnnotationAsParameter(String key, AnnotationDef, ?> value) {
annotationsAsParameters.compute( key, ( k, oldValue ) -> {
if ( oldValue == null ) {
return Collections.singletonList( value );
}
else {
List> resultingList = CollectionHelper.newArrayList( oldValue );
resultingList.add( value );
return resultingList;
}
} );
annotationsAsParametersTypes.putIfAbsent( key, value.annotationDescriptorBuilder.getType() );
return getThis();
}
private AnnotationDescriptor createAnnotationDescriptor() {
for ( Map.Entry>> annotationAsParameter : annotationsAsParameters.entrySet() ) {
annotationDescriptorBuilder.setAttribute(
annotationAsParameter.getKey(),
toAnnotationParameterArray(
annotationAsParameter.getValue(),
annotationsAsParametersTypes.get( annotationAsParameter.getKey() )
)
);
}
try {
return annotationDescriptorBuilder.build();
}
catch (RuntimeException e) {
throw LOG.getUnableToCreateAnnotationForConfiguredConstraintException( e );
}
}
private A createAnnotationProxy() {
return createAnnotationDescriptor().getAnnotation();
}
@SuppressWarnings("unchecked")
private T[] toAnnotationParameterArray(List> list, Class aClass) {
return list.stream()
.map( AnnotationDef::createAnnotationProxy )
.toArray( n -> (T[]) Array.newInstance( aClass, n ) );
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append( this.getClass().getSimpleName() );
sb.append( '{' );
sb.append( annotationDescriptorBuilder );
sb.append( '}' );
return sb.toString();
}
}