Lombok-Implementierung JSR-269

Lombok-Implementierung JSR-269

Vorwort

Einführung

Lombok ist ein praktisches Tool, genau wie Google Guava, und wird wärmstens empfohlen. Jeder Java-Entwickler sollte es verwenden. Lombok ist ein Java™-Dienstprogramm, das Entwicklern hilft, die Ausführlichkeit von Java zu beseitigen, insbesondere bei einfachen alten Java-Objekten (POJOs). Dies geschieht durch Anmerkungen. Durch die Implementierung von Lombok in ihre Entwicklungsumgebung können Entwickler viel Zeit beim Erstellen von Methoden wie hashCode() und equals() sowie beim Katalogisieren verschiedener Zugriffsmethoden und Mutatoren sparen.

Wie wird Lombok umgesetzt?
Erstellen Sie eine neue Testklasse mit den Getter- und Setter-Annotationen von Lombok und kompilieren Sie sie über IDEA

importiere lombok.Getter;
importiere lombok.Setter;

@Getter
@Setter
öffentliche Klasse UserInfo {
    private String-Benutzer-ID;

    privater String-Benutzername;
}

Öffnen Sie die nach der Kompilierung generierte Datei UserInfo.class

Es wurde festgestellt, dass Get- und Set-Methoden generiert wurden, woraus wir schließen können, dass Lombok den Code zur Kompilierzeit verbessert. Wie wird also die Verbesserung zur Kompilierzeit erreicht?

Kompilierungsphase

Der Vorschlag JSR-269 wurde in JDK6 vorgeschlagen und verabschiedet. Der Vorschlag verabschiedete eine Reihe von Standard-APIs namens „Plug-in-Annotation-Prozessoren“, die während der Kompilierung bestimmte Annotationen im Code im Voraus verarbeiten und so den Arbeitsprozess des Compilers beeinflussen können.
Bei einigen zugrunde liegenden Implementierungen wird im Allgemeinen angenommen, dass die Implementierung mit C++ wie eine virtuelle Maschine erfolgt, was für Java-Programmierer nicht besonders benutzerfreundlich ist. Der Javac-Compiler ist jedoch in Java implementiert und einfacher zu verwenden.
Der Kompilierungsprozess von Javac ist grob in mehrere Schritte unterteilt

  1. Vorbereitung: Initialisieren des Pluggable Annotation Processor
  2. Analysieren und Füllen der Symboltabelle. Lexikalische und grammatische Analyse. Erstellen eines abstrakten Syntaxbaums (AST).
  3. Annotationsverarbeitung von steckbaren Annotationsprozessoren
  4. Analyse- und Bytecode-Generierungsprozess
  5. Nach der Änderung des Syntaxbaums wird die Symboltabelle erneut analysiert und gefüllt. Wenn sich der Syntaxbaum nicht ändert, arbeitet der Compiler nicht mehr mit dem Quellcode-Zeichenstrom, sondern basiert auf dem abstrakten Syntaxbaum.

Zusammenfassend lässt sich sagen, dass Sie, wenn Sie den Effekt von Lombok erzielen möchten, nur JSR-269 einhalten und während der Kompilierung mit AST arbeiten müssen. Natürlich kann nicht nur Lombok auf diese Weise implementiert werden, beispielsweise können auch FindBug, MapStruct usw. auf diese Weise implementiert werden.

erreichen

JCTree

JCTree ist die Basisklasse von AST-Elementen. Um den Effekt zu erzielen, müssen Sie nur einen JCTree-Knoten hinzufügen.
JCTree ist eine abstrakte Klasse, die teilweise implementiert

Anhand des Klassennamens können Sie erraten, welcher Knoten verwendet wird. Hier sind einige allgemeine Erklärungen
JCStatement deklariert einen Syntaxbaumknoten
JCBlock-Syntaxblock
JCReturn: Syntaxbaumknoten der Return-Anweisung
JCClassDecl: Syntaxbaumknoten der Klassendefinition
JCVariableDecl: Syntaxbaumknoten für Feld-/Variablendefinitionen
JCMethodDecl: Knoten im Syntaxbaum der Methodendefinition
JCModifiers: Zugriff auf Flag-Syntaxstrukturknoten
JCExpression: Ausdruckssyntaxbaumknoten, gemeinsame Unterklassen sind wie folgt
JCAssign: Knoten der Syntaxstruktur der Zuweisungsanweisung
JCIdent: Bezeichnersyntaxbaumknoten wie dieser

BaumMaker

Wird hauptsächlich zum Generieren von Syntaxbaumknoten verwendet

Code

Zuerst müssen Sie die Klasse kommentieren, um den Umfang und die Dauer der Aktion anzugeben. Die beiden Klassen entsprechen jeweils Lomboks Getter und Setter.

