From 5b014e43488e025c8c56e616190083335e3db7a9 Mon Sep 17 00:00:00 2001 From: farkhalit rida Date: Mon, 20 Jul 2026 14:05:53 +0530 Subject: [PATCH] load classes without initializing them in Converter.CLASS --- .../org/apache/commons/cli/Converter.java | 5 +++-- .../apache/commons/cli/ConverterTests.java | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/cli/Converter.java b/src/main/java/org/apache/commons/cli/Converter.java index fcb9c43b5..0a2981ee6 100644 --- a/src/main/java/org/apache/commons/cli/Converter.java +++ b/src/main/java/org/apache/commons/cli/Converter.java @@ -43,9 +43,10 @@ public interface Converter { Converter DEFAULT = s -> s; /** - * Converts a String to a {@link Class}. Calls {@link Class#forName(String)}. + * Converts a String to a {@link Class}. Calls {@link Class#forName(String, boolean, ClassLoader)} with {@code initialize} set to {@code false} so that + * naming a class does not run its static initializer. */ - Converter, ClassNotFoundException> CLASS = Class::forName; + Converter, ClassNotFoundException> CLASS = s -> Class.forName(s, false, Converter.class.getClassLoader()); /** * Converts a String to a {@link File}. Calls {@link File#File(String)}. diff --git a/src/test/java/org/apache/commons/cli/ConverterTests.java b/src/test/java/org/apache/commons/cli/ConverterTests.java index 1f5efad55..fd77ed8bc 100644 --- a/src/test/java/org/apache/commons/cli/ConverterTests.java +++ b/src/test/java/org/apache/commons/cli/ConverterTests.java @@ -18,8 +18,10 @@ Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.commons.cli; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.net.URL; import java.text.DateFormat; @@ -41,6 +43,14 @@ Licensed to the Apache Software Foundation (ASF) under one or more */ public class ConverterTests { + // A class whose static initializer has an observable side effect. + public static class AClassWithAStaticInitializer { + + static { + classInitializerRan = true; + } + } + // A class without a default constructor. public class AClassWithoutADefaultConstructor { @@ -48,6 +58,9 @@ public AClassWithoutADefaultConstructor(final int i) { } } + // Set by the static initializer of AClassWithAStaticInitializer; readable without initializing that class. + private static boolean classInitializerRan; + private static Stream numberTestParameters() { final List lst = new ArrayList<>(); lst.add(Arguments.of("123", Long.valueOf("123"))); @@ -72,6 +85,15 @@ void testClass() throws Exception { assertNotNull(Converter.CLASS.apply(AClassWithoutADefaultConstructor.class.getName())); } + @Test + void testClassDoesNotInitialize() throws Exception { + final Class cls = Converter.CLASS.apply(AClassWithAStaticInitializer.class.getName()); + assertFalse(classInitializerRan); + assertEquals(AClassWithAStaticInitializer.class, cls); + cls.getConstructor().newInstance(); + assertTrue(classInitializerRan); + } + @Test void testDate() throws Exception { assertThrows(java.text.ParseException.class, () -> Converter.DATE.apply("whatever"));