From f146d09607286909eff62e540be3e36630442ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Mon, 20 Nov 2023 11:44:12 +0100 Subject: [PATCH] Handle default package with AOT processing Adding generated code in the default package is not supported as we intend to import it, most probably from another package, and that is not supported. While this situation is hard to replicate with Java, Kotlin is unfortunately more lenient and users can end up in that situation if they forget to add a package statement. This commit checks for the presence of a valid package, and throws a dedicated exception if necessary. Closes gh-31628 --- .../aot/generate/GeneratedFiles.java | 11 +++++++++++ .../aot/generate/GeneratedFilesTests.java | 17 +++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/spring-core/src/main/java/org/springframework/aot/generate/GeneratedFiles.java b/spring-core/src/main/java/org/springframework/aot/generate/GeneratedFiles.java index bd6ec60ae27..1c326e4fd96 100644 --- a/spring-core/src/main/java/org/springframework/aot/generate/GeneratedFiles.java +++ b/spring-core/src/main/java/org/springframework/aot/generate/GeneratedFiles.java @@ -20,6 +20,7 @@ import org.springframework.core.io.InputStreamSource; import org.springframework.javapoet.JavaFile; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; import org.springframework.util.function.ThrowingConsumer; /** @@ -43,6 +44,7 @@ public interface GeneratedFiles { * @param javaFile the java file to add */ default void addSourceFile(JavaFile javaFile) { + validatePackage(javaFile.packageName, javaFile.typeSpec.name); String className = javaFile.packageName + "." + javaFile.typeSpec.name; addSourceFile(className, javaFile::writeTo); } @@ -161,11 +163,20 @@ public interface GeneratedFiles { private static String getClassNamePath(String className) { Assert.hasLength(className, "'className' must not be empty"); + validatePackage(ClassUtils.getPackageName(className), className); Assert.isTrue(isJavaIdentifier(className), "'className' must be a valid identifier, got '" + className + "'"); return ClassUtils.convertClassNameToResourcePath(className) + ".java"; } + private static void validatePackage(String packageName, String className) { + if (!StringUtils.hasLength(packageName)) { + throw new IllegalArgumentException("Could not add '" + className + "', " + + "processing classes in the default package is not supported. " + + "Did you forget to add a package statement?"); + } + } + private static boolean isJavaIdentifier(String className) { char[] chars = className.toCharArray(); for (int i = 0; i < chars.length; i++) { diff --git a/spring-core/src/test/java/org/springframework/aot/generate/GeneratedFilesTests.java b/spring-core/src/test/java/org/springframework/aot/generate/GeneratedFilesTests.java index 0eeb510490e..3372fe0c4da 100644 --- a/spring-core/src/test/java/org/springframework/aot/generate/GeneratedFilesTests.java +++ b/spring-core/src/test/java/org/springframework/aot/generate/GeneratedFilesTests.java @@ -60,6 +60,15 @@ class GeneratedFilesTests { .contains("Hello, World!"); } + @Test + void addSourceFileWithJavaFileInTheDefaultPackageThrowsException() { + TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld").build(); + JavaFile javaFile = JavaFile.builder("", helloWorld).build(); + assertThatIllegalArgumentException().isThrownBy(() -> this.generatedFiles.addSourceFile(javaFile)) + .withMessage("Could not add 'HelloWorld', processing classes in the " + + "default package is not supported. Did you forget to add a package statement?"); + } + @Test void addSourceFileWithCharSequenceAddsFile() throws Exception { this.generatedFiles.addSourceFile("com.example.HelloWorld", "{}"); @@ -73,6 +82,14 @@ class GeneratedFilesTests { .withMessage("'className' must not be empty"); } + @Test + void addSourceFileWithCharSequenceWhenClassNameIsInTheDefaultPackageThrowsException() { + assertThatIllegalArgumentException() + .isThrownBy(() -> this.generatedFiles.addSourceFile("HelloWorld", "{}")) + .withMessage("Could not add 'HelloWorld', processing classes in the " + + "default package is not supported. Did you forget to add a package statement?"); + } + @Test void addSourceFileWithCharSequenceWhenClassNameIsInvalidThrowsException() { assertThatIllegalArgumentException()