package com.farata.cleardatabuilder.extjs.validation.apt;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.persistence.Entity;
import org.eclipse.jdt.apt.core.util.EclipseMessager;
import clear.cdb.extjs.annotations.JSJPQLMethod;
import com.farata.cleardatabuilder.extjs.validation.IValidationConstants;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.AnnotationMirror;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.declaration.AnnotationTypeElementDeclaration;
import com.sun.mirror.declaration.AnnotationValue;
import com.sun.mirror.declaration.ClassDeclaration;
import com.sun.mirror.declaration.Declaration;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.type.TypeMirror;
import com.sun.mirror.util.SourcePosition;
public class JSJPQLMethodProcessor implements AnnotationProcessor,
IValidationConstants {
private static final String CLASS_OF_THE_COLLECTION_ELEMENTS_IS_NOT_SPECIFIED_AND_TRANSFER_INFO_PARAMETER_IS_MISSING = "Class of the collection elements is not specified and transferInfo parameter is missing";
private static final String TYPE_ATTRIBUTE_SHOULD_BE_NOT_EMPTY = "'type' attribute should be not empty";
private AnnotationProcessorEnvironment _env;
JSJPQLMethodProcessor(AnnotationProcessorEnvironment _env) {
this._env = _env;
}
@Override
public void process() {
EclipseMessager messager = (EclipseMessager) _env.getMessager();
// obtain the declaration of the annotation we want to process
AnnotationTypeDeclaration annoDecl = (AnnotationTypeDeclaration) _env
.getTypeDeclaration(JSJPQLMethod.class.getName());
// get the annotated types
Collection<Declaration> annotatedTypes = _env
.getDeclarationsAnnotatedWith(annoDecl);
for (Declaration decl : annotatedTypes) {
Collection<AnnotationMirror> mirrors = decl.getAnnotationMirrors();
// for each annotation found, get a map of element name/value pairs
for (AnnotationMirror mirror : mirrors) {
if (!"JSJPQLMethod".equals(mirror.getAnnotationType()
.getDeclaration().getSimpleName())) {
continue;
}
MethodDeclaration methodDeclaration = (MethodDeclaration) decl;
JSJPQLMethodProcessor.checkReturnType(mirror,
methodDeclaration, messager);
JSJPQLMethodProcessor.checkTransferInfo(mirror,
methodDeclaration, true, messager);
JSJPQLMethodProcessor.checkUpdateInfo(mirror,
methodDeclaration, messager);
}
}
}
public static boolean checkTransferInfo(AnnotationMirror mirror,
MethodDeclaration methodDeclaration, boolean checkReturnType, EclipseMessager messager) {
Map<AnnotationTypeElementDeclaration, AnnotationValue> valueMap = mirror
.getElementValues();
Set<Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue>> valueSet = valueMap
.entrySet();
boolean found = false;
for (Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue> annoKeyValue : valueSet) {
if (annoKeyValue.getKey().getSimpleName().equals("transferInfo")) {
found = true;
checkTransferInfoType(annoKeyValue.getValue(), messager);
checkIfAnnotationValueAttributeIsEntity(
(AnnotationMirror) annoKeyValue.getValue().getValue(),
"mappedBy", messager);
break;
}
}
if (!found && checkReturnType) {
TypeMirror returnType = methodDeclaration.getReturnType();
String returnTypeName = returnType.toString();
if (returnTypeName.equals("java.util.List<?>")
|| returnTypeName.equals("java.util.List")
|| returnTypeName.equals("java.util.Collection<?>")
|| returnTypeName.equals("java.util.Collection")) {
// System.out.println(returnType);
SourcePosition pos = mirror.getPosition();
messager
.printFixableError(
pos,
CLASS_OF_THE_COLLECTION_ELEMENTS_IS_NOT_SPECIFIED_AND_TRANSFER_INFO_PARAMETER_IS_MISSING,
PLUGIN_ID, ERROR_transferInfo_is_missing);
return false;
}
}
return true;
}
private static boolean checkUpdateInfo(AnnotationMirror mirror,
MethodDeclaration methodDeclaration, EclipseMessager messager) {
Map<AnnotationTypeElementDeclaration, AnnotationValue> valueMap = mirror
.getElementValues();
Set<Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue>> valueSet = valueMap
.entrySet();
for (Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue> annoKeyValue : valueSet) {
if (annoKeyValue.getKey().getSimpleName().equals("updateInfo")) {
checkIfAnnotationValueAttributeIsEntity(
(AnnotationMirror) annoKeyValue.getValue().getValue(),
"updateEntity", messager);
}
}
return true;
}
private static boolean checkTransferInfoType(
AnnotationValue annotationValue, EclipseMessager messager) {
AnnotationMirror mirror = (AnnotationMirror) annotationValue.getValue();
Map<AnnotationTypeElementDeclaration, AnnotationValue> valueMap = mirror
.getElementValues();
Set<Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue>> valueSet = valueMap
.entrySet();
for (Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue> annoKeyValue : valueSet) {
if (annoKeyValue.getKey().getSimpleName().equals("type")) {
String annoValue = (String) annoKeyValue.getValue().getValue();
if (annoValue != null && annoValue.trim().length() == 0) {
SourcePosition pos = annoKeyValue.getValue().getPosition();
messager
.printError(pos, TYPE_ATTRIBUTE_SHOULD_BE_NOT_EMPTY);
}
return false;
}
}
return true;
}
public static boolean checkIfAnnotationValueAttributeIsEntity(
AnnotationMirror mirror, String attributeName,
EclipseMessager messager) {
Map<AnnotationTypeElementDeclaration, AnnotationValue> valueMap = mirror
.getElementValues();
Set<Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue>> valueSet = valueMap
.entrySet();
for (Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue> annoKeyValue : valueSet) {
if (annoKeyValue.getKey().getSimpleName().equals(attributeName)) {
ClassDeclaration annoValue = (ClassDeclaration) annoKeyValue
.getValue().getValue();
Entity entityAnnotation = annoValue.getAnnotation(Entity.class);
if (entityAnnotation == null) {
SourcePosition pos = annoKeyValue.getValue().getPosition();
messager
.printError(
pos,
"'"
+ attributeName
+ "' attribute value class should be annotated with 'javax.persistence.Entity'");
return false;
}
}
}
return true;
}
public static boolean checkReturnType(AnnotationMirror mirror,
MethodDeclaration methodDeclaration, EclipseMessager messager) {
TypeMirror returnType = methodDeclaration.getReturnType();
String returnTypeName = returnType.toString();
if (!(returnTypeName.startsWith("java.util.List") || returnTypeName
.startsWith("java.util.Collection"))) {
messager
.printFixableError(
methodDeclaration.getPosition(),
"Method should return java.util.List or java.util.Collection",
PLUGIN_ID, ERROR_wrong_return_type);
return false;
}
return true;
}
}