Skip to content

URLThreeArgumentConstructor does not introduce newly thrown exception #467

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
timtebeek opened this issue Apr 29, 2024 · 9 comments
Closed
Labels
bug Something isn't working

Comments

@timtebeek
Copy link
Contributor

What version of OpenRewrite are you using?

  • OpenRewrite v8.24.0
  • rewrite-migrate-java v2.12.0

How are you running OpenRewrite?

I'm running org.openrewrite.java.migrate.net.URLConstructorsToURI.URLThreeArgumentConstructorRecipe, via:

description = "Converts `new URL(String, String, String)` constructors to `new URI(...).toURL()`."
)
public static class URLThreeArgumentConstructor {
@BeforeTemplate
URL urlConstructor(String protocol, String host, String file) throws Exception {
return new URL(protocol, host, file);
}
@AfterTemplate
URL newUriToUrl(String protocol, String host, String file) throws Exception {
return new URI(protocol, null, host, -1, file, null, null).toURL();
}
}
@RecipeDescriptor(

What is the smallest, simplest way to reproduce the problem?

class A {
    URL urlConstructor(String protocol, String host, String file) throws IOException {
        return new URL(protocol, host, file);
    }
}

What did you expect to see?

class A {
    URL urlConstructor(String protocol, String host, String file) throws URISyntaxException, IOException {
            return new URI(protocol, null, host, -1, file, null, null).toURL();
        }
}

What did you see instead?

class A {
    URL urlConstructor(String protocol, String host, String file) throws IOException {
            return new URI(protocol, null, host, -1, file, null, null).toURL();
        }
}

Note the lacking throws URISyntaxException.

What is the full stack trace of any errors you encountered?

Compiler error, as URISyntaxException does not extend IOException, in contrast to MalformedURLException thrown before. As reported by @IanDarwin

@timtebeek timtebeek added the bug Something isn't working label Apr 29, 2024
@timtebeek timtebeek moved this to Backlog in OpenRewrite Apr 29, 2024
@timtebeek
Copy link
Contributor Author

This recipe is implemented as a Refaster recipe, and as such it's well possible the fix should land in https://github.com/openrewrite/rewrite-templating to introduce the new exception there from what's thrown in the after template method. /cc @knutwannheden

@Riyazul555
Copy link

Hey @timtebeek I have a suggestion on this issue
It seems like in your URLThreeArgumentConstructor class, you are converting new URL(String, String, String) constructors to new URI(...).toURL() without adding the throws URISyntaxException declaration in the AfterTemplate method. To fix this issue, you should include throws URISyntaxException in your AfterTemplate method like this:

public static class URLThreeArgumentConstructor {
        @BeforeTemplate
        URL urlConstructor(String protocol, String host, String file) throws Exception {
            return new URL(protocol, host, file);
        }

        @AfterTemplate
        URL newUriToUrl(String protocol, String host, String file) throws URISyntaxException {
            return new URI(protocol, null, host, -1, file, null, null).toURL();
        }
    }

This ensures that the throws URISyntaxException is correctly propagated in the converted code, addressing the issue you encountered.

What are your thoughts @timtebeek over this ?

@timtebeek
Copy link
Contributor Author

Hi! Thanks for the suggestion; the way that our rewrite-templating converts Refaster templates to OpenRewrite recipes does not yet include adding a throws declaration where necessary. It might be more complicated to add that there, but would indeed be helpful here.

Note that our implementation of Refaster is different from ErrorProne itself, if you're familiar with how ErrorProne works.

@koppor
Copy link

koppor commented Sep 24, 2024

Similar issue here

 package org.jabref.logic.importer.fetcher;
 
 import java.io.IOException;
+import java.net.URI;
 import java.net.URL;
 import java.util.Objects;
 import java.util.Optional;
 
 import org.jabref.logic.importer.FulltextFetcher;
@@ -60,11 +61,11 @@ public class SpringerLink implements FulltextFetcher, CustomizableKeyFetcher {
                 JSONObject json = jsonResponse.getBody().getObject();
                 int results = json.getJSONArray("result").getJSONObject(0).getInt("total");
 
                 if (results > 0) {
                     LOGGER.info("Fulltext PDF found @ Springer.");
-                    return Optional.of(new URL("http", CONTENT_HOST, "/content/pdf/%s.pdf".formatted(doi.get().getDOI())));
+                    return Optional.of(new URI("http", null, CONTENT_HOST, -1, "/content/pdf/%s.pdf".formatted(doi.get().getDOI()), null, null).toURL());
                 }
             }
         } catch (UnirestException e) {
             LOGGER.warn("SpringerLink API request failed", e);
         }

@ddsharpe
Copy link

ddsharpe commented Mar 7, 2025

Because org.openrewrite.java.migrate.UpgradeToJava21 includes the recipe org.openrewrite.java.migrate.net.URLConstructorsToURI, we have been unable to use UpgradeToJava21 in its current form. Everywhere that had new URL code is broken due to the lack of exception handling.

@timtebeek
Copy link
Contributor Author

Sorry to hear about your issues applying this recipe @ddsharpe ; if you want you can remove that single recipe through the recipe builder for now.

We've recently revised this recipe, which makes it easier to add more custom logic now if needed:

The question is a bit what folks expect: through "do no harm" we could remove the recipe from Java 21 upgrade for now, and/or look at adding the throws to any surrounding blocks / catch clauses, although might quickly become complex. Could you describe what behavior you'd expect in various cases? Preferably closely resembling our unit tests?

@ddsharpe
Copy link

@timtebeek I don't know if this would be the "perfect" answer, but given this is "converted code" I think this is what I would expect:
Given the original URL constructors can throw MalformedURLException, I think it would be okay for the replacement to do the same thing. Convert new URL(...) to new URI(...) and add a try/catch(URISyntaxException) that wraps the URISyntaxException with a MalformedURLException and rethrows the new MalformedURLException. Unfortunately, MalformedURLException does not have a constructor for that, but it is an extension of IOException that does have that constructor. new IOException(theURISyntaxException). If the user's code was catching MalformedURLException, it would be better to be an extension of that class and not IOException. Unfortunately, nothing is presenting it self as the perfect solution right now. Open to ideas.

@github-project-automation github-project-automation bot moved this from Backlog to Done in OpenRewrite Mar 11, 2025
@timtebeek
Copy link
Contributor Author

Thanks for researching and laying out the options here @ddsharpe ; what I've done for now is split the recipe we had in two: one part that's also included with the Java 21 upgrade, and a second part that can be optionally run but then lacks introducing the necessary error handling. /cc @rlsanders4 & @karthikNousher for your earlier involvement on #678

I hope that's satisfying for all: an out of the box experience that just works, as well as a dedicated recipe that can be run for additional changes, but might then result in a compilation issue regarding exception handling.

@ddsharpe
Copy link

Satisfied, thank you. Confirmed 3.4.0 did not change URL to URI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Archived in project
Development

No branches or pull requests

4 participants