@@ -465,80 +465,72 @@ With all of that done, the complete `SayHelloRecipe` looks like this:
465465``` java
466466package com.yourorg ;
467467
468- import com.fasterxml.jackson.annotation.JsonCreator ;
469- import com.fasterxml.jackson.annotation.JsonProperty ;
470468import lombok.EqualsAndHashCode ;
471469import lombok.Value ;
472- import org.jspecify.annotations.NonNull ;
473- import org.openrewrite.* ;
470+ import org.openrewrite.ExecutionContext ;
471+ import org.openrewrite.Option ;
472+ import org.openrewrite.Recipe ;
473+ import org.openrewrite.TreeVisitor ;
474474import org.openrewrite.java.JavaIsoVisitor ;
475475import org.openrewrite.java.JavaTemplate ;
476476import org.openrewrite.java.tree.J ;
477+ import org.openrewrite.java.tree.TypeUtils ;
478+
479+ import java.util.Comparator ;
477480
478481// Making your recipe immutable helps make them idempotent and eliminates categories of possible bugs.
479482// Configuring your recipe in this way also guarantees that basic validation of parameters will be done for you by rewrite.
480483// Also note: All recipes must be serializable. This is verified by RewriteTest.rewriteRun() in your tests.
481484@Value
482485@EqualsAndHashCode (callSuper = false )
483486public class SayHelloRecipe extends Recipe {
484- @Option (displayName = " Fully Qualified Class Name" ,
485- description = " A fully qualified class name indicating which class to add a hello() method to." ,
486- example = " com.yourorg.FooBar" )
487- @NonNull
487+ @Option (displayName = " Fully qualified class name" ,
488+ description = " A fully qualified class name indicating which class to add a `hello()` method to." ,
489+ example = " `com.yourorg.FooBar`" )
488490 String fullyQualifiedClassName;
489491
490- // All recipes must be serializable. This is verified by RewriteTest.rewriteRun() in your tests.
491- @JsonCreator
492- public SayHelloRecipe (@NonNull @JsonProperty (" fullyQualifiedClassName" ) String fullyQualifiedClassName ) {
493- this . fullyQualifiedClassName = fullyQualifiedClassName;
494- }
495-
496492 @Override
497493 public String getDisplayName () {
498494 return " Say Hello" ;
499495 }
500496
501497 @Override
502498 public String getDescription () {
503- return " Adds a \" hello\" method to the specified class." ;
499+ return " Adds a ` hello` method to the specified class." ;
504500 }
505501
506502 @Override
507503 public TreeVisitor<?, ExecutionContext > getVisitor () {
508504 // getVisitor() should always return a new instance of the visitor to avoid any state leaking between cycles
509- return new SayHelloVisitor ();
510- }
511-
512- public class SayHelloVisitor extends JavaIsoVisitor<ExecutionContext > {
513- private final JavaTemplate helloTemplate =
514- JavaTemplate . builder( " public String hello() { return \" Hello from #{}!\" ; }" )
515- .build();
516-
517- @Override
518- public J .ClassDeclaration visitClassDeclaration (J .ClassDeclaration classDecl , ExecutionContext executionContext ) {
519- // Don't make changes to classes that don't match the fully qualified name
520- if (classDecl. getType() == null || ! classDecl. getType(). getFullyQualifiedName(). equals(fullyQualifiedClassName)) {
521- return classDecl;
522- }
523-
524- // Check if the class already has a method named "hello".
525- boolean helloMethodExists = classDecl. getBody(). getStatements(). stream()
526- .filter(statement - > statement instanceof J . MethodDeclaration )
527- .map(J . MethodDeclaration . class:: cast)
528- .anyMatch(methodDeclaration - > methodDeclaration. getName(). getSimpleName(). equals(" hello" ));
529-
530- // If the class already has a `hello()` method, don't make any changes to it.
531- if (helloMethodExists) {
532- return classDecl;
505+ return new JavaIsoVisitor<ExecutionContext > () {
506+
507+ @Override
508+ public J .ClassDeclaration visitClassDeclaration (J .ClassDeclaration classDecl , ExecutionContext ctx ) {
509+ // Don't make changes to classes that don't match the fully qualified name
510+ if (! TypeUtils . isOfClassType(classDecl. getType(), fullyQualifiedClassName)) {
511+ return classDecl;
512+ }
513+
514+ // Check if the class already has a method named "hello".
515+ boolean helloMethodExists = classDecl. getBody(). getStatements(). stream()
516+ .filter(J . MethodDeclaration . class:: isInstance)
517+ .map(J . MethodDeclaration . class:: cast)
518+ .map(J . MethodDeclaration :: getSimpleName)
519+ .anyMatch(" hello" :: equals);
520+
521+ // If the class already has a `hello()` method, don't make any changes to it.
522+ if (helloMethodExists) {
523+ return classDecl;
524+ }
525+
526+ // insert the defined method into the existing class declaration
527+ return JavaTemplate . apply(
528+ " public String hello() { return \" Hello from #{}!\" ; }" ,
529+ updateCursor(classDecl),
530+ classDecl. getBody(). getCoordinates(). addMethodDeclaration(Comparator . comparing(J . MethodDeclaration :: getSimpleName)),
531+ fullyQualifiedClassName);
533532 }
534-
535- // Interpolate the fullyQualifiedClassName into the template and use the resulting LST to update the class body
536- classDecl = classDecl. withBody( helloTemplate. apply(new Cursor (getCursor(), classDecl. getBody()),
537- classDecl. getBody(). getCoordinates(). lastStatement(),
538- fullyQualifiedClassName ));
539-
540- return classDecl;
541- }
533+ };
542534 }
543535}
544536```
@@ -549,31 +541,30 @@ public class SayHelloRecipe extends Recipe {
549541``` java
550542package com.yourorg ;
551543
552- import com.fasterxml.jackson.annotation.JsonCreator ;
553- import com.fasterxml.jackson.annotation.JsonProperty ;
554- import lombok.Value ;
555544import org.jspecify.annotations.NonNull ;
556- import org.openrewrite.* ;
545+ import org.openrewrite.ExecutionContext ;
546+ import org.openrewrite.Option ;
547+ import org.openrewrite.Recipe ;
548+ import org.openrewrite.TreeVisitor ;
557549import org.openrewrite.java.JavaIsoVisitor ;
558550import org.openrewrite.java.JavaTemplate ;
559551import org.openrewrite.java.tree.J ;
552+ import org.openrewrite.java.tree.TypeUtils ;
560553
554+ import java.util.Comparator ;
561555import java.util.Objects ;
562556
563557// Making your recipe immutable helps make them idempotent and eliminates categories of possible bugs.
564558// Configuring your recipe in this way also guarantees that basic validation of parameters will be done for you by rewrite.
565559// Also note: All recipes must be serializable. This is verified by RewriteTest.rewriteRun() in your tests.
566- @Value
567- public class SayHelloRecipe extends Recipe {
568- @Option (displayName = " Fully Qualified Class Name" ,
569- description = " A fully qualified class name indicating which class to add a hello() method to." ,
570- example = " com.yourorg.FooBar" )
560+ public final class SayHelloRecipe extends Recipe {
561+ @Option (displayName = " Fully qualified class name" ,
562+ description = " A fully qualified class name indicating which class to add a `hello()` method to." ,
563+ example = " `com.yourorg.FooBar`" )
571564 @NonNull
572- String fullyQualifiedClassName;
565+ private final String fullyQualifiedClassName;
573566
574- // All recipes must be serializable. This is verified by RewriteTest.rewriteRun() in your tests.
575- @JsonCreator
576- public SayHelloRecipe (@NonNull @JsonProperty (" fullyQualifiedClassName" ) String fullyQualifiedClassName ) {
567+ public SayHelloRecipe (@NonNull String fullyQualifiedClassName ) {
577568 this . fullyQualifiedClassName = fullyQualifiedClassName;
578569 }
579570
@@ -584,13 +575,41 @@ public class SayHelloRecipe extends Recipe {
584575
585576 @Override
586577 public String getDescription () {
587- return " Adds a \" hello\" method to the specified class." ;
578+ return " Adds a ` hello` method to the specified class." ;
588579 }
589580
590581 @Override
591582 public TreeVisitor<?, ExecutionContext > getVisitor () {
592583 // getVisitor() should always return a new instance of the visitor to avoid any state leaking between cycles
593- return new SayHelloVisitor ();
584+ return new JavaIsoVisitor<ExecutionContext > () {
585+
586+ @Override
587+ public J .ClassDeclaration visitClassDeclaration (J .ClassDeclaration classDecl , ExecutionContext ctx ) {
588+ // Don't make changes to classes that don't match the fully qualified name
589+ if (! TypeUtils . isOfClassType(classDecl. getType(), fullyQualifiedClassName)) {
590+ return classDecl;
591+ }
592+
593+ // Check if the class already has a method named "hello".
594+ boolean helloMethodExists = classDecl. getBody(). getStatements(). stream()
595+ .filter(J . MethodDeclaration . class:: isInstance)
596+ .map(J . MethodDeclaration . class:: cast)
597+ .map(J . MethodDeclaration :: getSimpleName)
598+ .anyMatch(" hello" :: equals);
599+
600+ // If the class already has a `hello()` method, don't make any changes to it.
601+ if (helloMethodExists) {
602+ return classDecl;
603+ }
604+
605+ // insert the defined method into the existing class declaration
606+ return JavaTemplate . apply(
607+ " public String hello() { return \" Hello from #{}!\" ; }" ,
608+ updateCursor(classDecl),
609+ classDecl. getBody(). getCoordinates(). addMethodDeclaration(Comparator . comparing(J . MethodDeclaration :: getSimpleName)),
610+ fullyQualifiedClassName);
611+ }
612+ };
594613 }
595614
596615 @Override
@@ -613,46 +632,6 @@ public class SayHelloRecipe extends Recipe {
613632 public int hashCode () {
614633 return Objects . hash(super . hashCode(), fullyQualifiedClassName);
615634 }
616-
617- public String getFullyQualifiedClassName () {
618- return fullyQualifiedClassName;
619- }
620-
621- public void setFullyQualifiedClassName (String fullyQualifiedClassName ) {
622- this . fullyQualifiedClassName = fullyQualifiedClassName;
623- }
624-
625- public class SayHelloVisitor extends JavaIsoVisitor<ExecutionContext > {
626- private final JavaTemplate helloTemplate =
627- JavaTemplate . builder( " public String hello() { return \" Hello from #{}!\" ; }" )
628- .build();
629-
630- @Override
631- public J .ClassDeclaration visitClassDeclaration (J .ClassDeclaration classDecl , ExecutionContext executionContext ) {
632- // Don't make changes to classes that don't match the fully qualified name
633- if (classDecl. getType() == null || ! classDecl. getType(). getFullyQualifiedName(). equals(fullyQualifiedClassName)) {
634- return classDecl;
635- }
636-
637- // Check if the class already has a method named "hello".
638- boolean helloMethodExists = classDecl. getBody(). getStatements(). stream()
639- .filter(statement - > statement instanceof J . MethodDeclaration )
640- .map(J . MethodDeclaration . class:: cast)
641- .anyMatch(methodDeclaration - > methodDeclaration. getName(). getSimpleName(). equals(" hello" ));
642-
643- // If the class already has a `hello()` method, don't make any changes to it.
644- if (helloMethodExists) {
645- return classDecl;
646- }
647-
648- // Interpolate the fullyQualifiedClassName into the template and use the resulting LST to update the class body
649- classDecl = classDecl. withBody( helloTemplate. apply(new Cursor (getCursor(), classDecl. getBody()),
650- classDecl. getBody(). getCoordinates(). lastStatement(),
651- fullyQualifiedClassName ));
652-
653- return classDecl;
654- }
655- }
656635}
657636```
658637</TabItem >
0 commit comments