diff --git a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java index bad6038f3b9..d671304708d 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java @@ -18,6 +18,8 @@ package org.springframework.boot.build.architecture; import java.io.File; import java.io.IOException; +import java.net.URLDecoder; +import java.net.URLEncoder; import java.nio.file.Files; import java.nio.file.StandardOpenOption; import java.util.List; @@ -60,6 +62,7 @@ import org.gradle.api.tasks.TaskAction; * {@link Task} that checks for architecture problems. * * @author Andy Wilkinson + * @author Yanming Zhou */ public abstract class ArchitectureCheck extends DefaultTask { @@ -71,7 +74,8 @@ public abstract class ArchitectureCheck extends DefaultTask { allBeanPostProcessorBeanMethodsShouldBeStaticAndHaveParametersThatWillNotCausePrematureInitialization(), allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(), noClassesShouldCallStepVerifierStepVerifyComplete(), - noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList()); + noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(), + noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding()); getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList())); } @@ -190,6 +194,20 @@ public abstract class ArchitectureCheck extends DefaultTask { .because("java.util.stream.Stream.toList() should be used instead"); } + private ArchRule noClassesShouldCallURLEncoderWithStringEncoding() { + return ArchRuleDefinition.noClasses() + .should() + .callMethod(URLEncoder.class, "encode", String.class, String.class) + .because("java.net.URLEncoder.encode(String s, Charset charset) should be used instead"); + } + + private ArchRule noClassesShouldCallURLDecoderWithStringEncoding() { + return ArchRuleDefinition.noClasses() + .should() + .callMethod(URLDecoder.class, "decode", String.class, String.class) + .because("java.net.URLDecoder.decode(String s, Charset charset) should be used instead"); + } + public void setClasses(FileCollection classes) { this.classes = classes; } diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java index e7a6ac524fa..f48abdf052f 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java @@ -23,6 +23,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -159,7 +160,7 @@ final class ChangeableUrls implements Iterable { urls.add(referenced); } else { - referenced = new URL(jarUrl, URLDecoder.decode(entry, "UTF-8")); + referenced = new URL(jarUrl, URLDecoder.decode(entry, StandardCharsets.UTF_8)); if (new File(referenced.getFile()).exists()) { urls.add(referenced); } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/web/SpringBootMockServletContextTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/web/SpringBootMockServletContextTests.java index c641e03f3f6..ec52bb67465 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/web/SpringBootMockServletContextTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/web/SpringBootMockServletContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import jakarta.servlet.ServletContext; import org.junit.jupiter.api.Test; @@ -80,7 +81,7 @@ class SpringBootMockServletContextTests implements ServletContextAware { }; URL resource = context.getResource("/"); assertThat(resource).isNotNull(); - File file = new File(URLDecoder.decode(resource.getPath(), "UTF-8")); + File file = new File(URLDecoder.decode(resource.getPath(), StandardCharsets.UTF_8)); assertThat(file).exists().isDirectory(); String[] contents = file.list((dir, name) -> !(".".equals(name) || "..".equals(name))); assertThat(contents).isNotNull(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java index 3703ac13670..908f5c033ec 100755 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java @@ -20,12 +20,12 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.UnsupportedEncodingException; import java.lang.reflect.Constructor; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -225,9 +225,9 @@ public class PropertiesLauncher extends Launcher { return getFileResource(config); } - private String handleUrl(String path) throws UnsupportedEncodingException { + private String handleUrl(String path) { if (path.startsWith("jar:file:") || path.startsWith("file:")) { - path = URLDecoder.decode(path, "UTF-8"); + path = URLDecoder.decode(path, StandardCharsets.UTF_8); if (path.startsWith("file:")) { path = path.substring("file:".length()); if (path.startsWith("//")) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java index 859ae88ab00..0af645f19c7 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java @@ -20,12 +20,12 @@ import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.net.URLStreamHandler; +import java.nio.charset.StandardCharsets; import java.security.Permission; /** @@ -318,13 +318,8 @@ final class JarURLConnection extends java.net.JarURLConnection { for (int i = 0; i < length; i++) { int c = source.charAt(i); if (c > 127) { - try { - String encoded = URLEncoder.encode(String.valueOf((char) c), "UTF-8"); - write(encoded, outputStream); - } - catch (UnsupportedEncodingException ex) { - throw new IllegalStateException(ex); - } + String encoded = URLEncoder.encode(String.valueOf((char) c), StandardCharsets.UTF_8); + write(encoded, outputStream); } else { if (c == '%') { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java index ae43901c8ad..6c348987ca7 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java @@ -20,6 +20,7 @@ import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; @@ -553,7 +554,7 @@ public class UndertowServletWebServerFactory extends AbstractServletWebServerFac private URLResource getMetaInfResource(URL resourceJar, String path) { try { - String urlPath = URLEncoder.encode(ENCODED_SLASH.matcher(path).replaceAll("/"), "UTF-8"); + String urlPath = URLEncoder.encode(ENCODED_SLASH.matcher(path).replaceAll("/"), StandardCharsets.UTF_8); URL resourceUrl = new URL(resourceJar + "META-INF/resources" + urlPath); URLResource resource = new URLResource(resourceUrl, path); if (resource.getContentLength() < 0) {