I'm migrating my code to Java 20.
In this release, the java.net.URL#URL(java.lang.String) got deprecated. Unfortunately, I have a class where I found no replacement for the old URL constructor.
package com.github.bottomlessarchive.loa.url.service.encoder;
import io.mola.galimatias.GalimatiasParseException;
import org.springframework.stereotype.Service;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Optional;
/**
* This service is responsible for encoding existing {@link URL} instances to valid
* <a href="https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier">resource identifiers</a>.
*/
@Service
public class UrlEncoder {
/**
* Encodes the provided URL to a valid
* <a href="https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier">resource identifier</a> and return
* the new identifier as a URL.
*
* @param link the url to encode
* @return the encoded url
*/
public Optional<URL> encode(final String link) {
try {
final URL url = new URL(link);
// We need to further validate the URL because the java.net.URL's validation is inadequate.
validateUrl(url);
return Optional.of(encodeUrl(url));
} catch (GalimatiasParseException | MalformedURLException | URISyntaxException e) {
return Optional.empty();
}
}
private void validateUrl(final URL url) throws URISyntaxException {
// This will trigger an URISyntaxException. It is needed because the constructor of java.net.URL doesn't always validate the
// passed url correctly.
new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
}
private URL encodeUrl(final URL url) throws GalimatiasParseException, MalformedURLException {
return io.mola.galimatias.URL.parse(url.toString()).toJavaURL();
}
}
Luckily, I have tests for the class as well:
package com.github.bottomlessarchive.loa.url.service.encoder;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
class UrlEncoderTest {
private final UrlEncoder underTest = new UrlEncoder();
@ParameterizedTest
@CsvSource(
value = {
"http://www.example.com/?test=Hello world,http://www.example.com/?test=Hello%20world",
"http://www.example.com/?test=ŐÚőúŰÜűü,http://www.example.com/?test=%C5%90%C3%9A%C5%91%C3%BA%C5%B0%C3%9C%C5%B1%C3%BC",
"http://www.example.com/?test=random word £500 bank $,"
+ "http://www.example.com/?test=random%20word%20%C2%A3500%20bank%20$",
"http://www.aquincum.hu/wp-content/uploads/2015/06/Aquincumi-F%C3%BCzetek_14_2008.pdf,"
+ "http://www.aquincum.hu/wp-content/uploads/2015/06/Aquincumi-F%C3%BCzetek_14_2008.pdf",
"http://www.aquincum.hu/wp-content/uploads/2015/06/Aquincumi-F%C3%BCzetek_14 _2008.pdf,"
+ "http://www.aquincum.hu/wp-content/uploads/2015/06/Aquincumi-F%C3%BCzetek_14%20_2008.pdf"
}
)
void testEncodeWhenUsingValidUrls(final String urlToEncode, final String expected) throws MalformedURLException {
final Optional<URL> result = underTest.encode(urlToEncode);
assertThat(result)
.contains(new URL(expected));
}
@ParameterizedTest
@CsvSource(
value = {
"http://промкаталог.рф/PublicDocuments/05-0211-00.pdf"
}
)
void testEncodeWhenUsingInvalidUrls(final String urlToEncode) {
final Optional<URL> result = underTest.encode(urlToEncode);
assertThat(result)
.isEmpty();
}
}
The only dependency it uses is the galamatias URL library.
Does anyone have any ideas on how could I remove the new URL(link)
code fragment while keeping the functionality the same?
I tried various things, like using java.net.URI#create
but it did not produce the exact result as the previous solution. For example, URLs that contain non-encoded characters like a space in http://www.example.com/?test=Hello world
resulted in an IllegalArgumentException. This was parsed by the URL class without giving an error (and my data contains a lot of these). Also, links that failed the URL conversion like http://промкаталог.рф/PublicDocuments/05-0211-00.pdf
are converted to URI successfully with URI.create.