From a001c19cfd1c655bf5cdbc3066538410ee1cea06 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Fri, 19 Jul 2024 08:26:07 -0400 Subject: [PATCH 1/3] Add testLang1641() --- .../commons/lang3/time/FastDateFormatTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/org/apache/commons/lang3/time/FastDateFormatTest.java b/src/test/java/org/apache/commons/lang3/time/FastDateFormatTest.java index aa13e28453b..3007c515ef6 100644 --- a/src/test/java/org/apache/commons/lang3/time/FastDateFormatTest.java +++ b/src/test/java/org/apache/commons/lang3/time/FastDateFormatTest.java @@ -47,6 +47,9 @@ * Unit tests {@link org.apache.commons.lang3.time.FastDateFormat}. */ public class FastDateFormatTest extends AbstractLangTest { + + private static final String ISO_8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZZ"; + private static final int NTHREADS = 10; private static final int NROUNDS = 10000; @@ -269,6 +272,20 @@ public void testLANG_954() { FastDateFormat.getInstance(pattern); } + @Test + public void testLang1641() { + assertSame(FastDateFormat.getInstance(ISO_8601_DATE_FORMAT), FastDateFormat.getInstance(ISO_8601_DATE_FORMAT)); + // commons-lang's GMT TimeZone + assertSame(FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, FastTimeZone.getGmtTimeZone()), + FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, FastTimeZone.getGmtTimeZone())); + // default TimeZone + assertSame(FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, TimeZone.getDefault()), + FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, TimeZone.getDefault())); + // TimeZones that are identical in every way except ID + assertNotSame(FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, TimeZone.getTimeZone("Australia/Broken_Hill")), + FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, TimeZone.getTimeZone("Australia/Yancowinna"))); + } + @Test public void testParseSync() throws InterruptedException { final String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS"; From abb0ca487cefc6d6df66600769655b3527a7f63e Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Fri, 19 Jul 2024 08:27:03 -0400 Subject: [PATCH 2/3] Rename some test methods --- .../lang3/time/FastDateFormatTest.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/test/java/org/apache/commons/lang3/time/FastDateFormatTest.java b/src/test/java/org/apache/commons/lang3/time/FastDateFormatTest.java index 3007c515ef6..698dd1ade4c 100644 --- a/src/test/java/org/apache/commons/lang3/time/FastDateFormatTest.java +++ b/src/test/java/org/apache/commons/lang3/time/FastDateFormatTest.java @@ -248,7 +248,7 @@ public void testDateDefaults() { } @Test - public void testLANG_1152() { + public void testLang1152() { final TimeZone utc = FastTimeZone.getGmtTimeZone(); final Date date = new Date(Long.MAX_VALUE); @@ -259,19 +259,10 @@ public void testLANG_1152() { assertEquals("17/08/292278994", dateAsString); } @Test - public void testLANG_1267() { + public void testLang1267() { FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); } - /** - * According to LANG-954 (https://issues.apache.org/jira/browse/LANG-954) this is broken in Android 2.1. - */ - @Test - public void testLANG_954() { - final String pattern = "yyyy-MM-dd'T'"; - FastDateFormat.getInstance(pattern); - } - @Test public void testLang1641() { assertSame(FastDateFormat.getInstance(ISO_8601_DATE_FORMAT), FastDateFormat.getInstance(ISO_8601_DATE_FORMAT)); @@ -286,6 +277,15 @@ public void testLang1641() { FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, TimeZone.getTimeZone("Australia/Yancowinna"))); } + /** + * According to LANG-954 (https://issues.apache.org/jira/browse/LANG-954) this is broken in Android 2.1. + */ + @Test + public void testLang954() { + final String pattern = "yyyy-MM-dd'T'"; + FastDateFormat.getInstance(pattern); + } + @Test public void testParseSync() throws InterruptedException { final String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS"; From d3bca794853626d18692517455c6a0ed31f7f0ac Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 25 Jan 2026 13:22:14 +0000 Subject: [PATCH 3/3] [LANG-1452] RecursiveToStringStyle and MultilineRecursiveToStringStyle shouldn't recurse into a java.math.BigDecimal - We already don't recurse into a Decimal and other boxed primitive. - Don't recurse into Number subclasses. - Don't recurse into AtomicBoolean. --- .../lang3/builder/RecursiveToStringStyle.java | 34 ++++++++---- .../builder/RecursiveToStringStyleTest.java | 55 ++++++++++++++++++- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/builder/RecursiveToStringStyle.java b/src/main/java/org/apache/commons/lang3/builder/RecursiveToStringStyle.java index 15968eb124b..95695079a82 100644 --- a/src/main/java/org/apache/commons/lang3/builder/RecursiveToStringStyle.java +++ b/src/main/java/org/apache/commons/lang3/builder/RecursiveToStringStyle.java @@ -17,8 +17,10 @@ package org.apache.commons.lang3.builder; import java.util.Collection; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.mutable.MutableBoolean; /** * Works with {@link ToStringBuilder} to create a "deep" {@code toString}. @@ -66,16 +68,29 @@ public RecursiveToStringStyle() { } /** - * Returns whether or not to recursively format the given {@link Class}. - * By default, this method always returns {@code true}, but may be overwritten by - * subclasses to filter specific classes. + * Tests whether or not to recursively format the given {@link Class}. + *

+ * By default, this method always filters out the following: + *

+ *
    + *
  • Boxed primitives, see {@link ClassUtils#isPrimitiveWrapper(Class)} + *
  • {@link String}
  • + *
  • {@link Number} subclasses
  • + *
  • {@link AtomicBoolean}
  • + *
  • {@link MutableBoolean}
  • + *
* - * @param clazz - * The class to test. - * @return Whether or not to recursively format the given {@link Class}. + * @param clazz The class to test. + * @return Whether or not to recursively format instances of the given {@link Class}. */ protected boolean accept(final Class clazz) { - return true; + // @formatter:off + return !ClassUtils.isPrimitiveWrapper(clazz) && + !String.class.equals(clazz) && + !Number.class.isAssignableFrom(clazz) && + !AtomicBoolean.class.equals(clazz) && + !MutableBoolean.class.equals(clazz); + // @formatter:on } @Override @@ -87,10 +102,7 @@ protected void appendDetail(final StringBuffer buffer, final String fieldName, f @Override public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { - final Class clazz = value.getClass(); - if (!ClassUtils.isPrimitiveWrapper(clazz) && - !String.class.equals(clazz) && - accept(clazz)) { + if (value != null && accept(value.getClass())) { buffer.append(ReflectionToStringBuilder.toString(value, this)); } else { super.appendDetail(buffer, fieldName, value); diff --git a/src/test/java/org/apache/commons/lang3/builder/RecursiveToStringStyleTest.java b/src/test/java/org/apache/commons/lang3/builder/RecursiveToStringStyleTest.java index 2f73484fabe..e8618e84d53 100644 --- a/src/test/java/org/apache/commons/lang3/builder/RecursiveToStringStyleTest.java +++ b/src/test/java/org/apache/commons/lang3/builder/RecursiveToStringStyleTest.java @@ -18,10 +18,22 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.lang3.AbstractLangTest; +import org.apache.commons.lang3.mutable.MutableBoolean; +import org.apache.commons.lang3.mutable.MutableByte; +import org.apache.commons.lang3.mutable.MutableDouble; +import org.apache.commons.lang3.mutable.MutableFloat; +import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.lang3.mutable.MutableLong; +import org.apache.commons.lang3.mutable.MutableShort; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -85,6 +97,30 @@ void testAppendSuper() { assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper(null).append("a", "hello").toString()); } + @Test + void testAtomicsArray() { + assertEquals(baseStr + "[{,5,{3,6}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new AtomicLong[] { new AtomicLong(3), new AtomicLong(6) } }).toString()); + assertEquals(baseStr + "[{,5,{3,6}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new AtomicInteger[] { new AtomicInteger(3), new AtomicInteger(6) } }).toString()); + assertEquals(baseStr + "[{,5,{true,false}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new AtomicBoolean[] { new AtomicBoolean(true), new AtomicBoolean(false) } }).toString()); + } + + @Test + void testBigDecimal() { + assertEquals(baseStr + "[{,5,{3,6}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new BigDecimal[] { BigDecimal.valueOf(3), BigDecimal.valueOf(6) } }).toString()); + assertEquals(baseStr + "[{,5,{3.0,6.0}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new BigDecimal[] { BigDecimal.valueOf(3.0), BigDecimal.valueOf(6.0) } }).toString()); + } + + @Test + void testBigInteger() { + assertEquals(baseStr + "[{,5,{3,6}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new BigInteger[] { BigInteger.valueOf(3), BigInteger.valueOf(6) } }).toString()); + } + @Test void testBlank() { assertEquals(baseStr + "[]", new ToStringBuilder(base).toString()); @@ -117,6 +153,24 @@ void testLongArrayArray() { assertEquals(baseStr + "[]", new ToStringBuilder(base).append((Object) array).toString()); } + @Test + void testMutableWrapperArray() { + assertEquals(baseStr + "[{,5,{3,6}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new MutableLong[] { new MutableLong(3), new MutableLong(6) } }).toString()); + assertEquals(baseStr + "[{,5,{3,6}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new MutableInt[] { new MutableInt(3), new MutableInt(6) } }).toString()); + assertEquals(baseStr + "[{,5,{3,6}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new MutableShort[] { new MutableShort(3), new MutableShort(6) } }).toString()); + assertEquals(baseStr + "[{,5,{3,6}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new MutableByte[] { new MutableByte((byte) 3), new MutableByte((byte) 6) } }).toString()); + assertEquals(baseStr + "[{,5,{3.0,6.0}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new MutableFloat[] { new MutableFloat(3f), new MutableFloat(6f) } }).toString()); + assertEquals(baseStr + "[{,5,{3.0,6.0}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new MutableDouble[] { new MutableDouble(3d), new MutableDouble(6d) } }).toString()); + assertEquals(baseStr + "[{,5,{true,false}}]", + new ToStringBuilder(base).append(new Object[] { null, base, new MutableBoolean[] { new MutableBoolean(true), new MutableBoolean(false) } }).toString()); + } + @Test void testObject() { final Integer i3 = Integer.valueOf(3); @@ -174,5 +228,4 @@ void testPrimitiveWrapperArray() { assertEquals(baseStr + "[{,5,{true,false}}]", new ToStringBuilder(base).append(new Object[] { null, base, new Boolean[] { true, false } }).toString()); } - }