Notes d'utilisation de JavaParser

Qu'est-ce que JavaParser?

Hello World ** Dépendances **

build.gradle


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

La mise en oeuvre

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);
        }
    }
}

** Résultat d'exécution **

***********************************************
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);
        }
    }
}

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

La description

VoidVisitor La mise en oeuvre

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);
        }
    }
}

** Résultat d'exécution **

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

La description

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);
    }

--L'interface VoidVisitor est fournie en tant queVisitor pour parcourir l'arborescence de la syntaxe. --Dans VoidVisitor, un peu moins de 100 méthodes sont déclarées rappelées pour chaque type de nœud.

Main.java


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

--Visitor peut être utilisé en le passant à ʻaccept () de la classe CompliationUnit`.

L'unité de complétion accepte()Implémentation de la méthode


    @Override
    public <A> void accept(VoidVisitor<A> v, A arg) {
        v.visit(this, arg); //★ Visite du visiteur vide()Est appelé tel quel
    }

--Si vous passez une valeur au second argument de la méthode ʻaccept () (et visit () `), cette valeur continuera à fonctionner ensemble tout en traversant le nœud. -Peut-être pour lier des données et traiter des objets de destination de délégation auxquels vous souhaitez vous référer en commun?

GenericVisitor La mise en oeuvre

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);
        }
    }
}

** Résultat d'exécution **

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

La description

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;
    }

Type de nœud

Les nœuds inclus dans l'arborescence de syntaxe abstraite héritent de la classe Node et ont la relation d'héritage suivante.

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

L'argument de la méthode visit () peut recevoir la dernière classe de ceux-ci (il n'y a pas de méthode qui reçoit une classe au milieu de la hiérarchie telle que Type ou ReferenceType).

Vous pouvez imaginer à quel élément du code correspond le nom de la classe, mais il y a des choses que vous ne pouvez pas imaginer, alors ne prenez que cette partie et vérifiez l'opération.

ArrayCreationLevel --Spécification de la taille initiale lors de la déclaration d'un tableau --ʻInt [] array = new int [10]; [10] part of `

MemberValuePair --La partie où l'argument de l'annotation est spécifié par son nom --@ SomeAnnotation (value = "text") `` value = "text"part of`

AnnotationMemberDeclaration

@interface MyAnnotation {
    String value() default "text"; //Avec ici
    int number();                  //À propos d'ici
}

ConditionalExpr

EnclosedExpr --Le groupe () utilisé dans l'expression

ExplicitConstructorInvocationStmt --this () etsuper ()qui sont explicitement appelés dans le constructeur

UnionType

UnknownType --Null objet représentant un paramètre dont la déclaration de type est omise dans l'argument de l'expression lambda --Type de ligne de .forEach (ligne-> ...)

MarkerAnnotationExpr, NormalAnnotationExpr, SingleMemberAnnotationExpr

Ceux qui ont levé les yeux mais n'ont pas compris

Obtenez des commentaires

Les commentaires de ligne et les commentaires de bloc sont traités différemment des autres syntaxes Java normales.

ParseCommentSample.java


package sample.javaparser;

// a comment

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

La classe à analyser. Essayez d'analyser cette classe pour obtenir des commentaires.

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);
        }
    }
}

** Résultat d'exécution **

// d comment

// b comment

«// un commentaire» et «// c comment» ont été ignorés.

Commentaires attachés au nœud et commentaires isolés

Les commentaires sont classés dans l'un des éléments suivants:

--Commentaires attachés au nœud

Implémentez VoidVisitor comme suit et vérifiez l'opération.

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);
        }
    }
}

** Résultat d'exécution **

unit orphan comment > [// a comment
]

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

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

--Node a getComment () ʻet getOrphanComment () `, qui sont des méthodes pour obtenir le commentaire associé au nœud.

Au fait, puisqu'il n'y a qu'un seul commentaire associé à un nœud (getComment () ne renvoie qu'un seul commentaire),

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

Si cela ressemble à, «// b comment» est traité comme un commentaire associé à la déclaration de variable, et «// a comment» devient un commentaire isolé (une telle règle).

Sortie sous forme de chaîne de caractères

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
        );
    }
}

Le format est caractérisé par l'insertion intentionnelle de sauts de ligne.

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);
        }
    }
}

** Résultat d'exécution **

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);
    }
}

La description

Ajuster la méthode de mise en forme

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("<nouvelle ligne>\n");
            
            System.out.println(unit.toString(conf));
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}

** Résultat d'exécution **

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

La description

Méthode La description Défaut
setIndent(String) Spécifiez la chaîne de caractères à utiliser pour un retrait (4 espaces)
setPrintComments(boolean) Spécifiez s'il faut afficher les commentaires true
setPrintJavaDoc(boolean) Spécifiez si vous souhaitez afficher Javadoc true
setEndOfLineCharacter(String) Spécifiez la chaîne de caractères à utiliser pour les sauts de ligne System.getProperty("line.separator")

Réécrire l'arbre de syntaxe

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;Ajouter le champ
                mainClass.addField(String.class, "textValue", Modifier.PRIVATE, Modifier.FINAL);
                
                //Constructeur ajouté pour initialiser textValue
                ConstructorDeclaration constructor = mainClass.addConstructor(Modifier.PUBLIC);
                constructor.addParameter(String.class, "textValue"); //Ajouter un argument de constructeur
                BlockStmt body = constructor.createBody(); //Ajout du corps du constructeur
                body.addStatement("this.textValue = textValue;");
            });

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

** Résultat d'exécution **

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;Ajouter le champ
                mainClass.addField(String.class, "textValue", Modifier.PRIVATE, Modifier.FINAL);
                //Constructeur ajouté pour initialiser textValue
                ConstructorDeclaration constructor = mainClass.addConstructor(Modifier.PUBLIC);
                //Ajouter un argument de constructeur
                constructor.addParameter(String.class, "textValue");
                //Ajout du corps du constructeur
                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 fournit une méthode pour réécrire l'arbre de syntaxe dans n'importe quelle forme.

référence

[^ 1]: Analyse du code source Java JDT --Qiita

Recommended Posts

Notes d'utilisation de JavaParser
Notes d'utilisation de WatchService
Mémo d'utilisation PlantUML
Notes d'utilisation de JUnit5
Notes d'utilisation de Spring Shell
Mémo d'utilisation de Spring Security CSRF
Mémo d'utilisation de Spring Security Run-As
Spring Security Usage Memo Method Security
Mémo d'utilisation de Spring Security Remember-Me
Notes sur l'utilisation du plug-in de gestion des dépendances
Mémo d'utilisation de Spring Security CORS
Test de mémo d'utilisation de Spring Security
Authentification / autorisation de mémo d'utilisation de Spring Security
Mémo d'utilisation de JCA (Java Encryption Architecture)
En-tête de réponse de mémo d'utilisation de Spring Security
Gestion des sessions de mémo d'utilisation de Spring Security
Mémo d'utilisation de Spring Security Basic / mécanisme
Mémo entier
mémo docker
Spring Security Usage Memo Domain Object Security (ACL)
Mémo de Lombok
Mémo Dockerfile
Mémo Itérateur
mémo corretto
Mémo Java
Mémo AWS
Mémo Dcokerfile
utilisation d'irb
Memo Stream