This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new e985f2eec [LANG-1838] Fix resource paths for unnamed packages (#1824)
e985f2eec is described below
commit e985f2eec421adac19fbf070734cee0a1348d61f
Author: Aryan R. Ganjoo <[email protected]>
AuthorDate: Sun Oct 18 00:34:10 2026 +0530
[LANG-1838] Fix resource paths for unnamed packages (#1824)
Return the unprefixed resource name for an empty Package name, and handle
Java 8 unnamed-package classes whose getPackage() is null. Add focused
regressions for class and Package overloads while retaining named-package and
null behavior.
AI-Assisted-by: OpenAI Codex
---
.../org/apache/commons/lang3/ClassPathUtils.java | 14 +++++---
src/test/java/ClassPathUtilsDefaultPackage.java | 25 +++++++++++++
.../apache/commons/lang3/ClassPathUtilsTest.java | 42 ++++++++++++++++++++++
3 files changed, 77 insertions(+), 4 deletions(-)
diff --git a/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
b/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
index 52b452b62..6fff8732d 100644
--- a/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
@@ -73,7 +73,9 @@ public static String pathToPackage(final String path) {
public static String toFullyQualifiedName(final Class<?> context, final
String resourceName) {
Objects.requireNonNull(context, "context");
Objects.requireNonNull(resourceName, "resourceName");
- return toFullyQualifiedName(context.getPackage(), resourceName);
+ final Package contextPackage = context.getPackage();
+ return contextPackage == null && !context.isArray() &&
!context.isPrimitive() && context.getName().indexOf('.') < 0
+ ? resourceName :
toFullyQualifiedName(Objects.requireNonNull(contextPackage, "context"),
resourceName);
}
/**
@@ -95,7 +97,8 @@ public static String toFullyQualifiedName(final Class<?>
context, final String r
public static String toFullyQualifiedName(final Package context, final
String resourceName) {
Objects.requireNonNull(context, "context");
Objects.requireNonNull(resourceName, "resourceName");
- return context.getName() + "." + resourceName;
+ final String packageName = context.getName();
+ return packageName.isEmpty() ? resourceName : packageName + "." +
resourceName;
}
/**
@@ -117,7 +120,9 @@ public static String toFullyQualifiedName(final Package
context, final String re
public static String toFullyQualifiedPath(final Class<?> context, final
String resourceName) {
Objects.requireNonNull(context, "context");
Objects.requireNonNull(resourceName, "resourceName");
- return toFullyQualifiedPath(context.getPackage(), resourceName);
+ final Package contextPackage = context.getPackage();
+ return contextPackage == null && !context.isArray() &&
!context.isPrimitive() && context.getName().indexOf('.') < 0
+ ? resourceName :
toFullyQualifiedPath(Objects.requireNonNull(contextPackage, "context"),
resourceName);
}
/**
@@ -139,7 +144,8 @@ public static String toFullyQualifiedPath(final Class<?>
context, final String r
public static String toFullyQualifiedPath(final Package context, final
String resourceName) {
Objects.requireNonNull(context, "context");
Objects.requireNonNull(resourceName, "resourceName");
- return packageToPath(context.getName()) + "/" + resourceName;
+ final String packageName = context.getName();
+ return packageName.isEmpty() ? resourceName :
packageToPath(packageName) + "/" + resourceName;
}
/**
diff --git a/src/test/java/ClassPathUtilsDefaultPackage.java
b/src/test/java/ClassPathUtilsDefaultPackage.java
new file mode 100644
index 000000000..ce18f143d
--- /dev/null
+++ b/src/test/java/ClassPathUtilsDefaultPackage.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * A class in the unnamed package for {@code ClassPathUtilsTest}.
+ */
+public final class ClassPathUtilsDefaultPackage {
+
+ private ClassPathUtilsDefaultPackage() {
+ }
+}
diff --git a/src/test/java/org/apache/commons/lang3/ClassPathUtilsTest.java
b/src/test/java/org/apache/commons/lang3/ClassPathUtilsTest.java
index 50759d365..8dc62acd0 100644
--- a/src/test/java/org/apache/commons/lang3/ClassPathUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/ClassPathUtilsTest.java
@@ -31,6 +31,14 @@
*/
class ClassPathUtilsTest extends AbstractLangTest {
+ private static Package unnamedPackage() {
+ return new ClassLoader() {
+ Package defineUnnamedPackage() {
+ return definePackage("", null, null, null, null, null, null,
null);
+ }
+ }.defineUnnamedPackage();
+ }
+
@Test
void testConstructor() {
assertNotNull(new ClassPathUtils());
@@ -60,6 +68,12 @@ void testToFullyQualifiedNameClassNull() {
assertNullPointerException(() ->
ClassPathUtils.toFullyQualifiedName(ClassPathUtils.class, null));
}
+ @Test
+ void testToFullyQualifiedNameArrayAndPrimitiveClass() {
+ assertNullPointerException(() ->
ClassPathUtils.toFullyQualifiedName(String[].class, "Test.properties"));
+ assertNullPointerException(() ->
ClassPathUtils.toFullyQualifiedName(int.class, "Test.properties"));
+ }
+
@Test
void testToFullyQualifiedNameClassString() {
final String expected = "org.apache.commons.lang3.Test.properties";
@@ -94,6 +108,17 @@ void testToFullyQualifiedNamePackageString() {
assertEquals(expected, actual);
}
+ @Test
+ void testToFullyQualifiedNameUnnamedPackage() {
+ assertEquals("Test.properties",
ClassPathUtils.toFullyQualifiedName(unnamedPackage(), "Test.properties"));
+ }
+
+ @Test
+ void testToFullyQualifiedNameUnnamedPackageClass() throws
ClassNotFoundException {
+ assertEquals("Test.properties", ClassPathUtils.toFullyQualifiedName(
+ Class.forName("ClassPathUtilsDefaultPackage"),
"Test.properties"));
+ }
+
@Test
void testToFullyQualifiedPathClass() {
final String expected = "org/apache/commons/lang3/Test.properties";
@@ -107,6 +132,12 @@ void testToFullyQualifiedPathClassNull() {
assertNullPointerException(() ->
ClassPathUtils.toFullyQualifiedPath(ClassPathUtils.class, null));
}
+ @Test
+ void testToFullyQualifiedPathArrayAndPrimitiveClass() {
+ assertNullPointerException(() ->
ClassPathUtils.toFullyQualifiedPath(String[].class, "Test.properties"));
+ assertNullPointerException(() ->
ClassPathUtils.toFullyQualifiedPath(int.class, "Test.properties"));
+ }
+
@Test
void testToFullyQualifiedPathClassNullString() {
assertNullPointerException(
@@ -132,4 +163,15 @@ void testToFullyQualifiedPathPackageNullString() {
assertNullPointerException(
() -> ClassPathUtils.toFullyQualifiedPath((Package) null,
"Test.properties"));
}
+
+ @Test
+ void testToFullyQualifiedPathUnnamedPackage() {
+ assertEquals("Test.properties",
ClassPathUtils.toFullyQualifiedPath(unnamedPackage(), "Test.properties"));
+ }
+
+ @Test
+ void testToFullyQualifiedPathUnnamedPackageClass() throws
ClassNotFoundException {
+ assertEquals("Test.properties", ClassPathUtils.toFullyQualifiedPath(
+ Class.forName("ClassPathUtilsDefaultPackage"),
"Test.properties"));
+ }
}