@Target({ElementType.TYPE}) //Der Klasse hinzugefügte Annotation @Retention(RetentionPolicy.SOURCE) //Beeinflusst den Kompilierungszeitraum public @interface Getter {
}
@Target({ElementType.TYPE}) //Der Klasse hinzugefügte Annotation @Retention(RetentionPolicy.SOURCE) //Beeinflusst den Kompilierungszeitraum public @interface Setter {
}

Um einen neuen abstrakten Annotationsprozessor zu erstellen, müssen Sie AbstractProcessor erben. Hier wird der Vorlagenmethodenmodus verwendet.

öffentliche abstrakte Klasse MyAbstractProcessor erweitert AbstractProcessor {
    //Syntaxbaum geschützt JavacTrees Bäume;

    //Syntaxbaumknoten erstellen, geschützter TreeMaker treeMaker;

    //Erstellen Sie ein Objekt mit dem Bezeichner „geschützte Namen“;

    @Überschreiben
    öffentliche synchronisierte void init(Verarbeitungsumgebung processingEnv) {
        super.init(processingEnv);
        diese.trees = JavacTrees.instance(processingEnv);
        Kontext Kontext = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(Kontext);
        this.names = Names.instance(Kontext);
    }

    @Überschreiben
    öffentlicher boolescher Prozess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //Holen Sie sich die kommentierte Klasse Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(getAnnotation());
        //Syntaxbaum abrufen set.stream().map(element -> trees.getTree(element)).forEach(jcTree -> jcTree.accept(new TreeTranslator() {
            //Holen Sie sich die Klassendefinition @Override
            öffentliche Leere visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                Liste<JCTree.JCVariableDecl> jcVariableDeclList = List.nil();
                //Alle Mitgliedsvariablen für (JCTree-Baum: jcClassDecl.defs) abrufen {
                    wenn (tree.getKind().equals(Tree.Kind.VARIABLE)) {
                        JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) Baum;
                        jcVariableDeclList = jcVariableDeclList.append(jcVariableDecl);
                    }
                }

                jcVariableDeclList.fürEach(jcVariableDecl -> {
                    jcClassDecl.defs = jcClassDecl.defs.prepend(makeMethodDecl(jcVariableDecl));
                });
                super.visitClassDef(jcClassDecl);
            }
        }));
        gibt true zurück;
    }

    /**
     * Erstellungsmethode * @param jcVariableDecl
     * @zurückkehren
     */
    öffentliches abstraktes JCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl);

    /**
     * Welche Art von Annotation soll abgerufen werden? * @return
     */
    öffentliche abstrakte Klasse <? erweitert Annotation> getAnnotation();
}

Wird verwendet, um die Setter-Annotation-Vererbung MyAbstractProcessor zu verarbeiten

