Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
902b7a7
Added implementation for classpathFromResource
JohannisK May 2, 2025
bf447cf
Join `jarNames` without `Stream.map(..)`
timtebeek May 4, 2025
fc56e32
Update expectations
timtebeek Aug 14, 2025
b44be87
Do not use `classpathFromResources` for TemplateProcessor just yet
timtebeek Aug 14, 2025
026d86d
Merge branch 'main' into 1136-use-classpathfromresources-instead-of-r…
timtebeek Aug 15, 2025
979e22c
Update expectations for NoGuavaRefasterRecipes.java
timtebeek Aug 15, 2025
06e4ab1
Add an option to generate classpathFromResources
timtebeek Aug 15, 2025
9d7ca4d
Adapt Semantics, PatternBuilder and TemplateProcessor
timtebeek Aug 15, 2025
013c36d
Apply formatter
timtebeek Aug 15, 2025
979aedc
Determine classpathFromResources from first argument
timtebeek Aug 15, 2025
ff581ba
Correctly concatenate more than one jar name
timtebeek Aug 15, 2025
77f2aa6
Add transitive jars to classpathFromResources too
timtebeek Aug 15, 2025
867a659
Run CI for pull request targeted at any branch
timtebeek Aug 15, 2025
436f996
Merge branch 'main' into transitive-jarnames
timtebeek Aug 15, 2025
f561654
Update ci.yml
timtebeek Aug 15, 2025
73e8f11
Merge branch 'main' into transitive-jarnames
timtebeek Aug 15, 2025
cbc503f
Expand to detect more types
timtebeek Aug 15, 2025
854d798
Annotated types come with a classpath dependency
timtebeek Aug 16, 2025
c2526b4
Annotated types come with a classpath dependency
timtebeek Aug 16, 2025
8d76c92
Merge branch 'main' into transitive-jarnames
timtebeek Aug 16, 2025
f4b16f6
Add ClasspathJarNameDetectorTest
timtebeek Aug 16, 2025
93d8d9a
Reuse `ImportDetector.imports`
timtebeek Aug 16, 2025
053233f
Organize imports
timtebeek Aug 16, 2025
ee55b6b
Improve formatting in ClasspathJarNameDetectorTest
timtebeek Aug 16, 2025
8c30c79
Accept suggestions to make the tests pass
timtebeek Aug 16, 2025
e508f29
Prune dead code branch according to test coverage
timtebeek Aug 16, 2025
694c92d
Make better use of visitor instead of instanceof checks in scan
timtebeek Aug 16, 2025
d32e934
Remove unnecessary method and nullability warnings
timtebeek Aug 16, 2025
fdc494e
Minimize what we actually need for current tests
timtebeek Aug 16, 2025
b28c470
Trim empty lines
timtebeek Aug 16, 2025
c19f3f4
Avoid nullability issue in `detectJUnitAndOpenTest4JFromStatement`
timtebeek Aug 16, 2025
17850a4
Swap test order
timtebeek Aug 16, 2025
ad52cd1
Merge branch 'main' into transitive-jarnames
timtebeek Aug 16, 2025
d328715
Merge branch 'main' into transitive-jarnames
timtebeek Aug 16, 2025
eff6676
Merge branch 'main' into transitive-jarnames
timtebeek Aug 16, 2025
f49b773
Adopt text blocks for ClasspathJarNameDetectorTest
timtebeek Aug 16, 2025
304d80a
Apply suggestions from code review
timtebeek Aug 16, 2025
b784da7
Add exports for ClasspathJarNameDetectorTest compilation
timtebeek Aug 17, 2025
1acb5c4
Slight polish
timtebeek Aug 17, 2025
fc7b9ba
Add a test showing we need transitive dependencies too
timtebeek Aug 17, 2025
a241c1b
Also look at super class and interfaces
timtebeek Aug 17, 2025
d938e9d
Fix execution in IntelliJ
timtebeek Aug 17, 2025
693fb9c
Add another test for extraction based on first statement
timtebeek Aug 17, 2025
e013a4a
Show extraction works even without imports
timtebeek Aug 17, 2025
b5c2e7c
Start anew
timtebeek Aug 17, 2025
bc02ba4
Apply formatter
timtebeek Aug 17, 2025
3da3a53
Use a private static class to minimize nullable warnings
timtebeek Aug 17, 2025
84fe2ec
Move where ImportsDetector is invoked
timtebeek Aug 17, 2025
e5ce73a
Remove the need for ImportDetector in ClasspathJarNameDetector
timtebeek Aug 17, 2025
e702d41
Organize imports
timtebeek Aug 17, 2025
50dd501
Collapse loops and visit in logical order
timtebeek Aug 17, 2025
a5c394b
Have ClasspathJarNameDetector directly extend TreeScanner
timtebeek Aug 17, 2025
3071974
Inline the static `jarNameFor`
timtebeek Aug 18, 2025
34b646f
Add major version to classpath entries to avoid conflicts
timtebeek Aug 18, 2025
6bfcdb8
Also suffix JSpecify versions
timtebeek Aug 18, 2025
d670df4
Use `replaceFirst` as suggested
timtebeek Aug 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions src/main/java/org/openrewrite/java/template/Semantics.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.openrewrite.java.template;

