Skip to content

Commit

Permalink
Execute and clear the validations by annotations.
Browse files Browse the repository at this point in the history
  • Loading branch information
wellingtoncosta committed Jan 23, 2018
1 parent e643fe3 commit fdab217
Show file tree
Hide file tree
Showing 12 changed files with 427 additions and 62 deletions.
4 changes: 2 additions & 2 deletions convalida-annotations/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ apply plugin: 'java'
apply plugin: 'maven'
group = 'com.github.WellingtonCosta'

sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8

task sourcesJar(type: Jar) {
from sourceSets.main.java.srcDirs
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package convalida.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.CLASS;

/**
* @author Wellington Costa on 19/01/2018.
*/
@Target(FIELD)
@Retention(CLASS)
public @interface ClearValidationsOnClick {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package convalida.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.CLASS;

/**
* @author Wellington Costa on 19/01/2018.
*/
@Target(METHOD)
@Retention(CLASS)
public @interface OnValidationError { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package convalida.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.CLASS;

/**
* @author Wellington Costa on 19/01/2018.
*/
@Target(METHOD)
@Retention(CLASS)
public @interface OnValidationSuccess { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package convalida.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.CLASS;

/**
* @author Wellington Costa on 19/01/2018.
*/
@Target(FIELD)
@Retention(CLASS)
public @interface ValidateOnClick { }
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
*/
class Constants {

static final ClassName UI_THREAD = ClassName.get("android.support.annotation", "UiThread");
static final ClassName OVERRIDE = ClassName.get("java.lang", "Override");

static final ClassName UI_THREAD = ClassName.get("android.support.annotation", "UiThread");
static final ClassName VIEW = ClassName.get("android.view", "View");
static final ClassName VIEW_ONCLICK_LISTENER = ClassName.get("android.view", "View.OnClickListener");

static final ClassName VALIDATOR = ClassName.get("convalida.validators", "ConvalidaValidator");
static final ClassName VALIDATOR_SET = ClassName.get("convalida.validators", "ValidatorSet");
static final ClassName VALIDATOR_SET = ClassName.get("convalida.validators", "ValidatorSet");

static final String NOT_EMPTY_ANNOTATION = "convalida.annotations.NotEmptyValidation";
static final String EMAIL_ANNOTATION = "convalida.annotations.EmailValidation";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,20 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
Expand All @@ -36,13 +40,17 @@
import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind;

import convalida.annotations.ClearValidationsOnClick;
import convalida.annotations.ConfirmPasswordValidation;
import convalida.annotations.EmailValidation;
import convalida.annotations.LengthValidation;
import convalida.annotations.NotEmptyValidation;
import convalida.annotations.OnValidationError;
import convalida.annotations.OnValidationSuccess;
import convalida.annotations.OnlyNumberValidation;
import convalida.annotations.PasswordValidation;
import convalida.annotations.PatternValidation;
import convalida.annotations.ValidateOnClick;
import convalida.compiler.internal.Id;
import convalida.compiler.internal.QualifiedId;
import convalida.compiler.internal.ValidationClass;
Expand All @@ -59,6 +67,16 @@
* @author Wellington Costa on 13/06/2017.
*/
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({
"convalida.annotations.NotEmptyValidation",
"convalida.annotations.EmailValidation",
"convalida.annotations.PatternValidation",
"convalida.annotations.LengthValidation",
"convalida.annotations.OnlyNumberValidation",
"convalida.annotations.PasswordValidation",
"convalida.annotations.ConfirmPasswordValidation"
})
public class ConvalidaProcessor extends AbstractProcessor {

private static final String TEXT_INPUT_LAYOUT_TYPE = "android.support.design.widget.TextInputLayout";
Expand Down Expand Up @@ -86,26 +104,6 @@ public synchronized void init(ProcessingEnvironment processingEnvironment) {
} catch (IllegalArgumentException ignored) { }
}

@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.RELEASE_7;
}

@Override
public Set<String> getSupportedAnnotationTypes() {
HashSet<String> supportedAnnotations = new HashSet<>();

supportedAnnotations.add(NotEmptyValidation.class.getCanonicalName());
supportedAnnotations.add(EmailValidation.class.getCanonicalName());
supportedAnnotations.add(PatternValidation.class.getCanonicalName());
supportedAnnotations.add(LengthValidation.class.getCanonicalName());
supportedAnnotations.add(OnlyNumberValidation.class.getCanonicalName());
supportedAnnotations.add(PasswordValidation.class.getCanonicalName());
supportedAnnotations.add(ConfirmPasswordValidation.class.getCanonicalName());

return supportedAnnotations;
}

private Set<Class<? extends Annotation>> getSupportedAnnotations() {
Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();

Expand Down Expand Up @@ -226,12 +224,128 @@ private List<ValidationClass> findAndParseValidations(RoundEnvironment env) {
}
}

parseValidateOnClick(parent, validationClass);
parseClearValidationsOnClick(parent, validationClass);

validationClasses.add(validationClass);
}

return validationClasses;
}

private void parseValidateOnClick(Element parent, ValidationClass validationClass) {
List<Element> elements = parent.getEnclosedElements()
.stream()
.filter(element -> element.getAnnotation(ValidateOnClick.class) != null)
.collect(Collectors.toList());

if (elements.size() > 1) {
error(
parent,
"The class %s must have only one element annotated with @ValidateOnClick annotation.",
parent.getSimpleName()
);
return;
}

if (elements.size() == 1) {
boolean isInaccessible = isInaccessible(ValidateOnClick.class, elements.get(0));
if (isInaccessible) return;

validationClass.setValidateButton(elements.get(0));
parseOnValidationSuccess(parent, validationClass);
parseOnValidationError(parent, validationClass);
}
}

private boolean validationMethodHasNoParams(Class<? extends Annotation> annotationClass, ExecutableElement method) {
boolean hasNoParams = true;

if (method.getParameters().size() > 0) {
hasNoParams = false;
error(method, "Method annotated with @%s can not have parameters.",annotationClass.getSimpleName());
}

return hasNoParams;
}

private void parseOnValidationSuccess(Element parent, ValidationClass validationClass) {
List<Element> elements = parent.getEnclosedElements()
.stream()
.filter(element -> element.getAnnotation(OnValidationSuccess.class) != null)
.collect(Collectors.toList());

if (elements.size() == 0) {
error(
parent,
"The class %s have an element annotated with @ValidateOnClick annotation and it requires a method annotated with @OnValidationSuccess annotation.",
parent.getSimpleName()
);
return;
}

if (elements.size() > 1) {
error(
parent,
"The class %s must have only one element annotated with @OnValidationSuccess annotation.",
parent.getSimpleName()
);
return;
}

if (elements.size() == 1) {
boolean isInaccessible = isInaccessible(OnValidationSuccess.class, elements.get(0));
boolean validationMethodHasNoParams = validationMethodHasNoParams(OnValidationSuccess.class, ((ExecutableElement) elements.get(0)));
if (isInaccessible && !validationMethodHasNoParams) return;

validationClass.setOnValidationSuccessMethod(elements.get(0));
}
}

private void parseOnValidationError(Element parent, ValidationClass validationClass) {
List<Element> elements = parent.getEnclosedElements()
.stream()
.filter(element -> element.getAnnotation(OnValidationError.class) != null)
.collect(Collectors.toList());

if (elements.size() > 1) {
error(
parent,
"The class %s must have only one element annotated with @OnValidationError annotation.",
parent.getSimpleName()
);
return;
}

if (elements.size() == 1) {
boolean isInaccessible = isInaccessible(OnValidationError.class, elements.get(0));
boolean validationMethodHasNoParams = validationMethodHasNoParams(OnValidationError.class, ((ExecutableElement) elements.get(0)));
if (isInaccessible && !validationMethodHasNoParams) return;

validationClass.setOnValidationErrorMethod(elements.get(0));
}
}

private void parseClearValidationsOnClick(Element parent, ValidationClass validationClass) {
List<Element> elements = parent.getEnclosedElements()
.stream()
.filter(element -> element.getAnnotation(ClearValidationsOnClick.class) != null)
.collect(Collectors.toList());

if (elements.size() > 1) {
error(
parent,
"The class %s must have only one element annotated with @ClearValidationsOnClick annotation.",
parent.getSimpleName()
);
return;
}

if (elements.size() == 1) {
validationClass.setClearValidationsButton(elements.get(0));
}
}

private void parseNotEmptyValidation(Element element, Set<Element> parents, List<ValidationField> validationFields) {
boolean hasError = isInvalid(NotEmptyValidation.class, element) || isInaccessible(NotEmptyValidation.class, element);

Expand Down Expand Up @@ -560,7 +674,6 @@ private void parseCompiledR(String respectivePackageName, TypeElement rClass) {
}
}


private void logParsingError(Element element, Class<? extends Annotation> annotation, Exception e) {
StringWriter stackTrace = new StringWriter();
e.printStackTrace(new PrintWriter(stackTrace));
Expand Down
Loading

0 comments on commit fdab217

Please sign in to comment.