インサートコールアウトプロセッサ

7914 ワード

Javacコマンドの-processorパラメータでコンパイルを実行するには付属の注釈プロセッサが必要で、複数の注釈プロセッサがあればカンマで区切ります.
-XprintRoundsおよび-XprintProcessorInfoパラメータを使用して、注記プロセッサの動作の詳細を表示することもできます.
NameCheckProcessorの例では、JSR-269埋め込み注釈処理APIの一部の機能のみが実証されています.このAPIのセットに基づいてサポートされている項目には、Hibernateラベルの正確性を検証するためのHibernate Validator Annotation Processor(本質的にはNameCheckProcessorとはあまり差がありません)があり、フィールドにgetterメソッドとsetterメソッドを自動的に生成するProject Lombokがあります.(既存の要素に基づいて新しい構文ツリー要素を生成する)など、
コードは次のとおりです.
import java.util.EnumSet;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
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.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementScanner7;
import javax.tools.Diagnostic.Kind;
/**
 * javac NameCheckProcessor.java
 * javac -processor NameCheckProcessor FT.java
 * @author kevin
 *
 */


//  *       Annotations 
@SupportedAnnotationTypes(value = "*")
@SupportedSourceVersion(value = SourceVersion.RELEASE_7)
public class NameCheckProcessor extends AbstractProcessor {
	@Override
	public synchronized void init(ProcessingEnvironment processingEnv) {
		super.init(processingEnv);
		this.nameCheck = new NameCheck(processingEnv);
	}

	private NameCheck nameCheck;

	@Override
	public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
		if (!roundEnv.processingOver()) {
			for (Element element : roundEnv.getRootElements()) {
				nameCheck.check(element);
			}
		}
		return false;
	}

	/**
	 *                        ,          Warning  
	 * 
	 * @author kevin
	 * 
	 */
	public static class NameCheck {
		Messager messager = null;
		public NameCheckScanner nameCheckScanner;

		private NameCheck(ProcessingEnvironment processingEnv) {
			messager = processingEnv.getMessager();
			nameCheckScanner = new NameCheckScanner(processingEnv);
		}

		/**
		 *  Java        ,  《Java    ( 3 )》6.8    ,Java            :
		 * <ul>
		 * <li>    :       ,     。
		 * <li>  :       ,     。
		 * <li>  :
		 * <ul>
		 * <li> ,    :       ,     。
		 * <li>  :      
		 * </ul>
		 * </ul>
		 * 
		 * @param element
		 */
		public void check(Element element) {
			nameCheckScanner.scan(element);
		}

		/**
		 *         ,   1.6     ElementScanner6<br>
		 *    Visitor             
		 * 
		 * @author kevin
		 * 
		 */
		public static class NameCheckScanner extends ElementScanner7<Void, Void> {
			Messager messager = null;

			public NameCheckScanner(ProcessingEnvironment processingEnv) {
				this.messager = processingEnv.getMessager();
			}

			/**
			 *        Java 
			 */
			@Override
			public Void visitType(TypeElement e, Void p) {
				scan(e.getTypeParameters(), p);
				checkCamelCase(e, true);
				super.visitType(e, p);
				return null;
			}

			/**
			 *      Element         ,     ,       
			 * 
			 * @param e
			 * @param b
			 */
			private void checkCamelCase(Element e, boolean initialCaps) {
				String name = e.getSimpleName().toString();
				boolean previousUpper = false;
				boolean conventional = true;
				int firstCodePoint = name.codePointAt(0);
				if (Character.isUpperCase(firstCodePoint)) {
					previousUpper = true;
					if (!initialCaps) {
						messager.printMessage(Kind.WARNING, "  :" + name + "          ", e);
						return;
					}
				} else if (Character.isLowerCase(firstCodePoint)) {
					if (initialCaps) {
						messager.printMessage(Kind.WARNING, "  :" + name + "          ", e);
						return;
					}
				} else {
					conventional = false;
				}
				if (conventional) {
					int cp = firstCodePoint;
					for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {
						cp = name.codePointAt(i);
						if (Character.isUpperCase(cp)) {
							if (previousUpper) {
								conventional = false;
								break;
							}
							previousUpper = true;
						} else {
							previousUpper = false;
						}
					}
				}
				if (!conventional) {
					messager.printMessage(Kind.WARNING, "  :" + name + "         (Camel Case Names)", e);
				}
			}

			/**
			 *           
			 */
			@Override
			public Void visitExecutable(ExecutableElement e, Void p) {
				if (e.getKind() == ElementKind.METHOD) {
					Name name = e.getSimpleName();
					if (name.contentEquals(e.getEnclosingElement().getSimpleName())) {
						messager.printMessage(Kind.WARNING, "      :" + name + "         ,           ", e);
						checkCamelCase(e, false);
					}
				}
				super.visitExecutable(e, p);
				return null;
			}

			/**
			 *         
			 */
			@Override
			public Void visitVariable(VariableElement e, Void p) {
				/*     Variable      ,        ,              */
				if (e.getKind() == ElementKind.ENUM_CONSTANT || e.getConstantValue() != null || heuristicallyConstant(e)) {
					checkAllCaps(e);
				} else {
					checkCamelCase(e, false);
				}
				super.visitVariable(e, p);
				return null;
			}

			/**
			 *       ,                 ,              
			 * 
			 * @param e
			 */
			private void checkAllCaps(VariableElement e) {
				String name = e.getSimpleName().toString();
				boolean conventional = true;
				int firstCodePoint = name.codePointAt(0);
				if (!Character.isUpperCase(firstCodePoint)) {
					conventional = false;
				} else {
					boolean previousUnderscore = false;
					int cp = firstCodePoint;
					for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {
						cp = name.codePointAt(i);
						if (cp == (int) '_') {
							if (previousUnderscore) {
								conventional = false;
								break;
							}
							previousUnderscore = true;
						} else {
							previousUnderscore = false;
							if (!Character.isUpperCase(cp) && !Character.isDigit(cp)) {
								conventional = false;
								break;
							}
						}

					}
				}
				if (!conventional) {
					messager.printMessage(Kind.WARNING, "  :" + name + "          " + "      ,       ", e);
				}
			}

			/**
			 *            
			 * 
			 * @param e
			 * @return
			 */
			private boolean heuristicallyConstant(VariableElement e) {
				if (e.getEnclosingElement().getKind() == ElementKind.INTERFACE) {
					return true;
				} else if (e.getKind() == ElementKind.FIELD && e.getModifiers().containsAll(EnumSet.of(javax.lang.model.element.Modifier.FINAL, javax.lang.model.element.Modifier.STATIC, javax.lang.model.element.Modifier.PUBLIC))) {
					return true;
				}
				return false;
			}
		}
	}

}

テストクラスを書きます.
import java.util.ArrayList;
import java.util.List;

public class FT {
	public static class A_B_C {

	}
	public static String ab_sd="";
	public static int method(List<Integer> list) {
		System.out.println("method(List<Integer>list)");
		return 1;
	}

	public static void main(String[] args) {
		method(new ArrayList<Integer>());
		Long aLong = 2l;
		Integer aInteger = 1;
		Integer bInteger = 1;
		System.out.println(aLong.equals(aInteger + bInteger));
		System.out.println(aInteger.equals(1L));
		System.out.println("true");
	}
}

次にコマンドラインに入ってみましょう
javac NameCheckProcessor.java 
javac -processor NameCheckProcessor FT.java
FT.java:4:警告:名称:FTはアルパカ式命名法(Camel Case Name)に適合しなければならない
public class FT {
       ^
1つの警告