{"id":266971,"date":"2015-10-28T14:19:08","date_gmt":"2015-10-28T11:19:08","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=266971"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=266971","title":{"rendered":"\u0420\u0430\u0437\u0431\u043e\u0440 Java \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e java \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b"},"content":{"rendered":"<p>       \u0420\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441 \u0442\u0435\u043e\u0440\u0438\u0435\u0439 \u0432 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/269037\/\">\u00ab\u041c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0438 \u0447\u0442\u043e \u043b\u0443\u0447\u0448\u0435 \u043c\u0435\u043d\u044f\u0442\u044c: \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u0438\u043b\u0438 AST \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b?\u00bb<\/a>. \u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Eclipse java compiler API.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/a24\/d35\/d88\/a24d35d88a8d48b1834172661d8255c2.jpg\"\/><\/p>\n<p>  Java \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0430\u0440\u0438\u0432\u0430\u0435\u0442 java \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443, \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0434 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0434\u0435\u0440\u0435\u0432\u043e\u043c (AST)\u2026<br \/>  <a name=\"habracut\"><\/a><\/p>\n<p>  \u041f\u0435\u0440\u0435\u0434 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b, \u0445\u043e\u0440\u043e\u0448\u043e \u0431\u044b \u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0435\u0435 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%BE%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE\">\u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c<\/a> \u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430. \u0421 \u044d\u0442\u043e\u0433\u043e \u0438 \u043d\u0430\u0447\u043d\u0435\u043c.<\/p>\n<p>  \u041f\u043e\u0432\u0442\u043e\u0440\u044e\u0441\u044c \u0432\u044b\u0432\u043e\u0434\u0430\u043c\u0438 \u0438\u0437 \u0441\u0432\u043e\u0435\u0439 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438, \u0447\u0442\u043e \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0445 \u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u043d\u0430 java \u043d\u0435\u0442 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0438 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0433\u043e API \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0434\u0435\u0440\u0435\u0432\u043e\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. \u041f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043b\u0438\u0431\u043e \u0441 <a href=\"http:\/\/docs.oracle.com\/javase\/8\/docs\/jdk\/api\/javac\/tree\/index.html\">com.sun.source.tree.*<\/a> \u043b\u0438\u0431\u043e org.eclipse.jdt.core.dom.*<\/p>\n<p>  \u0412\u044b\u0431\u043e\u0440 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u2014 Eclipse java compiler (ejc) \u0438 \u0435\u0433\u043e AST \u043c\u043e\u0434\u0435\u043b\u044c <a href=\"http:\/\/help.eclipse.org\/mars\/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fjdt%2Fcore%2Fdom%2FExpression.html\">org.eclipse.jdt.core.dom.*<\/a><\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0434\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u0432\u043e\u0434\u043e\u0432 \u0432 \u043f\u043e\u043b\u044c\u0437\u0443 ejc:  <\/p>\n<ul>\n<li>\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 <a href=\"http:\/\/central.maven.org\/maven2\/org\/eclipse\/tycho\/org.eclipse.jdt.core\/3.11.0.v20150602-1242\/org.eclipse.jdt.core-3.11.0.v20150602-1242.pom\">maven \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u0430\u0440\u0438\u0438<\/a> \u0438 \u043d\u0435 \u043d\u0430\u0434\u043e \u043d\u0430\u0434\u0435\u044f\u0442\u044c\u0441\u044f \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 tools.jar<\/li>\n<li>\u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 JavaCompiler API<\/li>\n<li>\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 java 8<\/li>\n<li>\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 Eclipse Java IDE \u0438 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e ejc \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440<\/li>\n<\/ul>\n<p>  \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 AST java \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b, \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0445\u043e\u0434\u0438\u0442\u044c \u0432\u0441\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0438\u0437 jar \u0444\u0430\u0439\u043b\u0430 \u0438 \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c <br \/>  \u0432\u044b\u0437\u043e\u0432\u044b \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0445 \u043d\u0430\u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043a\u043b\u0430\u0441\u0441\u043e\u0432-\u043b\u043e\u0433\u0435\u0440\u043e\u0432 org.slf4j.Logger, org.apache.commons.logging.Log, org.springframework.boot.cli.util.Log<\/p>\n<p>  \u0417\u0430\u0434\u0430\u0447\u0430 \u0441 \u043f\u043e\u0438\u0441\u043a\u043e\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430 \u043b\u0435\u0433\u043a\u043e \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b\u0441\u044f \u0432 maven \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u0430\u0440\u0438\u0439 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u043e\u043c \u0442\u0438\u043f\u0430 source \u0438 \u0432 jar \u0441 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 \u0435\u0441\u0442\u044c \u0444\u0430\u0439\u043b\u044b pom.properties \u0438\u043b\u0438 pom.xml. \u0421 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b, \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 MavenCoordHelper \u0438\u0437 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0430 io.fabric8.insight:insight-log4j \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0438\u0437 Maven \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u0430\u0440\u0438\u044f MavenClassLoader \u0438\u0437 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0430 com.github.smreed:dropship.<\/p>\n<p>  MavenCoordHelper \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u0439\u0442\u0438 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b group:artifact:version \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 pom.properties. \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043d\u0430\u0439\u0442\u0438 maven \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b groupId:artifactId:version \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430:  <\/p>\n<pre><code class=\"java\">    public static String getMavenSourcesId(String className) {         String mavenCoordinates = io.fabric8.insight.log.log4j.MavenCoordHelper.getMavenCoordinates(className);         if(mavenCoordinates==null) return null;         DefaultArtifact artifact = new DefaultArtifact(mavenCoordinates);         return String.format(&quot;%s:%s:%s:sources:%s&quot;, artifact.getGroupId(), artifact.getArtifactId(),                                                     artifact.getExtension(), artifact.getVersion());     } <\/code><\/pre>\n<p>  MavenClassLoader \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u043f\u043e \u044d\u0442\u0438\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c classpath (\u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0442\u0440\u0430\u043d\u0437\u0438\u0442\u0438\u0432\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438) \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432 \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435. \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0438\u0437 maven \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u0430\u0440\u0438\u044f:  <\/p>\n<pre><code class=\"java\">    public static LoadingCache&lt;String, URLClassLoader&gt; createMavenClassloaderCache() {         return CacheBuilder.newBuilder()                 .maximumSize(MAX_CACHE_SIZE)                 .build(new CacheLoader&lt;String, URLClassLoader&gt;() {                     @Override                     public URLClassLoader load(String mavenId) throws Exception {                         return com.github.smreed.dropship.MavenClassLoader.forMavenCoordinates(mavenId);                     }                 });     } <\/code><\/pre>\n<p>  \u0421\u0430\u043c\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430 EJC \u0438 \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 AST \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f:  <\/p>\n<pre><code class=\"java\">package com.github.igorsuhorukov.java.ast;  import com.google.common.cache.LoadingCache; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.CompilationUnit; import java.net.URLClassLoader; import java.util.Set; import static com.github.igorsuhorukov.java.ast.ParserUtils.*;  public class Parser {     public static final String[] SOURCE_PATH = new String[]{System.getProperty(&quot;java.io.tmpdir&quot;)};     public static final String[] SOURCE_ENCODING = new String[]{&quot;UTF-8&quot;};      public static void main(String[] args) throws Exception {          if(args.length!=1) throw new IllegalArgumentException(&quot;Class name should be specified&quot;);         String file = getJarFileByClass(Class.forName(args[0]));         Set&lt;String&gt; classes = getClasses(file);         LoadingCache&lt;String, URLClassLoader&gt; classLoaderCache = createMavenClassloaderCache();          for (final String currentClassName : classes) {              String mavenSourcesId = getMavenSourcesId(currentClassName);             if (mavenSourcesId == null)                 throw new IllegalArgumentException(&quot;Maven group:artifact:version not found for class &quot; + currentClassName);              URLClassLoader urlClassLoader = classLoaderCache.get(mavenSourcesId);              ASTParser parser = ASTParser.newParser(AST.JLS8);             parser.setResolveBindings(true);             parser.setKind(ASTParser.K_COMPILATION_UNIT);             parser.setCompilerOptions(JavaCore.getOptions());              parser.setEnvironment(prepareClasspath(urlClassLoader), SOURCE_PATH, SOURCE_ENCODING, true);              parser.setUnitName(currentClassName + &quot;.java&quot;);              String sourceText = getClassSourceCode(currentClassName, urlClassLoader);             if(sourceText == null) continue;              parser.setSource(sourceText.toCharArray());                          CompilationUnit cu = (CompilationUnit) parser.createAST(null);              cu.accept(new LoggingVisitor(cu, currentClassName));         }     } } <\/code><\/pre>\n<p>  \u0427\u0430\u0441\u0442\u044c \u043c\u0430\u0433\u0438\u0438, \u0447\u0442\u043e \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043f\u0440\u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0435, \u0441\u043a\u0440\u044b\u0442\u0430 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 ParserUtils, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u0437\u0430 \u0441\u0447\u0435\u0442 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u043b\u0430\u0441\u044c \u0432\u044b\u0448\u0435.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">ParserUtils.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package com.github.igorsuhorukov.java.ast;  import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.io.CharStreams; import org.sonatype.aether.util.artifact.DefaultArtifact;  import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.net.URLClassLoader; import java.security.CodeSource; import java.util.Arrays; import java.util.Collections; import java.util.Set; import java.util.function.Function; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.stream.Collectors;  public class ParserUtils {      public static final int MAX_CACHE_SIZE = 1000;      public static Set&lt;String&gt; getClasses(String file) throws IOException {         return Collections.list(new JarFile(file).entries()).stream()                 .filter(jar -&gt; jar.getName().endsWith(&quot;class&quot;) && !jar.getName().contains(&quot;$&quot;))                 .map(new Function&lt;JarEntry, String&gt;() {                     @Override                     public String apply(JarEntry jarEntry) {                         return jarEntry.getName().replace(&quot;.class&quot;, &quot;&quot;).replace('\/', '.');                     }                 }).collect(Collectors.toSet());     }      public static String getMavenSourcesId(String className) {         String mavenCoordinates = io.fabric8.insight.log.log4j.MavenCoordHelper.getMavenCoordinates(className);         if(mavenCoordinates==null) return null;         DefaultArtifact artifact = new DefaultArtifact(mavenCoordinates);         return String.format(&quot;%s:%s:%s:sources:%s&quot;, artifact.getGroupId(), artifact.getArtifactId(),                                                     artifact.getExtension(), artifact.getVersion());     }      public static LoadingCache&lt;String, URLClassLoader&gt; createMavenClassloaderCache() {         return CacheBuilder.newBuilder()                 .maximumSize(MAX_CACHE_SIZE)                 .build(new CacheLoader&lt;String, URLClassLoader&gt;() {                     @Override                     public URLClassLoader load(String mavenId) throws Exception {                         return com.github.smreed.dropship.MavenClassLoader.forMavenCoordinates(mavenId);                     }                 });     }      public static String[] prepareClasspath(URLClassLoader urlClassLoader) {         return Arrays.stream(urlClassLoader.getURLs()).map(new Function&lt;URL, String&gt;() {             @Override             public String apply(URL url) {                 return url.getFile();             }         }).toArray(String[]::new);     }      public static String getJarFileByClass(Class&lt;?&gt; clazz) {         CodeSource source = clazz.getProtectionDomain().getCodeSource();         String file = null;         if (source != null) {             URL locationURL = source.getLocation();             if (&quot;file&quot;.equals(locationURL.getProtocol())) {                 file = locationURL.getPath();             } else {                 file = locationURL.toString();             }         }         return file;     }      static String getClassSourceCode(String className, URLClassLoader urlClassLoader) throws IOException {         String sourceText = null;         try (InputStream javaSource = urlClassLoader.getResourceAsStream(className.replace(&quot;.&quot;, &quot;\/&quot;) + &quot;.java&quot;)) {             if (javaSource != null){                 try (InputStreamReader sourceReader = new InputStreamReader(javaSource)){                     sourceText = CharStreams.toString(sourceReader);                 }             }         }         return sourceText;     } } <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  \u0418 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u00ab\u0444\u0430\u0440\u0448\u00bb \u0441 \u0440\u0430\u0437\u0431\u043e\u0440\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0445 \u043d\u0430\u0441 \u043c\u0435\u0441\u0442 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043b\u043e\u0433\u0433\u0435\u0440\u043e\u0432 \u0432 \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435 \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d \u0432 LoggingVisitor<br \/>  \u0420\u0430\u0441\u0448\u0438\u0440\u044f\u044f \u043a\u043b\u0430\u0441\u0441 <b>ASTVisitor<\/b> \u0438 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0436\u0430\u044f \u0432 \u043d\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <b>public boolean visit(MethodInvocation node)<\/b>, \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0435\u0433\u043e \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0443 ejc. \u0412 \u044d\u0442\u043e\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0435\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u0447\u0442\u043e \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0442 \u0438 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">LoggingVisitor.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package com.github.igorsuhorukov.java.ast;  import org.eclipse.jdt.core.dom.*;  import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set;  class LoggingVisitor extends ASTVisitor {      final static Set&lt;String&gt; LOGGER_CLASS = new HashSet&lt;String&gt;() {{         add(&quot;org.slf4j.Logger&quot;);         add(&quot;org.apache.commons.logging.Log&quot;);         add(&quot;org.springframework.boot.cli.util.Log&quot;);     }};      final static Set&lt;String&gt; LOGGER_METHOD = new HashSet&lt;String&gt;() {{         add(&quot;fatal&quot;);         add(&quot;error&quot;);         add(&quot;warn&quot;);         add(&quot;info&quot;);         add(&quot;debug&quot;);         add(&quot;trace&quot;);     }};      public static final String LITERAL = &quot;Literal&quot;;     public static final String FORMAT_METHOD = &quot;format&quot;;      private final CompilationUnit cu;     private final String currentClassName;      public LoggingVisitor(CompilationUnit cu, String currentClassName) {         this.cu = cu;         this.currentClassName = currentClassName;     }      @Override     public boolean visit(MethodInvocation node) {         if (LOGGER_METHOD.contains(node.getName().getIdentifier())) {             ITypeBinding objType = node.getExpression() != null ? node.getExpression().resolveTypeBinding() : null;             if (objType != null && LOGGER_CLASS.contains(objType.getBinaryName())) {                  int lineNumber = cu.getLineNumber(node.getStartPosition());                  boolean isFormat = false;                 boolean isConcat = false;                 boolean isLiteral1 = false;                 boolean isLiteral2 = false;                 boolean isMethod = false;                 boolean withException = false;                  for (int i = 0; i &lt; node.arguments().size(); i++) {                     ASTNode innerNode = (ASTNode) node.arguments().get(i);                     if (i == node.arguments().size() - 1) {                         if (innerNode instanceof SimpleName && ((SimpleName) innerNode).resolveTypeBinding() != null) {                             ITypeBinding typeBinding = ((SimpleName) innerNode).resolveTypeBinding();                             while (typeBinding != null && Object.class.getName().equals(typeBinding.getBinaryName())) {                                 if (Throwable.class.getName().equals(typeBinding.getBinaryName())) {                                     withException = true;                                     break;                                 }                                 typeBinding = typeBinding.getSuperclass();                             }                             if (withException) continue;                         }                     }                     if (innerNode instanceof MethodInvocation) {                         MethodInvocation methodInvocation = (MethodInvocation) innerNode;                         if (FORMAT_METHOD.equals(methodInvocation.getName().getIdentifier()) && methodInvocation.getExpression() != null                                 && methodInvocation.getExpression().resolveTypeBinding() != null                                 && String.class.getName().equals(methodInvocation.getExpression().resolveTypeBinding().getBinaryName())) {                             isFormat = true;                         } else {                             isMethod = true;                         }                     } else if (innerNode instanceof InfixExpression) {                         InfixExpression infixExpression = (InfixExpression) innerNode;                         if (InfixExpression.Operator.PLUS.equals(infixExpression.getOperator())) {                             List expressions = new ArrayList();                             expressions.add(infixExpression.getLeftOperand());                             expressions.add(infixExpression.getRightOperand());                             expressions.addAll(infixExpression.extendedOperands());                             long stringLiteralCount = expressions.stream().filter(item -&gt; item instanceof StringLiteral).count();                             long notLiteralCount = expressions.stream().filter(item -&gt; item.getClass().getName().contains(LITERAL)).count();                             if (notLiteralCount &gt; 0 && stringLiteralCount &gt; 0) {                                 isConcat = true;                             }                         }                     } else if (innerNode instanceof Expression && innerNode.getClass().getName().contains(LITERAL)) {                         isLiteral1 = true;                     } else if (innerNode instanceof SimpleName || innerNode instanceof QualifiedName                             || innerNode instanceof ConditionalExpression || innerNode instanceof ThisExpression                             || innerNode instanceof ParenthesizedExpression                             || innerNode instanceof PrefixExpression || innerNode instanceof PostfixExpression                             || innerNode instanceof ArrayCreation || innerNode instanceof ArrayAccess                             || innerNode instanceof FieldAccess || innerNode instanceof ClassInstanceCreation) {                         isLiteral2 = true;                     }                 }                 String type = loggerInvocationType(node, isFormat, isConcat, isLiteral1 || isLiteral2, isMethod);                 System.out.println(currentClassName + &quot;:&quot; + lineNumber + &quot;\\t\\t\\t&quot; + node+&quot;\\t\\ttype &quot;+type); \/\/node.getStartPosition()              }         }         return true;     }      private String loggerInvocationType(MethodInvocation node, boolean isFormat, boolean isConcat, boolean isLiteral, boolean isMethod) {         if (!isConcat && !isFormat && isLiteral) {             return &quot;literal&quot;;         } else {             if (isFormat && isConcat) {                 return &quot;format concat&quot;;             } else if (isFormat && !isLiteral) {                 return &quot;format&quot;;             } else if (isConcat && !isLiteral) {                 return &quot;concat&quot;;             } else {                 if (isConcat || isFormat || isLiteral) {                     if (node.arguments().size() == 1) {                         return &quot;single argument&quot;;                     } else {                         return  &quot;mixed logging&quot;;                     }                 }             }             if(isMethod){                 return &quot;method&quot;;             }         }         return &quot;unknown&quot;;     } } <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b-\u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0432   <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;project xmlns=&quot;http:\/\/maven.apache.org\/POM\/4.0.0&quot; xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot;          xsi:schemaLocation=&quot;http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/maven-v4_0_0.xsd&quot;&gt;     &lt;parent&gt;         &lt;groupId&gt;org.sonatype.oss&lt;\/groupId&gt;         &lt;artifactId&gt;oss-parent&lt;\/artifactId&gt;         &lt;version&gt;7&lt;\/version&gt;     &lt;\/parent&gt;     &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;     &lt;groupId&gt;com.github.igor-suhorukov&lt;\/groupId&gt;     &lt;artifactId&gt;java-ast&lt;\/artifactId&gt;     &lt;packaging&gt;jar&lt;\/packaging&gt;     &lt;version&gt;1.0-SNAPSHOT&lt;\/version&gt;     &lt;properties&gt;         &lt;maven.compiler.source&gt;1.8&lt;\/maven.compiler.source&gt;         &lt;maven.compiler.target&gt;1.8&lt;\/maven.compiler.target&gt;         &lt;insight.version&gt;1.2.0.redhat-133&lt;\/insight.version&gt;     &lt;\/properties&gt;     &lt;dependencies&gt;         &lt;!-- EJC --&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.eclipse.tycho&lt;\/groupId&gt;             &lt;artifactId&gt;org.eclipse.jdt.core&lt;\/artifactId&gt;             &lt;version&gt;3.11.0.v20150602-1242&lt;\/version&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.eclipse.core&lt;\/groupId&gt;             &lt;artifactId&gt;runtime&lt;\/artifactId&gt;             &lt;version&gt;3.9.100-v20131218-1515&lt;\/version&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.eclipse.birt.runtime&lt;\/groupId&gt;             &lt;artifactId&gt;org.eclipse.core.resources&lt;\/artifactId&gt;             &lt;version&gt;3.8.101.v20130717-0806&lt;\/version&gt;         &lt;\/dependency&gt;          &lt;!-- MAVEN --&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.fabric8.insight&lt;\/groupId&gt;             &lt;artifactId&gt;insight-log4j&lt;\/artifactId&gt;             &lt;version&gt;${insight.version}&lt;\/version&gt;             &lt;exclusions&gt;                 &lt;exclusion&gt;                     &lt;groupId&gt;*&lt;\/groupId&gt;                     &lt;artifactId&gt;*&lt;\/artifactId&gt;                 &lt;\/exclusion&gt;             &lt;\/exclusions&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.fabric8.insight&lt;\/groupId&gt;             &lt;artifactId&gt;insight-log-core&lt;\/artifactId&gt;             &lt;version&gt;${insight.version}&lt;\/version&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.fabric8&lt;\/groupId&gt;             &lt;artifactId&gt;common-util&lt;\/artifactId&gt;             &lt;version&gt;${insight.version}&lt;\/version&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;com.github.igor-suhorukov&lt;\/groupId&gt;             &lt;artifactId&gt;aspectj-scripting&lt;\/artifactId&gt;             &lt;version&gt;1.0&lt;\/version&gt;             &lt;classifier&gt;agent&lt;\/classifier&gt;         &lt;\/dependency&gt;           &lt;dependency&gt;             &lt;groupId&gt;com.google.guava&lt;\/groupId&gt;             &lt;artifactId&gt;guava&lt;\/artifactId&gt;             &lt;version&gt;19.0-rc2&lt;\/version&gt;         &lt;\/dependency&gt;          &lt;!-- Dependency to analyze --&gt;         &lt;dependency&gt;             &lt;groupId&gt;com.googlecode.log4jdbc&lt;\/groupId&gt;             &lt;artifactId&gt;log4jdbc&lt;\/artifactId&gt;             &lt;version&gt;1.2&lt;\/version&gt;         &lt;\/dependency&gt;      &lt;\/dependencies&gt; &lt;\/project&gt; <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0432 com.github.igorsuhorukov.java.ast.Parser \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432, \u043a\u0430\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440, \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438\u043c\u044f \u043a\u043b\u0430\u0441\u0441\u0430 net.sf.log4jdbc.ConnectionSpy<br \/>  \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0432\u044b\u0432\u043e\u0434 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c \u043a\u0430\u043a\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0432 \u043c\u0435\u0442\u043e\u0434\u044b:<\/p>\n<blockquote><p>[Dropship WARN] No dropship.properties found! Using .dropship-prefixed system properties (-D)<br \/>  [Dropship INFO] Collecting maven metadata.<br \/>  [Dropship INFO] Resolving dependencies.<br \/>  [Dropship INFO] Building classpath for com.googlecode.log4jdbc:log4jdbc:jar:sources:1.2 from 2 URLs.<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:104 jdbcLogger.error(header,e) type literal<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:105 sqlOnlyLogger.error(header,e) type literal<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:106 sqlTimingLogger.error(header,e) type literal<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:111 jdbcLogger.error(header + &quot; &quot; + sql,e) type mixed logging<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:116 sqlOnlyLogger.error(getDebugInfo() + nl + spyNo+ &quot;. &quot;+ sql,e) type mixed logging<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:120 sqlOnlyLogger.error(header + &quot; &quot; + sql,e) type mixed logging<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:126 sqlTimingLogger.error(getDebugInfo() + nl + spyNo+ &quot;. &quot;+ sql+ &quot; {FAILED after &quot;+ execTime+ &quot; msec}&quot;,e) type mixed logging<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:130 sqlTimingLogger.error(header + &quot; FAILED! &quot; + sql+ &quot; {FAILED after &quot;+ execTime+ &quot; msec}&quot;,e) type mixed logging<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:158 logger.debug(header + &quot; &quot; + getDebugInfo()) type concat<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:162 logger.info(header) type literal<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:221 sqlOnlyLogger.debug(getDebugInfo() + nl + spy.getConnectionNumber()+ &quot;. &quot;+ processSql(sql)) type concat<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:226 sqlOnlyLogger.info(processSql(sql)) type method<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:352 sqlTimingLogger.error(buildSqlTimingDump(spy,execTime,methodCall,sql,sqlTimingLogger.isDebugEnabled())) type method<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:360 sqlTimingLogger.warn(buildSqlTimingDump(spy,execTime,methodCall,sql,sqlTimingLogger.isDebugEnabled())) type method<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:365 sqlTimingLogger.debug(buildSqlTimingDump(spy,execTime,methodCall,sql,true)) type method<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:370 sqlTimingLogger.info(buildSqlTimingDump(spy,execTime,methodCall,sql,false)) type method<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:519 debugLogger.debug(msg) type literal<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:531 connectionLogger.info(spy.getConnectionNumber() + &quot;. Connection opened &quot; + getDebugInfo()) type concat<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:533 connectionLogger.debug(ConnectionSpy.getOpenConnectionsDump()) type method<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:537 connectionLogger.info(spy.getConnectionNumber() + &quot;. Connection opened&quot;) type concat<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:550 connectionLogger.info(spy.getConnectionNumber() + &quot;. Connection closed &quot; + getDebugInfo()) type concat<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:552 connectionLogger.debug(ConnectionSpy.getOpenConnectionsDump()) type method<br \/>  net.sf.log4jdbc.Slf4jSpyLogDelegator:556 connectionLogger.info(spy.getConnectionNumber() + &quot;. Connection closed&quot;) type concat  <\/p><\/blockquote>\n<p>  \u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u0440\u0430\u0437\u0431\u043e\u0440 \u0438 \u0430\u043d\u0430\u043b\u0438\u0437 java \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043b\u0435\u0433\u043a\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432 java \u043a\u043e\u0434\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430 ejc \u0438 \u0442\u0430\u043a\u0436\u0435 \u043b\u0435\u0433\u043a\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 Maven \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u0430\u0440\u0438\u044f \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u043a\u043e\u0434\u044b \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0445 \u043d\u0430\u0441 \u043a\u043b\u0430\u0441\u0441\u043e\u0432.<\/p>\n<p>  \u0412\u043f\u0435\u0440\u0435\u0434\u0438 \u043d\u0430\u0441 \u0436\u0434\u0435\u0442 Java agent, \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c \u2014 \u0437\u0430\u0434\u0430\u0447\u0430 <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u043d\u0435\u0435 \u0438 \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u0447\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0432\u0430\u0440\u0438\u0432\u0430\u043d\u0438\u0435 AST&#8230;<\/b><\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/142\/98e\/b52\/14298eb52cba4f2aa3774934333844a0.jpg\"\/><\/div>\n<\/div>\n<p>  \u0414\u043e \u0441\u043a\u043e\u0440\u044b\u0445 \u0432\u0441\u0442\u0440\u0435\u0447!               <\/p>\n<div class=\"clear\"><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/269129\/\"> http:\/\/habrahabr.ru\/post\/269129\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>       \u0420\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441 \u0442\u0435\u043e\u0440\u0438\u0435\u0439 \u0432 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/269037\/\">\u00ab\u041c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0438 \u0447\u0442\u043e \u043b\u0443\u0447\u0448\u0435 \u043c\u0435\u043d\u044f\u0442\u044c: \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u0438\u043b\u0438 AST \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b?\u00bb<\/a>. \u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Eclipse java compiler API.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/a24\/d35\/d88\/a24d35d88a8d48b1834172661d8255c2.jpg\"\/><\/p>\n<p>  Java \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0430\u0440\u0438\u0432\u0430\u0435\u0442 java \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443, \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0434 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0434\u0435\u0440\u0435\u0432\u043e\u043c (AST)\u2026  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-266971","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/266971","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=266971"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/266971\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=266971"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=266971"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=266971"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}