/*
* 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.ap;
import java.util.Collection;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;
import org.hibernate.validator.ap.checks.ConstraintCheckIssue;
import org.hibernate.validator.ap.classchecks.ClassCheck;
import org.hibernate.validator.ap.classchecks.ClassCheckFactory;
import org.hibernate.validator.ap.util.AnnotationApiHelper;
import org.hibernate.validator.ap.util.CollectionHelper;
import org.hibernate.validator.ap.util.Configuration;
import org.hibernate.validator.ap.util.ConstraintHelper;
import org.hibernate.validator.ap.util.MessagerAdapter;
/**
* An {@link javax.lang.model.element.ElementVisitor} that visits methods of classes and interfaces and applies
* different checks to them. Each {@link ConstraintCheckIssue} occurred will be reported using the
* {@link javax.annotation.processing.Messager} API.
*
* @author Marko Bekhta
*/
public class ClassVisitor extends AbstractElementVisitor<Void, Void> {
private final ClassCheckFactory factory;
private final Elements elementUtils;
public ClassVisitor(
ProcessingEnvironment processingEnvironment,
MessagerAdapter messager,
Configuration configuration) {
super( messager, configuration );
this.elementUtils = processingEnvironment.getElementUtils();
this.factory = ClassCheckFactory.getInstance(
processingEnvironment.getTypeUtils(),
processingEnvironment.getElementUtils(),
new ConstraintHelper(
processingEnvironment.getTypeUtils(),
new AnnotationApiHelper(
processingEnvironment.getElementUtils(), processingEnvironment.getTypeUtils()
)
)
);
}
/**
* Doesn't perform any checks at the moment but calls a visit methods on its own elements.
*
* @param element a class element to check
* @param aVoid
*/
@Override
public Void visitTypeAsClass(TypeElement element, Void aVoid) {
visitAllMyElements( element );
return null;
}
/**
* Doesn't perform any checks at the moment but calls a visit methods on its own elements.
*
* @param element a class element to check
* @param aVoid
*/
@Override
public Void visitTypeAsInterface(TypeElement element, Void aVoid) {
visitAllMyElements( element );
return null;
}
/**
* Checks whether the constraints of the given method are valid.
*
* @param element a method under investigation
* @param aVoid
*/
@Override
public Void visitExecutableAsMethod(ExecutableElement element, Void aVoid) {
processClassChecks( element );
return null;
}
/**
* Visits all inner elements of provided {@link TypeElement}.
*
* @param typeElement inner elements of which you want to visit
*/
private void visitAllMyElements(TypeElement typeElement) {
for ( Element element : elementUtils.getAllMembers( typeElement ) ) {
visit( element );
}
}
private void processClassChecks(Element element) {
try {
Set<ConstraintCheckIssue> allIssues = CollectionHelper.newHashSet();
Collection<ClassCheck> classChecks = factory.getClassChecks( element );
for ( ClassCheck classCheck : classChecks ) {
allIssues.addAll( classCheck.execute( element ) );
}
reportIssues( allIssues );
}
//HV-293: if single constraints can't be properly checked, report this and
//proceed with next constraints
catch (Exception e) {
if ( verbose ) {
messager.getDelegate().printMessage(
Diagnostic.Kind.NOTE,
e.getMessage() != null ? e.getMessage() : e.toString(),
element
);
}
}
}
}