Skip to content

Commit c3b8811

Browse files
authored
Add "Semantics class shortcut" section to JavaTemplate (#399)
* Add "Semantics class shortcut" section to JavaTemplate. Also some other small improvements. * Polish * Polish * Polish * Polish
1 parent ae9cd9a commit c3b8811

File tree

1 file changed

+42
-5
lines changed

1 file changed

+42
-5
lines changed

docs/concepts-and-explanations/javatemplate.md

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ More advanced refactoring recipes often require the construction of complex [Los
1717
```java
1818
public class ChangeMethodInvocation extends JavaIsoVisitor<ExecutionContext> {
1919
private final JavaTemplate template =
20-
JavaTemplate.builder("withString(#{any(java.lang.String)}).length()") // Code Snippet
20+
JavaTemplate.builder("withString(#{any(java.lang.String)}).length()") // Code Snippet
2121
.javaParser(
22-
JavaParser.fromJavaVersion() // Parser
23-
.classpath("example-utils")) // Classpath lookup
24-
.staticImports("org.example.StringUtils.withString") // Additional import
22+
JavaParser.fromJavaVersion() // Parser
23+
.classpath("example-utils")) // Classpath lookup
24+
.staticImports("org.example.StringUtils.withString") // Additional import
25+
.doAfterVariableSubstitution(System.out::println) // Optional side-effect
26+
.doBeforeParseTemplate(System.out::println) // Optional side-effect
2527
.build();
2628
}
2729
```
@@ -274,4 +276,39 @@ When a JavaTemplate is used for matching, then the `Matcher` can be used to "ext
274276

275277
This can then be passed into another JavaTemplate to generate some new code (such as what was done with the `after` template above).
276278

277-
Another useful example that doesn't involve Refaster recipes is our [JavaTemplateMatchTest class](https://github.com/openrewrite/rewrite/blob/main/rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateMatchTest.java#L32). In there, you can see how we create a JavaTemplate for the use case of matching/finding code rather than replacing it.
279+
Another useful example that doesn't involve Refaster recipes is our [JavaTemplateMatchTest class](https://github.com/openrewrite/rewrite/blob/main/rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateMatchTest.java#L32). In there, you can see how we create a JavaTemplate for the use case of matching/finding code rather than replacing it.
280+
281+
## Semantics class shortcut
282+
283+
If you're looking for a more concise way to define JavaTemplates, the [Semantics class](https://github.com/openrewrite/rewrite-templating/blob/main/src/main/java/org/openrewrite/java/template/Semantics.java) offers a powerful alternative. Instead of writing the raw template string yourself, you can define the desired expression or statement directly in Java, and a annotation processor will automatically generate the corresponding template code for you.
284+
285+
This approach helps you avoid dealing with the syntax of raw templates and lets the compiler validate your logic directly.
286+
287+
For example, instead of writing:
288+
289+
```java
290+
JavaTemplate isEmptyReplacement =
291+
JavaTemplate.builder("(#{any(java.lang.String)} == null || #{any(java.lang.String)}.isEmpty())").build();
292+
```
293+
294+
You can write:
295+
296+
```java
297+
JavaTemplate isEmptyReplacement =
298+
Semantics.expression(this, "IsEmpty", (String s) -> (s == null || s.isEmpty())).build();
299+
```
300+
301+
Similarly, for statements:
302+
303+
```java
304+
JavaTemplate newInstanceTemplate =
305+
Semantics.statement(this, "Example", () -> { String example = "some statement"; }).build();
306+
```
307+
308+
Behind the scenes, the annotation processor transforms these `Semantics.expression(...)` and `Semantics.statement(...)` calls into actual JavaTemplate definitions with proper substitution indicators and imports.
309+
310+
:::info
311+
Prerequisite: To use this feature, make sure your project is set up for Refaster-style recipes with annotation processing enabled. See the [How to create a Refaster recipe](../authoring-recipes/refaster-recipes#how-to-create-a-refaster-recipe) section for more details.
312+
:::
313+
314+
Since the Semantics class is functionally equivalent to defining a JavaTemplate manually, while offering compile-time safety and slightly less boilerplate, it is well-suited for cases where your template is just beyond what Refaster can express easily. It provides a convenient middle ground between Refaster and fully custom JavaTemplate logic.

0 commit comments

Comments
 (0)