Checking compilation time of method arguments

I found several similar questions here, but the incomplete answers did not help and did not cause more confusion than clarifying anything, so here I will try to give a more structured question and get reliable answers that will help more users.

My simplified example : I have a Java class with two different constructors

public class ObjectOfInterest {
  public ObjectOfInterest(String string, Integer int) { ... }
  public ObjectOfInterest(String string1, String string2) { ... }
  ...
}

I need some compilation checking time when calling these constructors. The parameter string2should be laconic, and I want to mark calls as a warning depending on the content (i.e. give a warning if it is not a literal or when the literal has the wrong format).

Unfortunately, the documentation for validation in Java with Eclipse is not so easy to understand, sometimes outdated, most often it seems incomplete, and it seems that there is no working example short enough for use in the tutorial.

My goal : First step: I would like to have a validator that marks calls to this version of the parameters with a warning - just to start somewhere and understand the basics.

What I have found so far : A few examples that I have seen are public class MyValidator implements IValidator, ISourceValidatorwhere IValidatorit is necessary to implement the method public void validate(IValidationContext arg0, IReporter arg1) throws ValidationExceptionand, it seems, from the old version of the verification framework (sometimes I found only an empty method with comment useless) and ISourceValidatorit is necessary to implement the method public void validate(IRegion arg0, IValidationContext arg1, IReporter arg2)- this, by Apparently a more modern version.

plugin.xml ( , plugin.xml).

: , IRegion, IValidationContext IReporter - , , ? ?

, . Outlook, String- - , , , .

+6
2

, , , Java. , , .

, , , . , Java. , , .

, , , :


Eclipse Plug-in Solution

, , , , - Eclipse, Eclipse Java . , , , , Eclipse.


, () , :

.

, . . , , . , . .

, , , , , !

+3

:

. . , . , .

Java- , JDK-5 JDK-6 JSR-269.

(java @interfaces), . , , , ( ). , . github. , github https://github.com/hjchanna/compile_validation_java

01: (@interface)

package com.mac.compile_validation;

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

/**
 * @author hjchanna
 */
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface CompileValidation {

}

02: Processor,

extend javax.annotation.processing.AbstractProcessor, @SupportedAnnotationTypes @SupportedSourceVersion. CompileValidationProcessor .

package com.mac.compile_validation;

import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
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.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.tools.Diagnostic;

/**
 *
 * @author hjchanna
 */
@SupportedAnnotationTypes("com.mac.compile_validation.CompileValidation")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class CompileValidationProcessor extends AbstractProcessor {

    /**
     * Processes a set of annotation types on type elements originating from the
     * prior round and returns whether or not these annotation types are claimed
     * by this processor. If {@code
     * true} is returned, the annotation types are claimed and subsequent
     * processors will not be asked to process them; if {@code false} is
     * returned, the annotation types are unclaimed and subsequent processors
     * may be asked to process them. A processor may always return the same
     * boolean value or may vary the result based on chosen criteria.
     *
     * The input set will be empty if the processor supports {@code
     * "*"} and the root elements have no annotations. A {@code
     * Processor} must gracefully handle an empty set of annotations.
     *
     * @param annotations the annotation types requested to be processed
     * @param roundEnv environment for information about the current and prior
     * round
     * @return whether or not the set of annotation types are claimed by this
     * processor
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //Iterate through compiling files which annotated with @CompileValidation
        for (Element elem : roundEnv.getElementsAnnotatedWith(CompileValidation.class)) {
            //find type element for element
            TypeElement typeElement = findEnclosingTypeElement(elem);

            //required parameter types
            TypeElement stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String");
            TypeElement integerType = processingEnv.getElementUtils().getTypeElement("java.lang.Integer");

            //find construtors according to your scenario
            ExecutableElement conA = findConstructor(typeElement, stringType.asType(), integerType.asType());
            ExecutableElement conB = findConstructor(typeElement, stringType.asType(), stringType.asType());

            //check availability of constructors, if not available it should show a warning message in compile time
            if (conA == null || conB == null) {
                String message = "Type " + typeElement + " has malformed constructors.";
                processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, message);
            }

        }
        return true; // no further processing of this annotation type
    }

    /**
     * Returns a constructor which have two parameters and parameter types equal
     * to paramA and paramB. Return null if required constructor is not
     * available.
     *
     * @param typeElement like the class which may constructors encapsulated
     * @param paramA first parameter of required constructor
     * @param paramB second parameter of required constructor
     * @return constructor which have required parameters
     */
    private static ExecutableElement findConstructor(TypeElement typeElement, TypeMirror paramA, TypeMirror paramB) {
        List<ExecutableElement> executableElements = ElementFilter.constructorsIn(typeElement.getEnclosedElements());

        for (ExecutableElement executableElement : executableElements) {
            List<VariableElement> variableElements = (List<VariableElement>) executableElement.getParameters();

            //match constructor params and length
            if (variableElements.size() == 2
                    && variableElements.get(0).asType().equals(paramA)
                    && variableElements.get(1).asType().equals(paramB)) {
                return executableElement;
            }
        }

        return null;
    }

    /**
     * Returns the TypeElement of element e.
     *
     * @param e Element which contain TypeElement
     * @return Type element
     */
    public static TypeElement findEnclosingTypeElement(Element e) {
        while (e != null && !(e instanceof TypeElement)) {
            e = e.getEnclosingElement();
        }

        return TypeElement.class.cast(e);
    }
}

03:

javax.annotation.processing.Processor (/src/main/resources/META-INF/services). Processor. .

com.mac.compile_validation.CompileValidationProcessor

maven-. META-INF/services .jar.

04:

. , , Processor . . , - . pom.xml ( <build> -> <plugin>).

<compilerArgument>-proc:none</compilerArgument>

. , , build output .jar.

. , (CompileValidation). , . .

build output

  • PMD, java. xml.
  • , java- . ( , , , spring, hibernate ).
  • Java Instrumentation API, , . .
+1

Source: https://habr.com/ru/post/1671682/


All Articles