import org.openrewrite.ExecutionContext;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.template.function.*;
Expand Down Expand Up @@ -112,4 +113,94 @@ public static JavaTemplate.Builder statement(JavaVisitor<?> owner, String name,
public static JavaTemplate.Builder statement(JavaVisitor<?> owner, String name, Stat10<?, ?, ?, ?, ?, ?, ?, ?, ?, ?> p) {
return new PatternBuilder(name).build(owner);
}

// Again, but with a first ExecutionContext argument for JavaParser classpathFromResources

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr0<?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr1<?, ?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr2<?, ?, ?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr3<?, ?, ?, ?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr4<?, ?, ?, ?, ?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr5<?, ?, ?, ?, ?, ?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr6<?, ?, ?, ?, ?, ?, ?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr7<?, ?, ?, ?, ?, ?, ?, ?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr8<?, ?, ?, ?, ?, ?, ?, ?, ?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr9<?, ?, ?, ?, ?, ?, ?, ?, ?, ?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder expression(ExecutionContext ctx, JavaVisitor<?> owner, String name, Expr10<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> f) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat0 p) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat1<?> p) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat2<?, ?> p) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat3<?, ?, ?> p) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat4<?, ?, ?, ?> p) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat5<?, ?, ?, ?, ?> p) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat6<?, ?, ?, ?, ?, ?> p) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat7<?, ?, ?, ?, ?, ?, ?> p) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat8<?, ?, ?, ?, ?, ?, ?, ?> p) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat9<?, ?, ?, ?, ?, ?, ?, ?, ?> p) {
return new PatternBuilder(name).build(ctx, owner);
}

