1515 */
1616package org .openrewrite .java .migrate .net ;
1717
18+ import fj .data .Option ;
19+ import org .jspecify .annotations .Nullable ;
1820import org .openrewrite .ExecutionContext ;
19- import org .openrewrite .ScanningRecipe ;
21+ import org .openrewrite .Recipe ;
2022import org .openrewrite .TreeVisitor ;
21- import org .openrewrite .java .*;
23+ import org .openrewrite .analysis .constantfold .ConstantFold ;
24+ import org .openrewrite .analysis .util .CursorUtil ;
25+ import org .openrewrite .java .JavaParser ;
26+ import org .openrewrite .java .JavaTemplate ;
27+ import org .openrewrite .java .JavaVisitor ;
28+ import org .openrewrite .java .MethodMatcher ;
2229import org .openrewrite .java .tree .Expression ;
2330import org .openrewrite .java .tree .J ;
2431import org .openrewrite .java .tree .JavaType ;
25- import org .openrewrite .java .tree .Statement ;
2632
2733import java .net .URI ;
28- import java .util .HashSet ;
29- import java .util .List ;
30- import java .util .Set ;
3134
32- public class URLConstructorsToURI extends ScanningRecipe < Set < String >> {
35+ public class URLConstructorsToURI extends Recipe {
3336 @ Override
3437 public String getDisplayName () {
3538 return "Convert `new URL(String)` to `URI.create(String).toURL()`" ;
@@ -41,88 +44,25 @@ public String getDescription() {
4144 }
4245
4346 @ Override
44- public Set <String > getInitialValue (ExecutionContext ctx ) {
45- return new HashSet <>();
46- }
47-
48- @ Override
49- public TreeVisitor <?, ExecutionContext > getScanner (Set <String > wrapperMethodClasses ) {
50- return new JavaIsoVisitor <ExecutionContext >() {
51- private final MethodMatcher methodMatcherSingleArg = new MethodMatcher ("java.net.URL <constructor>(java.lang.String)" );
52-
53- @ Override
54- public J .NewClass visitNewClass (J .NewClass nc , ExecutionContext ctx ) {
55- if (methodMatcherSingleArg .matches (nc )) {
56- Expression arg = nc .getArguments ().get (0 );
57- if (!(arg instanceof J .Literal && arg .getType ().toString ().equals ("String" ))) {
58- J .ClassDeclaration cd = getCursor ().firstEnclosing (J .ClassDeclaration .class );
59- if (cd != null ) {
60- wrapperMethodClasses .add (cd .getType ().getFullyQualifiedName ());
61- }
62- }
63- }
64- return super .visitNewClass (nc , ctx );
65- }
66- };
67- }
68-
69- @ Override
70- public TreeVisitor <?, ExecutionContext > getVisitor (Set <String > wrapperMethodClasses ) {
47+ public TreeVisitor <?, ExecutionContext > getVisitor () {
7148 return new JavaVisitor <ExecutionContext >() {
7249 private final MethodMatcher methodMatcherSingleArg = new MethodMatcher ("java.net.URL <constructor>(java.lang.String)" );
7350 private final MethodMatcher methodMatcherThreeArg = new MethodMatcher ("java.net.URL <constructor>(java.lang.String, java.lang.String, java.lang.String)" );
7451 private final MethodMatcher methodMatcherFourArg = new MethodMatcher ("java.net.URL <constructor>(java.lang.String, java.lang.String, int, java.lang.String)" );
75- JavaType .Method methodType ;
76-
77-
78- @ Override
79- public J visitClassDeclaration (J .ClassDeclaration cd , ExecutionContext ctx ) {
80- boolean wrapperMethodExists = cd .getBody ()
81- .getStatements ()
82- .stream ()
83- .filter (J .MethodDeclaration .class ::isInstance )
84- .map (J .MethodDeclaration .class ::cast )
85- .anyMatch (md -> md .getSimpleName ().equals ("transformNonLiteralURIToValidURL" ));
86-
87- if (!wrapperMethodExists && wrapperMethodClasses .contains (cd .getType ().getFullyQualifiedName ())) {
88- JavaTemplate convertUriMethod = JavaTemplate .builder (
89- "public URL transformNonLiteralURIToValidURL(String spec) {\n " +
90- " try {\n " +
91- " return URI.create(spec).toURL();\n " +
92- " } catch (Exception e) {\n " +
93- " return new URL(spec);\n " +
94- " }\n " +
95- "}" )
96- .contextSensitive ()
97- .imports ("java.net.URI" , "java.net.URL" )
98- .javaParser (JavaParser .fromJavaVersion ())
99- .build ();
100- maybeAddImport ("java.net.URI" );
101-
102- cd = convertUriMethod .apply (updateCursor (cd ), cd .getBody ().getCoordinates ().lastStatement ());
103-
104- List <Statement > statements = cd .getBody ().getStatements ();
105- J .MethodDeclaration md = (J .MethodDeclaration ) statements .get (statements .size () - 1 );
106- methodType = md .getMethodType ();
107- }
108- return super .visitClassDeclaration (cd , ctx );
109- }
11052
11153 @ Override
11254 public J visitNewClass (J .NewClass nc , ExecutionContext ctx ) {
113- J .MethodDeclaration enclosingMethod = getCursor ().firstEnclosing (J .MethodDeclaration .class );
114- if (enclosingMethod != null && enclosingMethod .getSimpleName ().equals ("transformNonLiteralURIToValidURL" )) {
115- return super .visitNewClass (nc , ctx );
116- }
117-
11855 if (methodMatcherSingleArg .matches (nc )) {
11956 Expression arg = nc .getArguments ().get (0 );
12057
121- if (arg instanceof J .Literal && arg .getType ().toString ().equals ("String" )) {
122- // If the argument is a string literal, only convert the constructor if the argument is a valid input
58+ if (arg instanceof J .Literal ) {
59+ // Check if the literal is of type String
60+ if (!arg .getType ().toString ().equals ("String" )) {
61+ return nc ;
62+ }
12363
64+ // Check if value is null
12465 String literalValue = ((J .Literal ) arg ).getValueSource ();
125-
12666 if (literalValue == null ) {
12767 return nc ;
12868 }
@@ -133,39 +73,47 @@ public J visitNewClass(J.NewClass nc, ExecutionContext ctx) {
13373
13474
13575 // Check that this string is a valid input for URI.create().toURL()
136- try {
137- //noinspection ResultOfMethodCallIgnored
138- URI .create (literalValue ).toURL ();
139- } catch (Exception e ) {
76+ if (isNotValidPath (literalValue )) {
77+ return nc ;
78+ }
79+
80+ } else if (arg instanceof J .Identifier ) {
81+ // Check if type is String
82+ JavaType type = arg .getType ();
83+ if (type == null || !type .toString ().equals ("java.lang.String" )) {
84+ return nc ;
85+ }
86+
87+
88+ // Check if constant value is valid
89+ String constantValue = null ;
90+ Option <String > constant = CursorUtil .findCursorForTree (getCursor (), arg )
91+ .bind (c -> ConstantFold .findConstantLiteralValue (c , String .class ));
92+
93+ if (constant .isSome ()) {
94+ constantValue = constant .some ();
95+ }
96+
97+ if (isNotValidPath (constantValue )) {
14098 return nc ;
14199 }
142100
143- JavaTemplate template = JavaTemplate .builder ("URI.create(#{any(String)}).toURL()" )
144- .imports ("java.net.URI" )
145- .contextSensitive ()
146- .javaParser (JavaParser .fromJavaVersion ())
147- .build ();
148-
149- J result = template .apply (getCursor (),
150- nc .getCoordinates ().replace (),
151- nc .getArguments ().get (0 ));
152- maybeAddImport ("java.net.URI" );
153- return result ;
154101 } else {
155- // If the argument is not a string literal, replace the constructor with the wrapper method
156- JavaTemplate template = JavaTemplate .builder ("transformNonLiteralURIToValidURL(#{any(String)})" )
157- .imports ("java.net.URI" )
158- .contextSensitive ()
159- .javaParser (JavaParser .fromJavaVersion ())
160- .build ();
161- J .MethodInvocation result = template .apply (updateCursor (nc ), nc .getCoordinates ().replace (), nc .getArguments ().get (0 ));
162- result = result .withMethodType (methodType );
163- J .Identifier name = result .getName ();
164- name = name .withType (methodType );
165- result = result .withName (name );
166- maybeAddImport ("java.net.URI" );
167- return result ;
102+ return nc ;
168103 }
104+
105+ JavaTemplate template = JavaTemplate .builder ("URI.create(#{any(String)}).toURL()" )
106+ .imports ("java.net.URI" )
107+ .contextSensitive ()
108+ .javaParser (JavaParser .fromJavaVersion ())
109+ .build ();
110+
111+ J result = template .apply (getCursor (),
112+ nc .getCoordinates ().replace (),
113+ nc .getArguments ().get (0 ));
114+ maybeAddImport ("java.net.URI" );
115+
116+ return result ;
169117 } else if (methodMatcherThreeArg .matches (nc )) {
170118 JavaTemplate template = JavaTemplate .builder ("new URI(#{any(String)}, null, #{any(String)}, -1, #{any(String)}, null, null).toURL()" )
171119 .imports ("java.net.URI" , "java.net.URL" )
@@ -198,4 +146,19 @@ public J visitNewClass(J.NewClass nc, ExecutionContext ctx) {
198146 }
199147 };
200148 }
149+
150+ private static boolean isNotValidPath (@ Nullable String path ) {
151+ if (path == null ) {
152+ return true ;
153+ }
154+
155+ try {
156+ //noinspection ResultOfMethodCallIgnored
157+ URI .create (path ).toURL ();
158+ } catch (Exception e ) {
159+ return true ;
160+ }
161+
162+ return false ;
163+ }
201164}
0 commit comments