В JDK существует набор связанных API -интерфейсов компиляции, которые могут инициировать процесс компиляции в Java, исходных файлов Parse Java и получить его синтаксисное дерево. Этот полный набор API включен в инструменты. Тем не менее, многие проекты использовали этот API, чтобы сделать много вещей. Например, знаменитый Ломбок использовал этот API для изменения синтаксического дерева в исходном коде на этапе обработки аннотаций. Окончательный результат эквивалентен вставке нового кода непосредственно в исходный файл!
Поскольку в этом наборе API в настоящее время не хватает соответствующих документов, его трудно использовать. Например, разрабатывайте все переменные в исходном коде и распечатайте их:
открытый класс Javaparser {Private Static Final String Path = "user.java"; Частный JavacfileManager FileManager; Частный Javactool Javactool; public javaparser () {context context = new Context (); fileManager = new JavacfileManager (контекст, true, charset.defaultcharset ()); javactool = new javactool (); } public void parsejavafiles () {iterable <!-? Extends javafileObject-> files = fileManager.getJavafileObjects (path); Javacompiler.compilationtask Компиляция task = javactool.gettask (null, filemanager, null, null, null, файлы); Javactask javactask = (javactask) сборник; Попробуйте {итерабильный <!-? Extends CompilationUnitTree-> result = javactask.parse (); for (koplationUnittree Tree: Result) {tree.accept (new Sourcevisitor (), null); }} catch (ioException e) {e.printstacktrace (); }} static class sourcevisitor extends treescanner <void, void = ""> {private String CurrentPackageName = null; @Override public void visitcompilationUnit (узел CompilationUnittree, void избегает) {return super.visitCompilationUnit (узел, избегание); } @Override public void visitVariable (variabletree node, void vest) {formatptrln ("Имя переменной: %s, тип: %s, вид: %s, пакет: %s", node.getname (), node.gettype (), node.getkind (), currentpackagename); вернуть ноль; }} public static void formatptrln (string format, object ... args) {system.out.println (string.format (format, args)); } public static void main (string [] args) {new javaparser (). parsejavafiles (); }} </void,>Код пользователя. Java выглядит следующим образом:
пакет com.ragnarok.javaparser; импорт com.sun.istack.internal.nullable; импорт java.lang.override; Пользователь открытого класса {@nullable Private String foo = "123123"; Частный Foo A; public void userMethod () {} статический класс foo {private String foostring = "123123"; public void foomethod () {}}}Результат выполнения приведенного выше Javaparser заключается в следующем:
Переменная: Foo, Annotaion: NullableVariable Имя: Foo, тип: строка, вид: переменная, пакет: com.ragnarok.javaparserver Имя переменной: A, тип: Foo, wind: variable, пакет: com.ragnarok.javaparser
Здесь мы сначала анализируем исходный файл через javacompiler.compilationTask, а затем используем пользовательский источник (унаследованный от TreesCanner) для доступа к структуре исходного кода. В классе Sourcevisitor мы перегружаем посещение визита, чтобы проанализировать блок компиляции (один файл исходного кода) и получить доступ ко всем переменным. Здесь можно увидеть, что мы не можем получить полностью квалифицированное имя этого типа переменной (включая имя пакета) и можем получить только соответствующее простое имя. Следовательно, определение типа требует внешней реализации, чтобы определить ее само по себе. Например, вы можете записать имя пакета, в котором находится класс, рекурсивно искать весь каталог исходного кода, чтобы отслеживать полностью квалифицированное имя всех классов, и обнаружить, содержит ли импорт соответствующий тип и т. Д.
В дополнение к методу визита, TreesCanner также содержит большое количество других методов визитагиза. Например, вы можете пройти все импорт, определения методов, аннотацию и т. Д. Для более конкретного конкретного, вы можете просмотреть исходный код об этом в OpenJDK.
Здесь мы возьмем еще один пример, перегружая метод VisitClass для доступа ко всем внутренним классам и сам класс:
@OverridePublic void VISTCLASS (Node ClassTree, void избегание) {formatptrln ("Имя класса: %s", node.getSimplename ()); for (rekemempor: node.getmembers ()) {if (exante -член variabletree) {variabletree variable = (variabletree) член; Список <!-? Extends AnnotationTree-> annotations = variable.getModifiers (). getAnnotation (); if (annotations.size ()> 0) {formatptrln ("variable: %s, annotaion: %s", variable.getname (), annotations.get (0) .getannotationtype ()); } else {formatptrln ("variable: %s", variable.getName ()); }}} return super.visitclass (node, избегание); }Здесь мы просто печатаем имя класса и имя переменной, тип и тип аннотации. Выполнить приведенный выше код, и результат заключается в следующем:
Название класса: Uservariable: Foo, Annotaion: NullableVariable: Имя класса: FOOVAILIAL: FOOSTRING
Видно, что мы распечатали имя класса и переменные в классе. В методе VisitClass мы можем получить всех членов класса с помощью метода GetMembers, включая переменные, методы, аннотацию и т. Д., Которые соответствуют различным типам. Например, переменные соответствуют типу variabletree, а метод соответствует типу метода.
В целом, хотя использование не особенно сложно на самом деле, оно вызвало большие препятствия для использования из -за отсутствия документации. И то, что мы представляем, является лишь небольшой частью этого API. Я буду продолжать изучать соответствующие функции этого API в будущем.
Выше приведено сборник данных анализатора JDK для анализа исходного кода Java. Мы будем продолжать добавлять соответствующую информацию в будущем. Спасибо за поддержку этого сайта!