1515 */
1616package org .openrewrite .java .migrate .net ;
1717
18- import fj .data .Option ;
1918import org .jspecify .annotations .Nullable ;
2019import org .openrewrite .ExecutionContext ;
20+ import org .openrewrite .Preconditions ;
2121import org .openrewrite .Recipe ;
2222import org .openrewrite .TreeVisitor ;
2323import org .openrewrite .analysis .constantfold .ConstantFold ;
2626import org .openrewrite .java .JavaTemplate ;
2727import org .openrewrite .java .JavaVisitor ;
2828import org .openrewrite .java .MethodMatcher ;
29+ import org .openrewrite .java .search .UsesType ;
2930import org .openrewrite .java .tree .Expression ;
3031import org .openrewrite .java .tree .J ;
3132import org .openrewrite .java .tree .JavaType ;
33+ import org .openrewrite .java .tree .TypeUtils ;
3234
3335import java .net .URI ;
3436
3537public class URLConstructorsToURI extends Recipe {
38+
39+ private static final String URI_FQN = "java.net.URI" ;
40+ private static final String URL_FQN = "java.net.URL" ;
41+ private static final MethodMatcher methodMatcherSingleArg = new MethodMatcher (URL_FQN + " <constructor>(java.lang.String)" );
42+ private static final MethodMatcher methodMatcherThreeArg = new MethodMatcher (URL_FQN + " <constructor>(java.lang.String, java.lang.String, java.lang.String)" );
43+ private static final MethodMatcher methodMatcherFourArg = new MethodMatcher (URL_FQN + " <constructor>(java.lang.String, java.lang.String, int, java.lang.String)" );
44+
3645 @ Override
3746 public String getDisplayName () {
3847 return "Convert `new URL(String)` to `URI.create(String).toURL()`" ;
@@ -45,120 +54,90 @@ public String getDescription() {
4554
4655 @ Override
4756 public TreeVisitor <?, ExecutionContext > getVisitor () {
48- return new JavaVisitor <ExecutionContext >() {
49- private final MethodMatcher methodMatcherSingleArg = new MethodMatcher ("java.net.URL <constructor>(java.lang.String)" );
50- private final MethodMatcher methodMatcherThreeArg = new MethodMatcher ("java.net.URL <constructor>(java.lang.String, java.lang.String, java.lang.String)" );
51- private final MethodMatcher methodMatcherFourArg = new MethodMatcher ("java.net.URL <constructor>(java.lang.String, java.lang.String, int, java.lang.String)" );
52-
53- @ Override
54- public J visitNewClass (J .NewClass nc , ExecutionContext ctx ) {
55- if (methodMatcherSingleArg .matches (nc )) {
56- Expression arg = nc .getArguments ().get (0 );
57-
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- }
63-
64- // Check if value is null
65- String literalValue = ((J .Literal ) arg ).getValueSource ();
66- if (literalValue == null ) {
67- return nc ;
68- }
69-
70- // Remove quotations from string
71- literalValue = literalValue .substring (1 );
72- literalValue = literalValue .substring (0 , literalValue .length () - 1 );
73-
74-
75- // Check that this string is a valid input for URI.create().toURL()
76- if (isNotValidPath (literalValue )) {
77- return nc ;
57+ return Preconditions .check (new UsesType <>(URL_FQN , false ),
58+ new JavaVisitor <ExecutionContext >() {
59+ @ Override
60+ public J visitNewClass (J .NewClass nc , ExecutionContext ctx ) {
61+ if (methodMatcherSingleArg .matches (nc )) {
62+ String path = extractPath (nc .getArguments ().get (0 ));
63+ if (isNotValidPath (path )) {
64+ return nc ;
65+ }
66+
67+ JavaTemplate template = JavaTemplate .builder ("URI.create(#{any(String)}).toURL()" )
68+ .imports (URI_FQN )
69+ .contextSensitive ()
70+ .javaParser (JavaParser .fromJavaVersion ())
71+ .build ();
72+ maybeAddImport (URI_FQN );
73+
74+ return template .apply (getCursor (),
75+ nc .getCoordinates ().replace (),
76+ nc .getArguments ().get (0 ));
77+ } else {
78+ if (methodMatcherThreeArg .matches (nc )) {
79+ JavaTemplate template = JavaTemplate .builder ("new URI(#{any(String)}, null, #{any(String)}, -1, #{any(String)}, null, null).toURL()" )
80+ .imports (URI_FQN , URL_FQN )
81+ .contextSensitive ()
82+ .javaParser (JavaParser .fromJavaVersion ())
83+ .build ();
84+
85+ maybeAddImport (URI_FQN );
86+ return template .apply (getCursor (), nc .getCoordinates ().replace (),
87+ nc .getArguments ().get (0 ),
88+ nc .getArguments ().get (1 ),
89+ nc .getArguments ().get (2 ));
90+ } else if (methodMatcherFourArg .matches (nc )) {
91+ JavaTemplate template = JavaTemplate .builder ("new URI(#{any(String)}, null, #{any(String)}, #{any(int)}, #{any(String)}, null, null).toURL()" )
92+ .imports (URI_FQN , URL_FQN )
93+ .contextSensitive ()
94+ .javaParser (JavaParser .fromJavaVersion ())
95+ .build ();
96+
97+ maybeAddImport (URI_FQN );
98+ return template .apply (getCursor (), nc .getCoordinates ().replace (),
99+ nc .getArguments ().get (0 ),
100+ nc .getArguments ().get (1 ),
101+ nc .getArguments ().get (2 ),
102+ nc .getArguments ().get (3 ));
103+ }
78104 }
105+ return super .visitNewClass (nc , ctx );
106+ }
79107
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 ;
108+ @ Nullable
109+ private String extractPath (Expression arg ) {
110+ if (arg instanceof J .Literal &&
111+ TypeUtils .isOfType (arg .getType (), JavaType .Primitive .String )) {
112+ // Check if value is not null
113+ String literalValueSource = ((J .Literal ) arg ).getValueSource ();
114+ // Remove quotations from string
115+ return literalValueSource != null ? literalValueSource .substring (1 , literalValueSource .length () - 1 ).trim () : null ;
116+ } else if (arg instanceof J .Identifier &&
117+ TypeUtils .isOfType (arg .getType (), JavaType .Primitive .String )) {
118+ // find constant value of the identifier
119+ return CursorUtil .findCursorForTree (getCursor (), arg )
120+ .bind (c -> ConstantFold .findConstantLiteralValue (c , String .class ))
121+ .toNull ();
122+ } else {
123+ // null indicates no path extractable
124+ return null ;
85125 }
126+ }
86127
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 ();
128+ private boolean isNotValidPath (@ Nullable String path ) {
129+ if (path == null ) {
130+ return true ;
95131 }
96132
97- if (isNotValidPath (constantValue )) {
98- return nc ;
133+ try {
134+ //noinspection ResultOfMethodCallIgnored
135+ URI .create (path ).toURL ();
136+ return false ;
137+ } catch (Exception e ) {
138+ return true ;
99139 }
100-
101- } else {
102- return nc ;
103140 }
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 ;
117- } else if (methodMatcherThreeArg .matches (nc )) {
118- JavaTemplate template = JavaTemplate .builder ("new URI(#{any(String)}, null, #{any(String)}, -1, #{any(String)}, null, null).toURL()" )
119- .imports ("java.net.URI" , "java.net.URL" )
120- .contextSensitive ()
121- .javaParser (JavaParser .fromJavaVersion ())
122- .build ();
123-
124- J result = template .apply (getCursor (), nc .getCoordinates ().replace (),
125- nc .getArguments ().get (0 ),
126- nc .getArguments ().get (1 ),
127- nc .getArguments ().get (2 ));
128- maybeAddImport ("java.net.URI" );
129- return result ;
130- } else if (methodMatcherFourArg .matches (nc )) {
131- JavaTemplate template = JavaTemplate .builder ("new URI(#{any(String)}, null, #{any(String)}, #{any(int)}, #{any(String)}, null, null).toURL()" )
132- .imports ("java.net.URI" , "java.net.URL" )
133- .contextSensitive ()
134- .javaParser (JavaParser .fromJavaVersion ())
135- .build ();
136-
137- J result = template .apply (getCursor (), nc .getCoordinates ().replace (),
138- nc .getArguments ().get (0 ),
139- nc .getArguments ().get (1 ),
140- nc .getArguments ().get (2 ),
141- nc .getArguments ().get (3 ));
142- maybeAddImport ("java.net.URI" );
143- return result ;
144- }
145- return super .visitNewClass (nc , ctx );
146- }
147- };
148- }
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 ;
141+ });
163142 }
164143}
0 commit comments