Verwendungshinweise zu JavaParser

Was ist JavaParser?

Hello World ** Abhängigkeiten **

build.gradle


dependencies {
    compile 'com.github.javaparser:javaparser-core:3.3.0'
}

Implementierung

Main.java


package sample.javaparser;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) {
        Path source = Paths.get("src/main/java/sample/javaparser/Main.java");
        try {
            CompilationUnit unit = JavaParser.parse(source);
            System.out.println("***********************************************");
            System.out.println(unit);
            System.out.println("***********************************************");
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}

** Ausführungsergebnis **

***********************************************
package sample.javaparser;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {

    public static void main(String[] args) {
        Path source = Paths.get("src/main/java/sample/javaparser/Main.java");
        try {
            CompilationUnit unit = JavaParser.parse(source);
            System.out.println("***********************************************");
            System.out.println(unit);
            System.out.println("***********************************************");
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}

***********************************************

Erläuterung

VoidVisitor Implementierung

MyVoidVisitor.java


package sample.javaparser;

import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

public class MyVoidVisitor extends VoidVisitorAdapter<String> {

    @Override
    public void visit(VariableDeclarator n, String arg) {
        System.out.println("n > " + n);
        System.out.println("arg > " + arg);
        super.visit(n, arg);
    }
}

Main.java


package sample.javaparser;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) {
        Path source = Paths.get("src/main/java/sample/javaparser/Main.java");
        
        try {
            CompilationUnit unit = JavaParser.parse(source);
            
            unit.accept(new MyVoidVisitor(), "ARG!!");
            
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}

** Ausführungsergebnis **

n > source = Paths.get("src/main/java/sample/javaparser/Main.java")
arg > ARG!!
n > unit = JavaParser.parse(source)
arg > ARG!!

Erläuterung

MyVoidVisitor.java


import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

public class MyVoidVisitor extends VoidVisitorAdapter<String> {

    @Override
    public void visit(VariableDeclarator n, String arg) {
        System.out.println("n > " + n);
        System.out.println("arg > " + arg);
        super.visit(n, arg);
    }

Main.java


            CompilationUnit unit = JavaParser.parse(source);
            
            unit.accept(new MyVoidVisitor(), "ARG!!");

--Visitor kann verwendet werden, indem es anaccept ()der Klasse CompliationUnit` übergeben wird.

Compliation Unit akzeptieren()Methodenimplementierung


    @Override
    public <A> void accept(VoidVisitor<A> v, A arg) {
        v.visit(this, arg); //★ Besucherbesuch stornieren()Wird so genannt wie es ist
    }

GenericVisitor Implementierung

MyGenericVisitor.java


package sample.javaparser;

import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.visitor.GenericVisitorAdapter;

public class MyGenericVisitor extends GenericVisitorAdapter<Integer, String> {
    
    @Override
    public Integer visit(VariableDeclarator n, String arg) {
        System.out.println(arg);
        System.out.println(n);
        super.visit(n, arg);
        return -1;
    }
}

Main.java


package sample.javaparser;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) {
        Path source = Paths.get("src/main/java/sample/javaparser/Main.java");
        
        try {
            CompilationUnit unit = JavaParser.parse(source);
            
            int result = unit.accept(new MyGenericVisitor(), "ARG!!");
            System.out.println(result);
            
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}

** Ausführungsergebnis **

ARG!!
source = Paths.get("src/main/java/sample/javaparser/Main.java")
-1

Erläuterung

MyGenericVisitor.java


import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.visitor.GenericVisitorAdapter;

public class MyGenericVisitor extends GenericVisitorAdapter<Integer, String> {
    
    @Override
    public Integer visit(VariableDeclarator n, String arg) {
        System.out.println(arg);
        System.out.println(n);
        super.visit(n, arg);
        return -1;
    }

--VoidVisitorsvisit ()hat keinen Rückgabewert, aber GenericVisitors visit () hat einen Rückgabewert.

Knotentyp

Die im abstrakten Syntaxbaum enthaltenen Knoten erben von der Node-Klasse und haben die folgende Vererbungsbeziehung.

Node
┣━ArrayCreationLevel
┣━CatchClause
┣━CompilationUnit
┣━ImportDeclaration
┣━MemberValuePair
┣━ModuleDeclaration
┣━Name
┣━PackageDeclaration
┣━Parameter
┣━SimpleName
┣━VariableDeclarator
┃ 
┣━BodyDeclaration
┃ ┣━AnnotationMemberDeclaration
┃ ┣━EnumConstantDeclaration
┃ ┣━FieldDeclaration
┃ ┣━InitializerDeclaration
┃ ┣━CallableDeclaration
┃ ┃ ┣━ConstructorDeclaration
┃ ┃ ┗━MethodDeclaration
┃ ┗━TypeDeclaration
┃   ┣━AnnotationDeclaration
┃   ┣━ClassOrInterfaceDeclaration
┃   ┗━EnumDeclaration
┃ 
┣━Comment
┃ ┣━BlockComment
┃ ┣━JavadocComment
┃ ┗━LineComment
┃ 
┣━Expression
┃ ┣━ArrayAccessExpr
┃ ┣━ArrayCreationExpr
┃ ┣━ArrayInitializerExpr
┃ ┣━AssignExpr
┃ ┣━BinaryExpr
┃ ┣━CastExpr
┃ ┣━ClassExpr
┃ ┣━ConditionalExpr
┃ ┣━EnclosedExpr
┃ ┣━FieldAccessExpr
┃ ┣━InstanceOfExpr
┃ ┣━LambdaExpr
┃ ┣━MethodCallExpr
┃ ┣━MethodReferenceExpr
┃ ┣━NameExpr
┃ ┣━ObjectCreationExpr
┃ ┣━SuperExpr
┃ ┣━ThisExpr
┃ ┣━TypeExpr
┃ ┣━UnaryExpr
┃ ┣━VariableDeclarationExpr
┃ ┣━AnnotationExpr
┃ ┃ ┣━MarkerAnnotationExpr
┃ ┃ ┣━NormalAnnotationExpr
┃ ┃ ┗━SingleMemberAnnotationExpr
┃ ┗━LiteralExpr
┃   ┣━BooleanLiteralExpr
┃   ┣━NullLiteralExpr
┃   ┗━LiteralStringValueExpr
┃     ┣━CharLiteralExpr
┃     ┣━DoubleLiteralExpr
┃     ┣━IntegerLiteralExpr
┃     ┣━LongLiteralExpr
┃     ┗━StringLiteralExpr
┃ 
┣━ModuleStmt
┃ ┣━ModuleExportsStmt
┃ ┣━ModuleOpensStmt
┃ ┣━ModuleProvidesStmt
┃ ┣━ModuleRequiresStmt
┃ ┗━ModuleUsesStmt
┃ 
┣━Statement
┃ ┣━AssertStmt
┃ ┣━BlockStmt
┃ ┣━BreakStmt
┃ ┣━ContinueStmt
┃ ┣━DoStmt
┃ ┣━EmptyStmt
┃ ┣━ExplicitConstructorInvocationStmt
┃ ┣━ExpressionStmt
┃ ┣━ForeachStmt
┃ ┣━ForStmt
┃ ┣━IfStmt
┃ ┣━LabeledStmt
┃ ┣━LocalClassDeclarationStmt
┃ ┣━ReturnStmt
┃ ┣━SwitchEntryStmt
┃ ┣━SwitchStmt
┃ ┣━SynchronizedStmt
┃ ┣━ThrowStmt
┃ ┣━TryStmt
┃ ┣━UnparsableStmt
┃ ┗━WhileStmt
┃ 
┗━Type
 ┣━IntersectionType
 ┣━PrimitiveType
 ┣━UnionType
 ┣━UnknownType
 ┣━VoidType
 ┣━WildcardType
 ┗━ReferenceType
   ┣━ArrayType
   ┣━ClassOrInterfaceType
   ┗━TypeParameter

Das Argument der Methode "visit ()" kann die letzte Klasse von diesen empfangen (es gibt keine Methode, die eine Klasse in der Mitte der Hierarchie empfängt, wie z. B. "Type" oder "ReferenceType").

Sie können sich vorstellen, welchem Element des Codes der Klassenname entspricht, aber es gibt einige Dinge, die Sie sich nicht vorstellen können. Nehmen Sie also nur diesen Teil und überprüfen Sie die Operation.

ArrayCreationLevel

MemberValuePair

AnnotationMemberDeclaration

@interface MyAnnotation {
    String value() default "text"; //Mit hier
    int number();                  //Ungefähr hier
}

ConditionalExpr

EnclosedExpr

ExplicitConstructorInvocationStmt --this () undsuper (), die im Konstruktor explizit aufgerufen werden

UnionType

UnknownType --Null Objekt, das einen Parameter darstellt, dessen Typdeklaration im Argument des Lambda-Ausdrucks weggelassen wird --Typ von line von .forEach (line-> ...)

MarkerAnnotationExpr, NormalAnnotationExpr, SingleMemberAnnotationExpr

Diejenigen, die aufschauten, aber nicht verstanden

Erhalten Sie Kommentare

Zeilenkommentare und Blockkommentare werden anders behandelt als andere normale Java-Syntax.

ParseCommentSample.java


package sample.javaparser;

// a comment

// b comment
public class ParseCommentSample {
    
    // c comment
    
    private String name; // d comment
}

Die zu analysierende Klasse. Versuchen Sie, diese Klasse zu analysieren, um Kommentare zu erhalten.

Main.java


package sample.javaparser;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.comments.LineComment;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) {
        Path source = Paths.get("src/main/java/sample/javaparser/ParseCommentSample.java");
        
        try {
            CompilationUnit unit = JavaParser.parse(source);
            
            unit.accept(new VoidVisitorAdapter<Void>() {
                @Override
                public void visit(LineComment n, Void arg) {
                    System.out.println(n);
                    super.visit(n, arg);
                }
            }, null);
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}

** Ausführungsergebnis **

// d comment

// b comment

// ein Kommentar und // c Kommentar wurden ignoriert.

An den Knoten angehängte Kommentare und isolierte Kommentare

Kommentare werden in eine der folgenden Kategorien eingeteilt:

Implementieren Sie VoidVisitor wie folgt und überprüfen Sie den Betrieb.

Main.java


package sample.javaparser;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) {
        Path source = Paths.get("src/main/java/sample/javaparser/ParseCommentSample.java");
        
        try {
            CompilationUnit unit = JavaParser.parse(source);

            System.out.println("unit orphan comment > " + unit.getOrphanComments());

            unit.accept(new VoidVisitorAdapter<Void>() {
                @Override
                public void visit(ClassOrInterfaceDeclaration n, Void arg) {
                    System.out.println("<<ClassOrInterfaceDeclaration>>");
                    System.out.println("comment > " + n.getComment());
                    System.out.println("orphan comment > " + n.getOrphanComments());
                    super.visit(n, arg);
                }

                @Override
                public void visit(FieldDeclaration n, Void arg) {
                    System.out.println("<<FieldDeclaration>>");
                    System.out.println("comment > " + n.getComment());
                    super.visit(n, arg);
                }
            }, null);
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}

** Ausführungsergebnis **

unit orphan comment > [// a comment
]

<<ClassOrInterfaceDeclaration>>
comment > Optional[// b comment
]
orphan comment > [// c comment
]

<<FieldDeclaration>>
comment > Optional[// d comment
]

--Node hatgetComment ()und getOrphanComment (), Methoden zum Abrufen des dem Knoten zugeordneten Kommentars. --Wenn ein Kommentar an einen Knoten angrenzt, wird der Kommentar als an diesen Knoten angehängt behandelt.

Übrigens, da einem Knoten nur ein Kommentar zugeordnet ist (getComment () gibt nur einen einzigen Kommentar zurück),

// a comment
String s = "xxx"; // b comment

Wenn es so aussieht, wird // b Kommentar als Kommentar behandelt, der der Variablendeklaration zugeordnet ist, und // ein Kommentar wird zu einem isolierten Kommentar (eine solche Regel).

Ausgabe als Zeichenkette

ToStringSample.java


package sample.javaparser;

/**
 * Javadoc
 */
public class ToStringSample {
    // line comment

    /**
     * Javadoc
     * @param age age
     * @param name name
     */
    public void method(
       int age,
       String name
    ) {
        /* block comment */
        System.out.println(
            "age=" + age +
            "name=" + name
        );
    }
}

Das Format zeichnet sich durch das absichtliche Einfügen von Zeilenumbrüchen aus.

Main.java


package sample.javaparser;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) {
        Path source = Paths.get("src/main/java/sample/javaparser/ToStringSample.java");
        
        try {
            CompilationUnit unit = JavaParser.parse(source);
            System.out.println(unit);
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}

** Ausführungsergebnis **

package sample.javaparser;

/**
 * Javadoc
 */
public class ToStringSample {

    // line comment
    /**
     * Javadoc
     * @param age age
     * @param name name
     */
    public void method(int age, String name) {
        /* block comment */
        System.out.println("age=" + age + "name=" + name);
    }
}

Erläuterung

Passen Sie die Formmethode an

Main.java


package sample.javaparser;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.printer.PrettyPrinterConfiguration;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) {
        Path source = Paths.get("src/main/java/sample/javaparser/ToStringSample.java");
        
        try {
            CompilationUnit unit = JavaParser.parse(source);
            PrettyPrinterConfiguration conf = new PrettyPrinterConfiguration();
            conf.setIndent("  ");
            conf.setPrintComments(false);
            conf.setPrintJavaDoc(false);
            conf.setEndOfLineCharacter("<Neue Zeile>\n");
            
            System.out.println(unit.toString(conf));
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}

** Ausführungsergebnis **

package sample.javaparser;<Neue Zeile>
<Neue Zeile>
public class ToStringSample {<Neue Zeile>
<Neue Zeile>
  public void method(int age, String name) {<Neue Zeile>
    System.out.println("age=" + age + "name=" + name);<Neue Zeile>
  }<Neue Zeile>
}<Neue Zeile>

Erläuterung

Methode Erläuterung Standard
setIndent(String) Geben Sie die Zeichenfolge an, die für einen Einzug verwendet werden soll (4 Felder)
setPrintComments(boolean) Geben Sie an, ob Kommentare angezeigt werden sollen true
setPrintJavaDoc(boolean) Geben Sie an, ob Javadoc angezeigt werden soll true
setEndOfLineCharacter(String) Geben Sie die Zeichenfolge an, die für Zeilenumbrüche verwendet werden soll System.getProperty("line.separator")

Schreiben Sie den Syntaxbaum neu

Main.java


package sample.javaparser;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.stmt.BlockStmt;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) {
        Path source = Paths.get("src/main/java/sample/javaparser/Main.java");
        
        try {
            CompilationUnit unit = JavaParser.parse(source);

            unit.getClassByName("Main").ifPresent(mainClass -> {
                // private final String textValue;Feld hinzufügen
                mainClass.addField(String.class, "textValue", Modifier.PRIVATE, Modifier.FINAL);
                
                //Konstruktor zum Initialisieren von textValue hinzugefügt
                ConstructorDeclaration constructor = mainClass.addConstructor(Modifier.PUBLIC);
                constructor.addParameter(String.class, "textValue"); //Konstruktorargument hinzufügen
                BlockStmt body = constructor.createBody(); //Konstruktorkörper hinzugefügt
                body.addStatement("this.textValue = textValue;");
            });

            System.out.println(unit);
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}

** Ausführungsergebnis **

package sample.javaparser;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.stmt.BlockStmt;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {

    public static void main(String[] args) {
        Path source = Paths.get("src/main/java/sample/javaparser/Main.java");
        try {
            CompilationUnit unit = JavaParser.parse(source);
            unit.getClassByName("Main").ifPresent(mainClass -> {
                // private final String textValue;Feld hinzufügen
                mainClass.addField(String.class, "textValue", Modifier.PRIVATE, Modifier.FINAL);
                //Konstruktor zum Initialisieren von textValue hinzugefügt
                ConstructorDeclaration constructor = mainClass.addConstructor(Modifier.PUBLIC);
                //Konstruktorargument hinzufügen
                constructor.addParameter(String.class, "textValue");
                //Konstruktorkörper hinzugefügt
                BlockStmt body = constructor.createBody();
                body.addStatement("this.textValue = textValue;");
            });
            System.out.println(unit);
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }

    private final String textValue;

    public Main(String textValue) {
        this.textValue = textValue;
    }
}

--Node bietet eine Methode zum Umschreiben des Syntaxbaums in eine beliebige Form.

Referenz

[^ 1]: JDT Java-Quellcode-Analyse - Qiita

Recommended Posts

Verwendungshinweise zu JavaParser
Hinweise zur Verwendung von WatchService
PlantUML-Nutzungsnotiz
Verwendungshinweise zu JUnit5
Hinweise zur Verwendung von Spring Shell
Spring Security-Nutzungsnotiz CSRF
Spring Security-Nutzungsnotiz Run-As
Sicherheit der Verwendungsnotizmethode für Spring Security
Spring Security-Nutzungsnotiz Remember-Me
Hinweise zur Verwendung des Abhängigkeitsmanagement-Plugins
Spring Security-Nutzungsnotiz CORS
Spring Security-Verwendungsnotiztest
Spring Security-Nutzungsnotiz Authentifizierung / Autorisierung
JCA-Verwendungsprotokoll (Java Encryption Architecture)
Antwortheader für die Verwendung von Spring Security
Sitzungsverwaltung für Spring Security-Nutzungsnotizen
Spring Security-Nutzungsnotiz Basic / Mechanismus
Ganzzahliges Memo
Docker-Memo
Spring Security Usage Memo Domänenobjektsicherheit (ACL)
Lombok Memo
Dockerfile-Memo
Iterator Memo
Corretto Memo
Java-Memo
AWS-Memo
Dcokerfile Memo
irb Verwendung
Memo Stream