From 1a4dbaebee1b613f1b9db677e56df7d95c8ce458 Mon Sep 17 00:00:00 2001 From: SunWeb3Sec Date: Sun, 19 Apr 2026 13:29:44 +0800 Subject: [PATCH 1/8] Harden ObjectArrayMessage deserialization with SerializationUtil.assertFiltered Adds a SerializationUtil.assertFiltered(in) call at the top of ObjectArrayMessage#readObject, bringing it in line with the defensive pattern already used by ObjectMessage and ParameterizedMessage. This is a defense-in-depth / consistency fix; the serialized wire format is unchanged so instances produced by older versions continue to round-trip. Signed-off-by: SunWeb3Sec --- .../log4j/message/ObjectArrayMessageTest.java | 13 +++++++++++++ .../logging/log4j/message/ObjectArrayMessage.java | 2 ++ .../.2.x.x/harden_message_deserialization.xml | 11 +++++++++++ 3 files changed, 26 insertions(+) create mode 100644 src/changelog/.2.x.x/harden_message_deserialization.xml diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ObjectArrayMessageTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ObjectArrayMessageTest.java index cdfb2c9bd26..8acd13b3d71 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ObjectArrayMessageTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ObjectArrayMessageTest.java @@ -19,6 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import org.apache.logging.log4j.test.junit.SerialUtil; import org.junit.jupiter.api.Test; /** @@ -38,4 +39,16 @@ void testGetParameters() { void testGetThrowable() { assertNull(OBJECT_ARRAY_MESSAGE.getThrowable()); } + + /** + * Round-trips through a filtered stream (see {@link SerialUtil#getObjectInputStream}) + * to verify that {@code readObject}'s new {@code SerializationUtil.assertFiltered} + * check accepts streams that carry a filter. + */ + @Test + void testSerializableRoundTripThroughFilteredStream() { + final ObjectArrayMessage original = new ObjectArrayMessage("A", "B", "C"); + final ObjectArrayMessage restored = SerialUtil.deserialize(SerialUtil.serialize(original)); + assertArrayEquals(original.getParameters(), restored.getParameters()); + } } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectArrayMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectArrayMessage.java index ffd83974b0a..b30b51f647d 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectArrayMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectArrayMessage.java @@ -21,6 +21,7 @@ import java.io.ObjectOutputStream; import java.util.Arrays; import org.apache.logging.log4j.util.Constants; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * Handles messages that contain an Object[]. @@ -117,6 +118,7 @@ public int hashCode() { } private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + SerializationUtil.assertFiltered(in); in.defaultReadObject(); array = (Object[]) in.readObject(); } diff --git a/src/changelog/.2.x.x/harden_message_deserialization.xml b/src/changelog/.2.x.x/harden_message_deserialization.xml new file mode 100644 index 00000000000..c21944d7079 --- /dev/null +++ b/src/changelog/.2.x.x/harden_message_deserialization.xml @@ -0,0 +1,11 @@ + + + + Hardened `ObjectArrayMessage.readObject()` to call `SerializationUtil.assertFiltered()` for consistency with `ObjectMessage` and `ParameterizedMessage`. Defense-in-depth only; wire format is unchanged. + + From 9dea59f80e5cd938170840fb042304c2b0b77536 Mon Sep 17 00:00:00 2001 From: SunWeb3Sec Date: Wed, 29 Apr 2026 07:52:20 +0800 Subject: [PATCH 2/8] Apply SerializationUtil.assertFiltered to all readObject(ObjectInputStream) Extends the previous ObjectArrayMessage hardening to every remaining private void readObject(ObjectInputStream) implementation across log4j-api, log4j-core, log4j-1.2-api, log4j-slf4j-impl, log4j-slf4j2-impl, and log4j-perf-test, per reviewer request. Defense-in-depth only; serialized wire format is unchanged. Signed-off-by: SunWeb3Sec --- log4j-1.2-api/src/main/java/org/apache/log4j/Level.java | 2 ++ .../java/org/apache/logging/log4j/message/FormattedMessage.java | 2 ++ .../java/org/apache/logging/log4j/message/LocalizedMessage.java | 2 ++ .../org/apache/logging/log4j/message/MessageFormatMessage.java | 2 ++ .../java/org/apache/logging/log4j/message/SimpleMessage.java | 2 ++ .../apache/logging/log4j/message/StringFormattedMessage.java | 2 ++ .../org/apache/logging/log4j/message/ThreadDumpMessage.java | 2 ++ .../org/apache/logging/log4j/core/async/RingBufferLogEvent.java | 2 ++ .../java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java | 2 ++ .../org/apache/logging/log4j/core/impl/MutableLogEvent.java | 2 ++ .../logging/log4j/core/util/datetime/FastDatePrinter.java | 2 ++ .../org/apache/logging/log4j/perf/nogc/OpenHashStringMap.java | 2 ++ .../src/main/java/org/apache/logging/slf4j/Log4jLogger.java | 2 ++ .../src/main/java/org/apache/logging/slf4j/Log4jLogger.java | 2 ++ src/changelog/.2.x.x/harden_message_deserialization.xml | 2 +- 15 files changed, 29 insertions(+), 1 deletion(-) diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/Level.java b/log4j-1.2-api/src/main/java/org/apache/log4j/Level.java index 7bc068a3faf..5b63adcd824 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/Level.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/Level.java @@ -25,6 +25,7 @@ import java.io.Serializable; import org.apache.log4j.helpers.OptionConverter; import org.apache.logging.log4j.util.Strings; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * Defines the minimum set of levels recognized by the system, that is @@ -214,6 +215,7 @@ public static Level toLevel(final String sArg, final Level defaultLevel) { * @throws ClassNotFoundException if class not found. */ private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException { + SerializationUtil.assertFiltered(s); s.defaultReadObject(); level = s.readInt(); syslogEquivalent = s.readInt(); diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java index 31c4040251d..fa3a514b374 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java @@ -23,6 +23,7 @@ import java.text.MessageFormat; import java.util.Arrays; import java.util.Locale; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * Handles messages that contain a format String. Dynamically determines if the format conforms to @@ -243,6 +244,7 @@ public int hashCode() { } private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + SerializationUtil.assertFiltered(in); in.defaultReadObject(); formattedMessage = in.readUTF(); messagePattern = in.readUTF(); diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java index c3152224d93..86193938225 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java @@ -23,6 +23,7 @@ import java.util.MissingResourceException; import java.util.ResourceBundle; import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * Provides some level of compatibility with Log4j 1.x and convenience but is not the recommended way to Localize @@ -283,6 +284,7 @@ private void writeObject(final ObjectOutputStream out) throws IOException { } private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + SerializationUtil.assertFiltered(in); in.defaultReadObject(); formattedMessage = in.readUTF(); key = in.readUTF(); diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java index 609bf77f4e8..b767962d2ba 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java @@ -25,6 +25,7 @@ import java.util.Locale; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * Handles messages that consist of a format string conforming to java.text.MessageFormat. @@ -164,6 +165,7 @@ private void writeObject(final ObjectOutputStream out) throws IOException { } private void readObject(final ObjectInputStream in) throws IOException { + SerializationUtil.assertFiltered(in); parameters = null; throwable = null; formattedMessage = in.readUTF(); diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java index f7f1dd1308d..48399021172 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java @@ -21,6 +21,7 @@ import java.io.ObjectOutputStream; import java.util.Objects; import org.apache.logging.log4j.util.StringBuilderFormattable; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * The simplest possible implementation of Message. It just returns the String given as the constructor argument. @@ -152,6 +153,7 @@ private void writeObject(final ObjectOutputStream out) throws IOException { } private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + SerializationUtil.assertFiltered(in); in.defaultReadObject(); charSequence = message; } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java index d1eba763d1c..7e27bf519a1 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java @@ -24,6 +24,7 @@ import java.util.Locale; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * Handles messages that consist of a format string conforming to {@link java.util.Formatter}. @@ -172,6 +173,7 @@ private void writeObject(final ObjectOutputStream out) throws IOException { } private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + SerializationUtil.assertFiltered(in); in.defaultReadObject(); formattedMessage = in.readUTF(); messagePattern = in.readUTF(); diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java index 88ac55fca8c..2473c01dcc0 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java @@ -33,6 +33,7 @@ import org.apache.logging.log4j.util.ServiceLoaderUtil; import org.apache.logging.log4j.util.StringBuilderFormattable; import org.apache.logging.log4j.util.Strings; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * Captures information about all running Threads. @@ -131,6 +132,7 @@ protected Object writeReplace() { } private void readObject(final ObjectInputStream stream) throws InvalidObjectException { + SerializationUtil.assertFiltered(stream); throw new InvalidObjectException("Proxy required"); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java index 71d1b55f5d4..2afb007387c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java @@ -45,6 +45,7 @@ import org.apache.logging.log4j.util.StringBuilders; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.util.Strings; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * When the Disruptor is started, the RingBuffer is populated with event objects. These objects are then re-used during @@ -450,6 +451,7 @@ private Object writeReplace() throws IOException { } private void readObject(final ObjectInputStream stream) throws InvalidObjectException { + SerializationUtil.assertFiltered(stream); throw new InvalidObjectException("Proxy required"); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java index e47fa88049e..471b1cd5bea 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java @@ -48,6 +48,7 @@ import org.apache.logging.log4j.util.StackLocatorUtil; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.util.Strings; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * Implementation of a LogEvent. @@ -993,6 +994,7 @@ public static Log4jLogEvent deserialize(final Serializable event) { } private void readObject(final ObjectInputStream stream) throws InvalidObjectException { + SerializationUtil.assertFiltered(stream); throw new InvalidObjectException("Proxy required"); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java index 151f4d4bfa5..9a99eae624d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java @@ -41,6 +41,7 @@ import org.apache.logging.log4j.util.StringBuilders; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.util.Strings; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * Mutable implementation of the {@code LogEvent} interface. @@ -493,6 +494,7 @@ protected Object writeReplace() { } private void readObject(final ObjectInputStream stream) throws InvalidObjectException { + SerializationUtil.assertFiltered(stream); throw new InvalidObjectException("Proxy required"); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java index 7e6f426f511..20f7184122a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java @@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.logging.log4j.core.util.Throwables; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** *