@SupportedAnnotationTypes("com.ingxx.processor.Setter") //Der Annotation-Prozessor wirkt auf welche Annotation. Sie können getSupportedAnnotationTypes auch neu schreiben
@SupportedSourceVersion(SourceVersion.RELEASE_8) //Kann jede Version verarbeiten und kann auch getSupportedSourceVersion überschreiben
öffentliche Klasse SetterProcessor erweitert MyAbstractProcessor {

    @Überschreiben
    öffentliche JCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
        ListBuffer<JCTree.JCStatement>-Anweisungen = neuer ListBuffer<>();
        //Funktionskörper generieren this.name = name;
        Anweisungen.Anhängen(treeMaker.Exec(treeMaker.Assign(treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.getName()),treeMaker.Ident(jcVariableDecl.getName()))));
        JCTree.JCBlock-Body = treeMaker.Block(0, Anweisungen.toList());
        //Methode generieren return treeMaker.MethodDef(
                treeMaker.Modifiers(Flags.PUBLIC), //Zugriffsflag getNewMethodName(jcVariableDecl.getName()), //Name treeMaker.TypeIdent(TypeTag.VOID), //Rückgabetyp List.nil(), //Allgemeine Parameterliste List.of(getParameters(jcVariableDecl)), //Parameterliste List.nil(), //Ausnahmeliste body, //Methodenbody null //Standardmethode (kann die Standardmethode in der Schnittstelle sein)
        );
    }

    @Überschreiben
    öffentliche Klasse<? erweitert Annotation> getAnnotation() {
        Setter.class zurückgeben;
    }

    privater Name getNewMethodName(Name name) {
        String Feldname = name.toString();
        gibt Namen zurück.fromString("set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, name.length()));
    }

    private JCTree.JCVariableDecl getParameters(JCTree.JCVariableDecl prototypeJCVariable) {
        returniere treeMaker.VarDef(
                treeMaker.Modifiers(Flags.PARAMETER), //Zugriffsflag prototypeJCVariable.name, //Name prototypeJCVariable.vartype, //Typ null //Initialisierungsanweisung);
    }
}

Wird verwendet, um von MyAbstractProcessor geerbte Getter-Annotationen zu verarbeiten.

@SupportedAnnotationTypes("com.ingxx.processor.Getter") //Der Annotation-Prozessor wirkt auf welche Annotation. Sie können getSupportedAnnotationTypes auch neu schreiben
@SupportedSourceVersion(SourceVersion.RELEASE_8) //Kann jede Version verarbeiten und kann auch getSupportedSourceVersion überschreiben
öffentliche Klasse GetterProcessor erweitert MyAbstractProcessor {

    @Überschreiben
    öffentliche JCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
        ListBuffer<JCTree.JCStatement>-Anweisungen = neuer ListBuffer<>();
        //Funktionskörper generieren return this.Feldname statements.append(treeMaker.Return(treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.getName())));
        JCTree.JCBlock-Body = treeMaker.Block(0, Anweisungen.toList());
        //Methode generieren return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC), getNewMethodName(jcVariableDecl.getName()), jcVariableDecl.vartype, List.nil(), List.nil(), List.nil(), body, null);
    }

    @Überschreiben
    öffentliche Klasse<? erweitert Annotation> getAnnotation() {
        gibt Getter.class zurück;
    }

    privater Name getNewMethodName(Name name) {
        String Feldname = name.toString();
        gibt Namen zurück.fromString("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, name.length()));
    }
}

Kompilieren einer vorhandenen Klasse

javac -cp $JAVA_HOME/lib/tools.jar *.java -d .

Erstellen Sie eine neue Testklasse. In IDEA wird ein Fehler gemeldet, da die Get-Set-Methode nicht gefunden werden kann. Sie können ihn ignorieren.

@Getter
@Setter
öffentliche Klasse UserInfo {
    private String-Benutzer-ID;

    privater String-Benutzername;

    öffentliche statische void main(String[] args) {
        Benutzerinfo Benutzerinfo = neue Benutzerinfo();
        Benutzerinfo.setUserId("001");
        userInfo.setUserName("Dewu");
        System.out.println("id = "+userInfo.getUserId()+" name = "+userInfo.getUserName());
    }
}

Dann kompilieren

//Mehrere Prozessoren werden durch Kommas getrennt javac -processor com.ingxx.processor.GetterProcessor,com.ingxx.processor.SetterProcessor UserInfo.java -d .

Überprüfen Sie die kompilierte Datei und stellen Sie fest, dass Get- und Set-Methoden generiert wurden

Oben sind die Details von Lombok bis JSR-269 aufgeführt. Weitere Informationen zum JS-Reflexionsmechanismus finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Beheben Sie das Fehlerproblem des IDEA2020.2-Plugins Lombok (getestet und effektiv).
  • Die Bibliotheksquelle stimmt nicht mit dem Bytecode-Fehlerproblem und der Lösung überein, die vom Lombok-Plugin in IDEA generiert werden (professioneller Test verfügbar)
  • Nach der Installation des Lombok-Plugins in IDEA und der Einstellung „Annotation Processing aktivieren“ meldet die Kompilierung immer noch eine Fehlerlösung
  • So installieren Sie Lombok unter IDEA und lösen das Problem, dass Get und Set nicht gefunden werden
  • Lösen Sie das Problem, dass IDEA2020.1 nicht mit Lombok kompatibel ist
  • Detaillierte Erklärung der Lösung für das Problem der fehlgeschlagenen Installation des Lombok-Plugins in Idea 2019.2

<<:  Detaillierte Analyse von Absturzfällen bei MySQL-Instanzen

>>:  So führen Sie Befehle auf einem Remote-Linux-System über SSH aus

Artikel empfehlen

So stellen Sie Rancher mit Docker bereit (keine Fallstricke)

Vor der Inbetriebnahme unbedingt lesen: Hinweis: ...

Verwenden von Textschatten- und Elementschatteneffekten in CSS

Einführung in Textschatten Verwenden Sie in CSS d...

Linux nutzt duale Netzwerkkartenbindung und Schraubendreherschnittstelle

Was ist eine Bindung? NIC-Bond ist eine Technolog...

Vue elementUI implementiert Baumstrukturtabelle und Lazy Loading

Inhaltsverzeichnis 1. Ergebnisse erzielen 2. Back...

Installation und Daemon-Konfiguration von Redis unter Windows und Linux

# Installations-Daemon-Konfiguration für Redis un...

Detaillierte Erläuterung des Zahlungsfunktionscodes des Vue-Projekts

1. Alipay-Methode: Alipay-Methode: Klicken Sie zu...

Detaillierte Erläuterung der MySQL-Transaktionsisolationsebene und des MVCC

Inhaltsverzeichnis Transaktionsisolationsebene Be...

Vollständige Analyse des MySQL INT-Typs

Vorwort: Integer ist einer der am häufigsten verw...

Verwendung von Provide und Inject in Vue3

1. Erklärung von provide und inject Mit „Bereitst...

Umgang mit Leerzeichen in CSS

1. Weltraumregeln Leerzeichen im HTML-Code werden...

Detaillierte Erklärung des MySQL-Überwachungstools mysql-monitor

1. Übersicht mysql-monitor MySQL-Überwachungstool...