public static JavaTemplate.Builder statement(ExecutionContext ctx, JavaVisitor<?> owner, String name, Stat10<?, ?, ?, ?, ?, ?, ?, ?, ?, ?> p) {
return new PatternBuilder(name).build(ctx, owner);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
package org.openrewrite.java.template.internal;

import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.TreeScanner;
import org.jspecify.annotations.Nullable;

import javax.tools.JavaFileObject;
import java.util.LinkedHashSet;
Expand All @@ -38,7 +40,7 @@ public class ClasspathJarNameDetector {
public static Set<String> classpathFor(JCTree input, List<Symbol> imports) {
Set<String> jarNames = new LinkedHashSet<String>() {
@Override
public boolean add(String s) {
public boolean add(@Nullable String s) {
return s != null && super.add(s);
}
};
Expand All @@ -47,15 +49,24 @@ public boolean add(String s) {
jarNames.add(jarNameFor(anImport));
}

// Detect fully qualified classes
new TreeScanner() {
@Override
public void scan(JCTree tree) {
// Detect fully qualified classes
if (tree instanceof JCFieldAccess &&
((JCFieldAccess) tree).sym instanceof Symbol.ClassSymbol &&
Character.isUpperCase(((JCFieldAccess) tree).getIdentifier().toString().charAt(0))) {
((JCFieldAccess) tree).sym instanceof Symbol.ClassSymbol &&
Character.isUpperCase(((JCFieldAccess) tree).getIdentifier().toString().charAt(0))) {
jarNames.add(jarNameFor(((JCFieldAccess) tree).sym));
}
// Detect method invocations that throw exceptions
if (tree instanceof JCTree.JCMethodInvocation) {
for (Type thrownType : ((JCTree.JCMethodInvocation) tree).meth.type.getThrownTypes()) {
if (thrownType.tsym instanceof Symbol.ClassSymbol) {
jarNames.add(jarNameFor(thrownType.tsym));
}
}
}

super.scan(tree);
}
}.scan(input);
Expand All @@ -64,7 +75,7 @@ public void scan(JCTree tree) {
}


private static String jarNameFor(Symbol anImport) {
private static @Nullable String jarNameFor(Symbol anImport) {
Symbol.ClassSymbol enclClass = anImport instanceof Symbol.ClassSymbol ? (Symbol.ClassSymbol) anImport : anImport.enclClass();
while (enclClass.enclClass() != null && enclClass.enclClass() != enclClass) {
enclClass = enclClass.enclClass();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.openrewrite.java.template.internal;

import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;

Expand All @@ -38,4 +39,16 @@ public JavaTemplate.Builder build(JavaVisitor<?> owner) {
throw new RuntimeException(e);
}
}

public JavaTemplate.Builder build(ExecutionContext ctx, JavaVisitor<?> owner) {
try {
Class<?> templateClass = Class.forName(owner.getClass().getName() + "_" + name, true,
owner.getClass().getClassLoader());
Method getTemplate = templateClass.getDeclaredMethod("getTemplate", ExecutionContext.class);
return (JavaTemplate.Builder) getTemplate.invoke(null, ctx);
} catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,15 @@

public class TemplateCode {

public static <T extends JCTree> String process(T tree, @Nullable Type returnType, List<JCTree.JCVariableDecl> parameters, List<JCTree.JCTypeParameter> typeParameters, int pos, boolean asStatement, boolean fullyQualified) {
public static <T extends JCTree> String process(
T tree,
@Nullable Type returnType,
List<JCTree.JCVariableDecl> parameters,
List<JCTree.JCTypeParameter> typeParameters,
int pos,
boolean asStatement,
boolean fullyQualified,
boolean classpathFromResources) {
StringWriter writer = new StringWriter();
TemplateCodePrinter printer = new TemplateCodePrinter(writer, parameters, pos, fullyQualified);
try {
Expand All @@ -62,18 +70,18 @@ public static <T extends JCTree> String process(T tree, @Nullable Type returnTyp
if (!printer.staticImports.isEmpty()) {
builder.append("\n .staticImports(").append(printer.staticImports.stream().map(i -> '"' + i + '"').collect(joining(", "))).append(")");
}
List<Symbol> imports = ImportDetector.imports(tree);
Set<String> jarNames = ClasspathJarNameDetector.classpathFor(tree, imports);
Set<String> jarNames = ClasspathJarNameDetector.classpathFor(tree, ImportDetector.imports(tree));
for (JCTree.JCVariableDecl parameter : parameters) {
jarNames.addAll(ClasspathJarNameDetector.classpathFor(parameter, ImportDetector.imports(parameter)));
}
if (!jarNames.isEmpty()) {
// It might be preferable to enumerate exactly the needed dependencies rather than the full classpath
// But this is expedient
// See https://github.com/openrewrite/rewrite-templating/issues/86
// String classpath = jarNames.stream().map(jarName -> '"' + jarName + '"').sorted().collect(joining(", "));
// builder.append("\n .javaParser(JavaParser.fromJavaVersion().classpath(").append(classpath).append("))");
builder.append("\n .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()))");
builder.append("\n .javaParser(JavaParser.fromJavaVersion()");
if (classpathFromResources) {
String joinedJarNames = jarNames.stream().collect(joining("\", \"", "\"", "\""));
builder.append(".classpathFromResources(ctx, ").append(joinedJarNames).append("))\n ");
} else {
builder.append(".classpath(JavaParser.runtimeClasspath()))\n ");
}
}
return builder.toString();
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,19 @@ public String toJavaTemplateBuilder(int pos) {
tree = ((JCTree.JCReturn) tree).getExpression();
}

String javaParserClasspathFrom = processingEnv.getOptions().get("rewrite.javaParserClasspathFrom");
boolean classpathFromResources = "resources".equals(javaParserClasspathFrom);

List<JCTree.JCTypeParameter> typeParameters = classDecl.typarams == null ? emptyList() : classDecl.typarams;
return TemplateCode.process(tree, method.getReturnType().type, method.getParameters(), typeParameters, pos, method.restype.type instanceof Type.JCVoidType, true);
return TemplateCode.process(
tree,
method.getReturnType().type,
method.getParameters(),
typeParameters,
pos,
method.restype.type instanceof Type.JCVoidType,
true,
classpathFromResources);
}

public boolean validate() {
Expand Down
Loading