FastDatePrinter is a fast and thread-safe version of @@ -639,6 +640,7 @@ public String toString() { * @throws ClassNotFoundException if a class cannot be found. */ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + SerializationUtil.assertFiltered(in); in.defaultReadObject(); init(); } diff --git a/log4j-perf-test/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashStringMap.java b/log4j-perf-test/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashStringMap.java index 5e1f3f4fc59..c03e06790c6 100644 --- a/log4j-perf-test/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashStringMap.java +++ b/log4j-perf-test/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashStringMap.java @@ -29,6 +29,7 @@ import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.util.TriConsumer; +import org.apache.logging.log4j.util.internal.SerializationUtil; /** * Open hash map-based implementation of the {@code ReadOnlyStringMap} interface. @@ -690,6 +691,7 @@ public int hashCode() { @SuppressWarnings("unchecked") private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException { + SerializationUtil.assertFiltered(s); s.defaultReadObject(); arraySize = HashCommon.arraySize(size, loadFactor); maxFill = HashCommon.maxFill(arraySize, loadFactor); diff --git a/log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java b/log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java index 2889a31d07d..3fe685cc90b 100644 --- a/log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java +++ b/log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java @@ -26,6 +26,7 @@ import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.spi.ExtendedLogger; +import org.apache.logging.log4j.util.internal.SerializationUtil; import org.slf4j.Marker; import org.slf4j.spi.LocationAwareLogger; @@ -384,6 +385,7 @@ public String getName() { * the de-serialized object. */ private void readObject(final ObjectInputStream aInputStream) throws ClassNotFoundException, IOException { + SerializationUtil.assertFiltered(aInputStream); // always perform the default de-serialization first aInputStream.defaultReadObject(); logger = LogManager.getContext().getLogger(name); diff --git a/log4j-slf4j2-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java b/log4j-slf4j2-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java index 59607e28ed6..a5dd86240a3 100644 --- a/log4j-slf4j2-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java +++ b/log4j-slf4j2-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java @@ -26,6 +26,7 @@ import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.spi.ExtendedLogger; +import org.apache.logging.log4j.util.internal.SerializationUtil; import org.slf4j.Marker; import org.slf4j.spi.LocationAwareLogger; import org.slf4j.spi.LoggingEventBuilder; @@ -384,6 +385,7 @@ public String getName() { * the de-serialized object. */ private void readObject(final ObjectInputStream aInputStream) throws ClassNotFoundException, IOException { + SerializationUtil.assertFiltered(aInputStream); // always perform the default de-serialization first aInputStream.defaultReadObject(); logger = LogManager.getContext().getLogger(name); diff --git a/src/changelog/.2.x.x/harden_message_deserialization.xml b/src/changelog/.2.x.x/harden_message_deserialization.xml index c21944d7079..923a0d4cce1 100644 --- a/src/changelog/.2.x.x/harden_message_deserialization.xml +++ b/src/changelog/.2.x.x/harden_message_deserialization.xml @@ -6,6 +6,6 @@ https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" type="changed"> - Hardened `ObjectArrayMessage.readObject()` to call `SerializationUtil.assertFiltered()` for consistency with `ObjectMessage` and `ParameterizedMessage`. Defense-in-depth only; wire format is unchanged. + Applied `SerializationUtil.assertFiltered()` consistently to every `private void readObject(ObjectInputStream)` across `log4j-api`, `log4j-core`, `log4j-1.2-api`, `log4j-slf4j-impl`, and `log4j-slf4j2-impl`. Defense-in-depth only; wire format is unchanged. From 305b482a66d38902637c0077342604556356b2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Wed, 29 Apr 2026 11:19:18 +0200 Subject: [PATCH 3/8] Improve changelog --- src/changelog/.2.x.x/harden_message_deserialization.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/changelog/.2.x.x/harden_message_deserialization.xml b/src/changelog/.2.x.x/harden_message_deserialization.xml index 923a0d4cce1..e474888373d 100644 --- a/src/changelog/.2.x.x/harden_message_deserialization.xml +++ b/src/changelog/.2.x.x/harden_message_deserialization.xml @@ -5,7 +5,8 @@ https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" type="changed"> + - Applied `SerializationUtil.assertFiltered()` consistently to every `private void readObject(ObjectInputStream)` across `log4j-api`, `log4j-core`, `log4j-1.2-api`, `log4j-slf4j-impl`, and `log4j-slf4j2-impl`. Defense-in-depth only; wire format is unchanged. + Harden `readObject(ObjectInputStream)` method argument checks in serializable API models From d1dd621903b325139a8b08a36c3b21f16fe1dc83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Sat, 2 May 2026 20:11:34 +0200 Subject: [PATCH 4/8] Dummy change to trigger CI --- src/changelog/.2.x.x/harden_message_deserialization.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/changelog/.2.x.x/harden_message_deserialization.xml b/src/changelog/.2.x.x/harden_message_deserialization.xml index e474888373d..3088f8bf556 100644 --- a/src/changelog/.2.x.x/harden_message_deserialization.xml +++ b/src/changelog/.2.x.x/harden_message_deserialization.xml @@ -5,8 +5,8 @@ https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" type="changed"> - - - Harden `readObject(ObjectInputStream)` method argument checks in serializable API models - + + + Harden `readObject(ObjectInputStream)` method argument checks in serializable API models + From 1d34c8d9dee6bfd4833a25951567572daf474a6f Mon Sep 17 00:00:00 2001 From: Sun Date: Sun, 3 May 2026 10:53:25 +0800 Subject: [PATCH 5/8] Route serialization-roundtrip tests through SerialUtil The PR's `assertFiltered(in)` calls reject plain `ObjectInputStream` on Java 8. Update the affected tests to deserialize via `SerialUtil` (or `FilteredObjectInputStream` for the JUnit 4 helper in `log4j-1.2-api`) so they work on both Java 8 and Java 9+. --- .../log4j/util/SerializationTestHelper.java | 11 +++++++++-- .../logging/log4j/test/SerializableMatchers.java | 4 ++-- .../log4j/message/FormattedMessageTest.java | 16 +++------------- .../log4j/message/LocalizedMessageTest.java | 7 +++---- .../message/StringFormattedMessageTest.java | 16 +++------------- 5 files changed, 20 insertions(+), 34 deletions(-) diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java b/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java index e58fa6436e2..00dcb6dc93c 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java @@ -24,9 +24,12 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import org.apache.commons.io.FileUtils; +import org.apache.logging.log4j.util.Constants; +import org.apache.logging.log4j.util.FilteredObjectInputStream; /** * Utiities for serialization tests. @@ -103,11 +106,15 @@ public static void assertStreamEquals( * @throws Exception thrown on IO or deserialization exception. */ public static Object deserializeStream(final String witness) throws Exception { - try (final ObjectInputStream objIs = new ObjectInputStream(new FileInputStream(witness))) { + try (final ObjectInputStream objIs = newObjectInputStream(new FileInputStream(witness))) { return objIs.readObject(); } } + private static ObjectInputStream newObjectInputStream(final InputStream in) throws IOException { + return Constants.JAVA_MAJOR_VERSION == 8 ? new FilteredObjectInputStream(in) : new ObjectInputStream(in); + } + /** * Creates a clone by serializing object and deserializing byte stream. * @@ -123,7 +130,7 @@ public static Object serializeClone(final Object obj) throws IOException, ClassN } final ByteArrayInputStream src = new ByteArrayInputStream(memOut.toByteArray()); - final ObjectInputStream objIs = new ObjectInputStream(src); + final ObjectInputStream objIs = newObjectInputStream(src); return objIs.readObject(); } diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/SerializableMatchers.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/SerializableMatchers.java index 6fc46f6f936..87ed36194f8 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/SerializableMatchers.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/SerializableMatchers.java @@ -20,7 +20,7 @@ import static org.hamcrest.core.IsInstanceOf.any; import java.io.Serializable; -import org.apache.commons.lang3.SerializationUtils; +import org.apache.logging.log4j.test.junit.SerialUtil; import org.hamcrest.FeatureMatcher; import org.hamcrest.Matcher; @@ -35,7 +35,7 @@ public static Matcher serializesRoundTrip(final Matc return new FeatureMatcher(matcher, "serializes round trip", "serializes round trip") { @Override protected T featureValueOf(final T actual) { - return SerializationUtils.roundtrip(actual); + return SerialUtil.deserialize(SerialUtil.serialize(actual)); } }; } diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java index f2a35b2474a..f49bb1d08b2 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java @@ -19,13 +19,9 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.util.Locale; import org.apache.logging.log4j.test.junit.Mutable; +import org.apache.logging.log4j.test.junit.SerialUtil; import org.apache.logging.log4j.util.Constants; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.ResourceAccessMode; @@ -158,15 +154,9 @@ void testSafeAfterGetFormattedMessageIsCalled() { // LOG4J2-763 } @Test - void testSerialization() throws IOException, ClassNotFoundException { + void testSerialization() { final FormattedMessage expected = new FormattedMessage("Msg", "a", "b", "c"); - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (final ObjectOutputStream out = new ObjectOutputStream(baos)) { - out.writeObject(expected); - } - final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - final ObjectInputStream in = new ObjectInputStream(bais); - final FormattedMessage actual = (FormattedMessage) in.readObject(); + final FormattedMessage actual = SerialUtil.deserialize(SerialUtil.serialize(expected)); assertEquals(expected, actual); assertEquals(expected.getFormat(), actual.getFormat()); assertEquals(expected.getFormattedMessage(), actual.getFormattedMessage()); diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java index 832230d53c8..7449acf714e 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java @@ -18,10 +18,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import java.io.Serializable; import java.util.Locale; -import org.apache.commons.lang3.SerializationUtils; import org.apache.logging.log4j.test.junit.Mutable; +import org.apache.logging.log4j.test.junit.SerialUtil; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.ResourceAccessMode; import org.junit.jupiter.api.parallel.ResourceLock; @@ -33,8 +32,8 @@ @ResourceLock(value = Resources.LOCALE, mode = ResourceAccessMode.READ) class LocalizedMessageTest { - private T roundtrip(final T msg) { - return SerializationUtils.roundtrip(msg); + private LocalizedMessage roundtrip(final LocalizedMessage msg) { + return SerialUtil.deserialize(SerialUtil.serialize(msg)); } @Test diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java index 29309b36592..3c3ea2345e4 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java @@ -20,13 +20,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.util.Locale; import org.apache.logging.log4j.test.junit.Mutable; +import org.apache.logging.log4j.test.junit.SerialUtil; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.ResourceAccessMode; import org.junit.jupiter.api.parallel.ResourceLock; @@ -115,15 +111,9 @@ void testSafeAfterGetFormattedMessageIsCalled() { // LOG4J2-763 } @Test - void testSerialization() throws IOException, ClassNotFoundException { + void testSerialization() { final StringFormattedMessage expected = new StringFormattedMessage("Msg", "a", "b", "c"); - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (final ObjectOutputStream out = new ObjectOutputStream(baos)) { - out.writeObject(expected); - } - final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - final ObjectInputStream in = new ObjectInputStream(bais); - final StringFormattedMessage actual = (StringFormattedMessage) in.readObject(); + final StringFormattedMessage actual = SerialUtil.deserialize(SerialUtil.serialize(expected)); assertEquals(expected, actual); assertEquals(expected.getFormat(), actual.getFormat()); assertEquals(expected.getFormattedMessage(), actual.getFormattedMessage()); From cde8d7d6a0bde3801d766f8a1eeba75049e59b4a Mon Sep 17 00:00:00 2001 From: Sun Date: Mon, 18 May 2026 20:27:30 +0800 Subject: [PATCH 6/8] Allow-list log4j 1.2 classes in SerializationTestHelper on Java 8 The Java 8 surefire run (`java8-tests` profile) goes through FilteredObjectInputStream, whose default allow-list covers `org.apache.logging.log4j.` but not the `org.apache.log4j.` 1.2-compatibility namespace. LevelTest#testDeserializeINFO and #testCustomLevelSerialization therefore failed with "Class is not allowed for deserialization" on Java 8. Pass the two 1.2 classes the tests in this module deserialize (`org.apache.log4j.Level`, `LevelTest$CustomLevel`) as the `allowedExtraClasses` set so the hardened `Level#readObject` check still passes. Signed-off-by: SunWeb3Sec --- .../apache/log4j/util/SerializationTestHelper.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java b/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java index 00dcb6dc93c..bd2154574b6 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java @@ -27,6 +27,8 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.util.Arrays; +import java.util.Collection; import org.apache.commons.io.FileUtils; import org.apache.logging.log4j.util.Constants; import org.apache.logging.log4j.util.FilteredObjectInputStream; @@ -111,8 +113,16 @@ public static Object deserializeStream(final String witness) throws Exception { } } + // FilteredObjectInputStream's default allow-list covers `org.apache.logging.log4j.` but not + // the `org.apache.log4j.` 1.2-compatibility namespace, so we have to enumerate the + // 1.2 classes that the tests in this module deserialize on Java 8. + private static final Collection ALLOWED_LOG4J_1_2_CLASSES = + Arrays.asList("org.apache.log4j.Level", "org.apache.log4j.LevelTest$CustomLevel"); + private static ObjectInputStream newObjectInputStream(final InputStream in) throws IOException { - return Constants.JAVA_MAJOR_VERSION == 8 ? new FilteredObjectInputStream(in) : new ObjectInputStream(in); + return Constants.JAVA_MAJOR_VERSION == 8 + ? new FilteredObjectInputStream(in, ALLOWED_LOG4J_1_2_CLASSES) + : new ObjectInputStream(in); } /** From e156c57c02d94b5a22a22123039ad8686ff0a869 Mon Sep 17 00:00:00 2001 From: Sun Date: Tue, 19 May 2026 08:26:41 +0800 Subject: [PATCH 7/8] Inline log4j 1.2 allow-list as a local variable Move the `org.apache.log4j.` allow-list into `newObjectInputStream` so the constant lives in the only place that uses it, per review feedback. The explanatory comment now sits directly above the local variable inside the `JAVA_MAJOR_VERSION == 8` branch. No behavior change. Signed-off-by: SunWeb3Sec --- .../log4j/util/SerializationTestHelper.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java b/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java index bd2154574b6..ab9b497de99 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/util/SerializationTestHelper.java @@ -113,16 +113,16 @@ public static Object deserializeStream(final String witness) throws Exception { } } - // FilteredObjectInputStream's default allow-list covers `org.apache.logging.log4j.` but not - // the `org.apache.log4j.` 1.2-compatibility namespace, so we have to enumerate the - // 1.2 classes that the tests in this module deserialize on Java 8. - private static final Collection ALLOWED_LOG4J_1_2_CLASSES = - Arrays.asList("org.apache.log4j.Level", "org.apache.log4j.LevelTest$CustomLevel"); - private static ObjectInputStream newObjectInputStream(final InputStream in) throws IOException { - return Constants.JAVA_MAJOR_VERSION == 8 - ? new FilteredObjectInputStream(in, ALLOWED_LOG4J_1_2_CLASSES) - : new ObjectInputStream(in); + if (Constants.JAVA_MAJOR_VERSION == 8) { + // FilteredObjectInputStream's default allow-list covers `org.apache.logging.log4j.` but + // not the `org.apache.log4j.` 1.2-compatibility namespace, so we have to enumerate the + // 1.2 classes that the tests in this module deserialize on Java 8. + final Collection allowedLog4j12Classes = + Arrays.asList("org.apache.log4j.Level", "org.apache.log4j.LevelTest$CustomLevel"); + return new FilteredObjectInputStream(in, allowedLog4j12Classes); + } + return new ObjectInputStream(in); } /** From a2434290aef04054ca4f9fc483e4f279b21775ba Mon Sep 17 00:00:00 2001 From: Sun Date: Tue, 19 May 2026 10:05:28 +0800 Subject: [PATCH 8/8] Allow-list slf4j Log4jLogger and export util.internal for OSGi Fixes two regressions surfaced when running `./mvnw verify` locally: * `org.apache.logging.slf4j.Log4jLogger` lives outside the `org.apache.logging.log4j.` namespace covered by `FilteredObjectInputStream`'s default allow-list, so the Java 8 surefire run of `SerializeTest` rejected it. Extend `SerialUtil` and `SerializableMatchers` with overloads that accept an additional allow-list and pass `Log4jLogger` through from the test. * Adding `import org.apache.logging.log4j.util.internal.SerializationUtil` to log4j-core created a cross-bundle OSGi `Import-Package` requirement on an unexported package, breaking `log4j-osgi-test`. Mirror the `core.util.internal.instant` package and ship a `package-info.java` that exports `util.internal` with javadoc warning external users away. --- .../log4j/test/SerializableMatchers.java | 21 ++++++++- .../logging/log4j/test/junit/SerialUtil.java | 44 +++++++++++++++++-- .../log4j/test/junit/package-info.java | 2 +- .../logging/log4j/test/package-info.java | 2 +- .../log4j/util/internal/package-info.java | 33 ++++++++++++++ .../apache/logging/slf4j/SerializeTest.java | 6 ++- .../apache/logging/slf4j/SerializeTest.java | 6 ++- 7 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 log4j-api/src/main/java/org/apache/logging/log4j/util/internal/package-info.java diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/SerializableMatchers.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/SerializableMatchers.java index 87ed36194f8..a5af542e862 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/SerializableMatchers.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/SerializableMatchers.java @@ -20,6 +20,8 @@ import static org.hamcrest.core.IsInstanceOf.any; import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; import org.apache.logging.log4j.test.junit.SerialUtil; import org.hamcrest.FeatureMatcher; import org.hamcrest.Matcher; @@ -32,10 +34,19 @@ public final class SerializableMatchers { public static Matcher serializesRoundTrip(final Matcher matcher) { + return serializesRoundTrip(matcher, Collections.emptySet()); + } + + /** + * Same as {@link #serializesRoundTrip(Matcher)} but extends the default deserialization + * allow-list on Java 8 (see {@link SerialUtil#deserialize(byte[], Collection)}). + */ + public static Matcher serializesRoundTrip( + final Matcher matcher, final Collection allowedExtraClasses) { return new FeatureMatcher(matcher, "serializes round trip", "serializes round trip") { @Override protected T featureValueOf(final T actual) { - return SerialUtil.deserialize(SerialUtil.serialize(actual)); + return SerialUtil.deserialize(SerialUtil.serialize(actual), allowedExtraClasses); } }; } @@ -52,5 +63,13 @@ public static Matcher serializesRoundTrip() { return serializesRoundTrip(any(Serializable.class)); } + /** + * Same as {@link #serializesRoundTrip()} but extends the default deserialization allow-list on + * Java 8 (see {@link SerialUtil#deserialize(byte[], Collection)}). + */ + public static Matcher serializesRoundTrip(final Collection allowedExtraClasses) { + return serializesRoundTrip(any(Serializable.class), allowedExtraClasses); + } + private SerializableMatchers() {} } diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/SerialUtil.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/SerialUtil.java index 707fee87d3e..34600f0c831 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/SerialUtil.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/SerialUtil.java @@ -24,6 +24,8 @@ import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; import org.apache.logging.log4j.test.internal.annotation.SuppressFBWarnings; import org.apache.logging.log4j.util.Constants; import org.apache.logging.log4j.util.FilteredObjectInputStream; @@ -68,11 +70,25 @@ public static byte[] serialize(final Serializable... objs) { * @param data byte array representing the serialized object * @return the deserialized object */ - @SuppressWarnings("unchecked") @SuppressFBWarnings("OBJECT_DESERIALIZATION") public static T deserialize(final byte[] data) { + return deserialize(data, Collections.emptySet()); + } + + /** + * Deserialize an object from the specified byte array using a {@link FilteredObjectInputStream} + * extended with the supplied allow-list (Java 8 only — Java 9+ uses the JVM's serialization + * filter, so the allow-list is ignored). + * @param data byte array representing the serialized object + * @param allowedExtraClasses fully-qualified class names to add to {@link + * FilteredObjectInputStream}'s default allow-list on Java 8 + * @return the deserialized object + */ + @SuppressWarnings("unchecked") + @SuppressFBWarnings("OBJECT_DESERIALIZATION") + public static T deserialize(final byte[] data, final Collection allowedExtraClasses) { try { - final ObjectInputStream ois = getObjectInputStream(data); + final ObjectInputStream ois = getObjectInputStream(data, allowedExtraClasses); return (T) ois.readObject(); } catch (final Exception ex) { throw new IllegalStateException("Could not deserialize", ex); @@ -86,8 +102,18 @@ public static T deserialize(final byte[] data) { */ @SuppressFBWarnings("OBJECT_DESERIALIZATION") public static ObjectInputStream getObjectInputStream(final byte[] data) throws IOException { + return getObjectInputStream(data, Collections.emptySet()); + } + + /** + * Creates an {@link ObjectInputStream} adapted to the current Java version, extended with the + * supplied allow-list on Java 8. + */ + @SuppressFBWarnings("OBJECT_DESERIALIZATION") + public static ObjectInputStream getObjectInputStream( + final byte[] data, final Collection allowedExtraClasses) throws IOException { final ByteArrayInputStream bas = new ByteArrayInputStream(data); - return getObjectInputStream(bas); + return getObjectInputStream(bas, allowedExtraClasses); } /** @@ -97,8 +123,18 @@ public static ObjectInputStream getObjectInputStream(final byte[] data) throws I */ @SuppressFBWarnings("OBJECT_DESERIALIZATION") public static ObjectInputStream getObjectInputStream(final InputStream stream) throws IOException { + return getObjectInputStream(stream, Collections.emptySet()); + } + + /** + * Creates an {@link ObjectInputStream} adapted to the current Java version, extended with the + * supplied allow-list on Java 8. + */ + @SuppressFBWarnings("OBJECT_DESERIALIZATION") + public static ObjectInputStream getObjectInputStream( + final InputStream stream, final Collection allowedExtraClasses) throws IOException { return Constants.JAVA_MAJOR_VERSION == 8 - ? new FilteredObjectInputStream(stream) + ? new FilteredObjectInputStream(stream, allowedExtraClasses) : new ObjectInputStream(stream); } } diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/package-info.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/package-info.java index f048e320fe0..ca324bf73a2 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/package-info.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/package-info.java @@ -15,7 +15,7 @@ * limitations under the license. */ @Export -@Version("2.25.3") +@Version("2.26.0") package org.apache.logging.log4j.test.junit; import org.osgi.annotation.bundle.Export; diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/package-info.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/package-info.java index a867f216a55..36413766c5a 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/package-info.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/package-info.java @@ -15,7 +15,7 @@ * limitations under the license. */ @Export -@Version("2.25.3") +@Version("2.26.0") package org.apache.logging.log4j.test; import org.osgi.annotation.bundle.Export; diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/internal/package-info.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/internal/package-info.java new file mode 100644 index 00000000000..1d176839216 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/internal/package-info.java @@ -0,0 +1,33 @@ +/* + * 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 + * + * http://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. + */ +/** + * Utilities for safely serializing and deserializing Log4j objects. + *

Internal usage only!

+ *

+ * This package is intended only for internal Log4j usage. + * Log4j users should not use this package! + * This package is not subject to any backward compatibility concerns. + *

+ * + * @since 2.26.0 + */ +@Export +@Version("2.26.0") +package org.apache.logging.log4j.util.internal; + +import org.osgi.annotation.bundle.Export; +import org.osgi.annotation.versioning.Version; diff --git a/log4j-slf4j-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.java b/log4j-slf4j-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.java index d8633a1863b..f16c5975799 100644 --- a/log4j-slf4j-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.java +++ b/log4j-slf4j-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.java @@ -20,6 +20,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import java.io.Serializable; +import java.util.Collections; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.junit.jupiter.api.Test; import org.slf4j.Logger; @@ -35,6 +36,9 @@ class SerializeTest { @Test void testLogger() { - assertThat((Serializable) logger, serializesRoundTrip()); + // `Log4jLogger` lives outside the `org.apache.logging.log4j.` namespace covered by + // FilteredObjectInputStream's default allow-list, so we have to enumerate it explicitly + // for the Java 8 surefire run that goes through FilteredObjectInputStream. + assertThat((Serializable) logger, serializesRoundTrip(Collections.singleton(Log4jLogger.class.getName()))); } } diff --git a/log4j-slf4j2-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.java b/log4j-slf4j2-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.java index cdea35ada64..1c400038e05 100644 --- a/log4j-slf4j2-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.java +++ b/log4j-slf4j2-impl/src/test/java/org/apache/logging/slf4j/SerializeTest.java @@ -20,6 +20,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import java.io.Serializable; +import java.util.Collections; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.junit.jupiter.api.Test; import org.slf4j.Logger; @@ -35,6 +36,9 @@ class SerializeTest { @Test void testLogger() { - assertThat((Serializable) logger, serializesRoundTrip()); + // `Log4jLogger` lives outside the `org.apache.logging.log4j.` namespace covered by + // FilteredObjectInputStream's default allow-list, so we have to enumerate it explicitly + // for the Java 8 surefire run that goes through FilteredObjectInputStream. + assertThat((Serializable) logger, serializesRoundTrip(Collections.singleton(Log4jLogger.class.getName()))); } }