You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ra...@apache.org on 2026/10/02 04:08:55 UTC
(logging-log4j2) 04/07: Serialize the `LogEvent` message without `MarshalledObject` (#4271)
This is an automated email from the ASF dual-hosted git repository.
ramanathan1504 pushed a commit to branch port/serialization-to-2.26.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit ea610fe54ee71f112b73f9811569111c437dbff0
Author: Piotr P. Karwasz <pk...@apache.org>
AuthorDate: Wed Sep 30 23:07:05 2026 +0200
Serialize the `LogEvent` message without `MarshalledObject` (#4271)
* Serialize the LogEvent message delegate through the filtered wrapper
`Log4jLogEvent.LogEventProxy` used `java.rmi.MarshalledObject` to
transport its `Message` delegate. `MarshalledObject.get()` deserializes
its embedded bytes on a private, unfiltered `ObjectInputStream`, so the
delegate escaped the deserialization allow-list entirely.
The message is now written with the same
`SerializationUtil.writeWrappedObject`/`readWrappedObject` mechanism
used by `ObjectMessage`, which re-applies the allow-list to the nested
stream, and `java.rmi.MarshalledObject` is removed from the allow-list.
Compatibility: log events serialized by Log4j 2.8.2-2.25.x are rejected
by newer readers, since `MarshalledObject` no longer passes the filter.
Events serialized by this version remain readable by older versions,
with the message downgraded to a `SimpleMessage`. The serialized-event
fixture in `Log4jLogEventTest` is regenerated accordingly, and the
stale, unused `serializedEvent.dat` resource is removed
(`SerializedLayoutTest` always rewrites it before reading).
Part of the hardening series from #4168.
Assisted-By: Claude Fable 5 <no...@anthropic.com>
* Remove `MarshalledObject` from the documented allowlist and test filter
Assisted-By: Claude Opus 5.5 <no...@anthropic.com>
* Fall back to a serializable value for unserializable objects
`SerializationUtil.writeWrappedObject` now takes a fallback, which is
written instead of the object if it is not `Serializable` or its
serialization fails. Failed serializations are logged as warnings.
- `LogEventProxy` writes a `SimpleMessage` with the formatted message,
as it did when the message was wrapped in a `MarshalledObject`.
- `ObjectMessage` writes its formatted message.
- `ParameterizedMessage` and `SortedArrayStringMap` write the string
representation of the value. For `SortedArrayStringMap`, this replaces
the `null` previously written for non-serializable values.
`UnserializableMessage` in `log4j-api-test` provides a reusable example
of a `Serializable` object that cannot be serialized.
Assisted-By: Claude Opus 5.5 <no...@anthropic.com>
* Note the serialization format change in the changelog
Assisted-By: Claude Opus 5.5 <no...@anthropic.com>
* Throw on nested objects rejected during deserialization
`readWrappedObject` returned `null` for any nested object that could
not be read, including classes rejected by the filter of the stream.
The nested stream now behaves like the outer one: `IOException`s,
including filter rejections, are thrown. Only classes that are not
available on the reader, `ClassNotFoundException` and `LinkageError`,
are still replaced with `null`.
Adds tests with a nested `java.net.URI`, which is not on the allowlist,
in `ObjectMessage` and in a `Log4jLogEvent`.
Assisted-By: Claude Opus 5.5 <no...@anthropic.com>
* Test deserialization of a message with an unknown class
A message whose class is allowed by the deserialization filter, but not
available to the reader, degrades to a `SimpleMessage` with the
formatted message.
The Base64 fixtures in `Log4jLogEventTest` are folded into multiple
lines.
Assisted-By: Claude Opus 5.5 <no...@anthropic.com>
(cherry picked from commit 9cb17cf7b77e85760dba50aa4ee094dd526f8856)
---
.../logging/log4j/message/ObjectMessageTest.java | 13 ++
.../log4j/message/ParameterizedMessageTest.java | 2 +
.../logging/log4j/test/UnserializableMessage.java | 66 ++++++
.../log4j/util/SortedArrayStringMapTest.java | 9 +-
.../log4j/util/internal/SerializationUtilTest.java | 6 +-
.../logging/log4j/message/ObjectMessage.java | 4 +-
.../log4j/message/ParameterizedMessage.java | 4 +-
.../log4j/util/FilteredObjectInputStream.java | 1 -
.../logging/log4j/util/SortedArrayStringMap.java | 5 +-
.../log4j/util/internal/SerializationUtil.java | 47 +++-
log4j-core-test/pom.xml | 2 +-
.../logging/log4j/core/impl/Log4jLogEventTest.java | 248 ++++++++++++++++++++-
.../log4j/core/impl/UnserializableMessage.java | 66 ++++++
.../src/test/resources/serializedEvent.dat | Bin 2251 -> 0 bytes
.../logging/log4j/core/impl/Log4jLogEvent.java | 32 +--
...shalled_object_from_log_event_serialization.xml | 12 +
.../4271_throw_on_rejected_nested_objects.xml | 12 +
17 files changed, 482 insertions(+), 47 deletions(-)
diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
index 2bdc1d7a68..7678fd05a4 100644
--- a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
@@ -17,10 +17,14 @@
package org.apache.logging.log4j.message;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import java.io.ObjectStreamException;
import java.math.BigDecimal;
+import java.net.URI;
import java.util.stream.Stream;
+import org.apache.logging.log4j.test.UnserializableMessage;
import org.apache.logging.log4j.test.junit.Mutable;
import org.apache.logging.log4j.test.junit.SerialUtil;
import org.junit.jupiter.api.Test;
@@ -95,6 +99,7 @@ class ObjectMessageTest {
return Stream.of(
"World",
new NonSerializable(),
+ new UnserializableMessage("World"),
new BigDecimal("123.456"),
// LOG4J2-3680
new RuntimeException(),
@@ -109,4 +114,12 @@ class ObjectMessageTest {
assertThat(actual).isInstanceOf(ObjectMessage.class);
assertThat(actual).isEqualTo(expected);
}
+
+ @Test
+ void testDeserializationOfClassNotOnAllowlist() {
+ final byte[] data = SerialUtil.serialize(new ObjectMessage(URI.create("https://logging.apache.org/")));
+ assertThatThrownBy(() -> SerialUtil.deserialize(data))
+ .hasCauseInstanceOf(ObjectStreamException.class)
+ .hasStackTraceContaining("java.net.URI");
+ }
}
diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
index 4bd5df91be..6ebe97d30c 100644
--- a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
@@ -26,6 +26,7 @@ import java.util.stream.Stream;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.status.StatusData;
import org.apache.logging.log4j.test.ListStatusListener;
+import org.apache.logging.log4j.test.UnserializableMessage;
import org.apache.logging.log4j.test.junit.Mutable;
import org.apache.logging.log4j.test.junit.SerialUtil;
import org.apache.logging.log4j.test.junit.UsingStatusListener;
@@ -170,6 +171,7 @@ class ParameterizedMessageTest {
return Stream.of(
"World",
new NonSerializable(),
+ new UnserializableMessage("World"),
new BigDecimal("123.456"),
// LOG4J2-3680
new RuntimeException(),
diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/test/UnserializableMessage.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/test/UnserializableMessage.java
new file mode 100644
index 0000000000..c861a72936
--- /dev/null
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/test/UnserializableMessage.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.test;
+
+import org.apache.logging.log4j.message.Message;
+
+/**
+ * A {@link Message} that cannot be serialized, although it implements {@link java.io.Serializable}.
+ * <p>
+ * One of its fields is not serializable, so serializing it throws {@link java.io.NotSerializableException}.
+ * It can be used to test that serializable Log4j classes, which contain arbitrary messages or objects,
+ * fall back to a serializable representation, like the formatted message.
+ * </p>
+ */
+public final class UnserializableMessage implements Message {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String text;
+
+ @SuppressWarnings({"serial", "unused"})
+ private final Object unserializableField = new Object();
+
+ public UnserializableMessage(final String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String getFormattedMessage() {
+ return text;
+ }
+
+ @Override
+ public String getFormat() {
+ return text;
+ }
+
+ @Override
+ public Object[] getParameters() {
+ return null;
+ }
+
+ @Override
+ public Throwable getThrowable() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+}
diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/SortedArrayStringMapTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/SortedArrayStringMapTest.java
index e5709a6a54..008c379004 100644
--- a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/SortedArrayStringMapTest.java
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/SortedArrayStringMapTest.java
@@ -107,7 +107,12 @@ class SortedArrayStringMapTest {
final SortedArrayStringMap original = new SortedArrayStringMap();
original.putValue("a", "avalue");
original.putValue("B", "Bvalue");
- original.putValue("unserializable", new Object());
+ original.putValue("unserializable", new Object() {
+ @Override
+ public String toString() {
+ return "unserializable value";
+ }
+ });
final byte[] binary = serialize(original);
final SortedArrayStringMap copy = deserialize(binary);
@@ -115,7 +120,7 @@ class SortedArrayStringMapTest {
final SortedArrayStringMap expected = new SortedArrayStringMap();
expected.putValue("a", "avalue");
expected.putValue("B", "Bvalue");
- expected.putValue("unserializable", null);
+ expected.putValue("unserializable", "unserializable value");
assertEquals(expected, copy);
}
diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/internal/SerializationUtilTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/internal/SerializationUtilTest.java
index 47ae134c6f..58861edd10 100644
--- a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/internal/SerializationUtilTest.java
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/internal/SerializationUtilTest.java
@@ -17,10 +17,12 @@
package org.apache.logging.log4j.util.internal;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
@@ -85,7 +87,7 @@ class SerializationUtilTest {
final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data));
setObjectInputFilter(in, "!" + Payload.class.getName());
- assertThat(readParameter(in)).isNull();
+ assertThatThrownBy(() -> readParameter(in)).isInstanceOf(InvalidClassException.class);
}
@Test
@@ -97,7 +99,7 @@ class SerializationUtilTest {
final ObjectInputStream in = new FilteredObjectInputStream(new ByteArrayInputStream(data));
setObjectInputFilter(in, "!" + Payload.class.getName());
- assertThat(readParameter(in)).isNull();
+ assertThatThrownBy(() -> readParameter(in)).isInstanceOf(InvalidClassException.class);
}
private static byte[] serialize(final Serializable obj) throws IOException {
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
index d102e42423..4795645834 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
@@ -19,7 +19,6 @@ package org.apache.logging.log4j.message;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.Serializable;
import org.apache.logging.log4j.util.StringBuilderFormattable;
import org.apache.logging.log4j.util.StringBuilders;
import org.apache.logging.log4j.util.internal.SerializationUtil;
@@ -125,8 +124,7 @@ public class ObjectMessage implements Message, StringBuilderFormattable {
private void writeObject(final ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
- SerializationUtil.writeWrappedObject(
- obj instanceof Serializable ? (Serializable) obj : String.valueOf(obj), out);
+ SerializationUtil.writeWrappedObject(obj, this::getFormattedMessage, out);
}
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java
index 68a75d5874..c054b4d376 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java
@@ -23,7 +23,6 @@ import com.google.errorprone.annotations.InlineMe;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.Serializable;
import java.util.Arrays;
import java.util.Objects;
import org.apache.logging.log4j.message.ParameterFormatter.MessagePatternAnalysis;
@@ -376,8 +375,7 @@ public class ParameterizedMessage implements Message, StringBuilderFormattable {
out.defaultWriteObject();
out.writeInt(args.length);
for (final Object arg : args) {
- final Serializable serializableArg = arg instanceof Serializable ? (Serializable) arg : String.valueOf(arg);
- SerializationUtil.writeWrappedObject(serializableArg, out);
+ SerializationUtil.writeWrappedObject(arg, () -> String.valueOf(arg), out);
}
}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/FilteredObjectInputStream.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/FilteredObjectInputStream.java
index c1a35fae1d..bf5e0f1be3 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/FilteredObjectInputStream.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/FilteredObjectInputStream.java
@@ -35,7 +35,6 @@ import org.apache.logging.log4j.util.internal.SerializationUtil;
* <ul>
* <li>primitive types,</li>
* <li>{@code java.math.BigDecimal} and {@code java.math.BigInteger},</li>
- * <li>{@code java.rmi.MarshalledObject},</li>
* <li>all classes whose name starts with {@code java.lang.}, {@code java.time.}, {@code java.util.}
* or {@code org.apache.logging.log4j.}.</li>
* </ul>
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/SortedArrayStringMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/SortedArrayStringMap.java
index 9098a47588..97bc365765 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/SortedArrayStringMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/SortedArrayStringMap.java
@@ -18,7 +18,6 @@ package org.apache.logging.log4j.util;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.Serializable;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
@@ -470,8 +469,8 @@ public class SortedArrayStringMap implements IndexedStringMap {
if (size > 0) {
for (int i = 0; i < size; i++) {
s.writeObject(keys[i]);
- SerializationUtil.writeWrappedObject(
- (values[i] instanceof Serializable) ? (Serializable) values[i] : null, s);
+ final Object value = values[i];
+ SerializationUtil.writeWrappedObject(value, () -> String.valueOf(value), s);
}
}
}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/internal/SerializationUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/internal/SerializationUtil.java
index ba95c34b38..5251446cb4 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/internal/SerializationUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/internal/SerializationUtil.java
@@ -27,6 +27,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
+import java.util.function.Supplier;
import org.apache.logging.log4j.internal.annotation.SuppressFBWarnings;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.FilteredObjectInputStream;
@@ -56,8 +57,6 @@ public final class SerializationUtil {
public static final List<String> REQUIRED_JAVA_CLASSES = Arrays.asList(
"java.math.BigDecimal",
"java.math.BigInteger",
- // for Message delegate
- "java.rmi.MarshalledObject",
// all primitives
"boolean",
"byte",
@@ -71,15 +70,49 @@ public final class SerializationUtil {
public static final List<String> REQUIRED_JAVA_PACKAGES =
Arrays.asList("java.lang.", "java.time.", "java.util.", "org.apache.logging.log4j.");
- public static void writeWrappedObject(final Serializable obj, final ObjectOutputStream out) throws IOException {
+ /**
+ * Serializes an object into a byte array and writes the array to the output stream.
+ * <p>
+ * If the object is neither {@code null} nor {@link Serializable}, or its serialization fails, the value returned by
+ * {@code fallback} is written instead. Failed serializations are logged as warnings.
+ * </p>
+ *
+ * @param obj The object to write.
+ * @param fallback Provides the value to write if {@code obj} cannot be serialized.
+ * @param out The output stream.
+ */
+ public static void writeWrappedObject(
+ final Object obj, final Supplier<Serializable> fallback, final ObjectOutputStream out) throws IOException {
+ byte[] data = null;
+ if (obj == null || obj instanceof Serializable) {
+ try {
+ data = toByteArray((Serializable) obj);
+ } catch (final IOException | RuntimeException e) {
+ StatusLogger.getLogger()
+ .warn("Unable to serialize an object of type {}, using a fallback value.", obj.getClass(), e);
+ }
+ }
+ out.writeObject(data != null ? data : toByteArray(fallback.get()));
+ }
+
+ private static byte[] toByteArray(final Serializable obj) throws IOException {
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
try (final ObjectOutputStream oos = new ObjectOutputStream(bout)) {
oos.writeObject(obj);
- oos.flush();
- out.writeObject(bout.toByteArray());
}
+ return bout.toByteArray();
}
+ /**
+ * Reads an object written by {@link #writeWrappedObject}.
+ *
+ * <p>The object is read from a nested stream, filtered in the same way as {@code in}.
+ * If the class of the object is not available, {@code null} is returned and a warning is logged.
+ * Other errors, including classes rejected by the filter, are thrown.</p>
+ *
+ * @param in The input stream.
+ * @return The object or {@code null}.
+ */
@SuppressFBWarnings(
value = "OBJECT_DESERIALIZATION",
justification = "The nested stream is filtered in the same way as the outer stream.")
@@ -93,7 +126,11 @@ public final class SerializationUtil {
copyObjectInputFilter(in, ois);
try {
return ois.readObject();
+ } catch (final IOException e) {
+ // Includes classes rejected by the stream's filter
+ throw e;
} catch (final Exception | LinkageError e) {
+ // The class is not available or not compatible
StatusLogger.getLogger().warn("Ignoring {} during deserialization", e.getMessage());
return null;
} finally {
diff --git a/log4j-core-test/pom.xml b/log4j-core-test/pom.xml
index 2fef2cbe50..9eec3c5f04 100644
--- a/log4j-core-test/pom.xml
+++ b/log4j-core-test/pom.xml
@@ -444,7 +444,7 @@
<goal>test</goal>
</goals>
<configuration>
- <argLine>-Djdk.serialFilter=java.lang.**;java.time.**;java.util.**;java.math.BigDecimal;java.math.BigInteger;java.rmi.MarshalledObject;org.apache.logging.log4j.**;!*</argLine>
+ <argLine>-Djdk.serialFilter=java.lang.**;java.time.**;java.util.**;java.math.BigDecimal;java.math.BigInteger;org.apache.logging.log4j.**;!*</argLine>
<groups>serialization</groups>
</configuration>
</execution>
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
index ae14cbb9d2..f833e4c03d 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
@@ -28,7 +28,9 @@ import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.io.ObjectStreamException;
import java.lang.reflect.Field;
+import java.net.URI;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
@@ -125,6 +127,36 @@ public class Log4jLogEventTest {
assertEquals(evt.isIncludeLocation(), evt2.isIncludeLocation());
}
+ @Test
+ @Tag("serialization")
+ void testJavaIoSerializableWithUnserializableMessage() {
+ final Log4jLogEvent evt = Log4jLogEvent.newBuilder() //
+ .setLoggerName("some.test") //
+ .setLoggerFqcn(Strings.EMPTY) //
+ .setLevel(Level.INFO) //
+ .setMessage(new UnserializableMessage("abc")) //
+ .build();
+
+ final Log4jLogEvent evt2 = deserialize(serialize(evt));
+
+ assertEquals(new SimpleMessage("abc"), evt2.getMessage());
+ }
+
+ @Test
+ @Tag("serialization")
+ void testJavaIoSerializableWithClassNotOnAllowlist() {
+ final Log4jLogEvent evt = Log4jLogEvent.newBuilder() //
+ .setLoggerName("some.test") //
+ .setLoggerFqcn(Strings.EMPTY) //
+ .setLevel(Level.INFO) //
+ .setMessage(new ObjectMessage(URI.create("https://logging.apache.org/"))) //
+ .build();
+
+ final byte[] binary = serialize(evt);
+ final IllegalStateException e = assertThrows(IllegalStateException.class, () -> deserialize(binary));
+ assertInstanceOf(ObjectStreamException.class, e.getCause());
+ }
+
@Test
@Tag("serialization")
void testJavaIoSerializableWithThrown() {
@@ -183,12 +215,158 @@ public class Log4jLogEventTest {
// final Exception thrown = new DeletedException(errorMessage);
// final Log4jLogEvent evt = new Log4jLogEvent(loggerName, marker, loggerFQN, level, msg, thrown);
// final byte[] binary = serialize(evt);
- // String base64Str = DatatypeConverter.printBase64Binary(binary);
- // System.out.println("final String base64 = \"" + base64Str.replaceAll("\r\n", "\\\\r\\\\n\" +\r\n\"") +
- // "\";");
-
- final String base64 =
- "rO0ABXNyAD5vcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkxvZzRqTG9nRXZlbnQkTG9nRXZlbnRQcm94eYgtmn+yXsP9AwAQWgAMaXNFbmRPZkJhdGNoWgASaXNMb2NhdGlvblJlcXVpcmVkSgAIdGhyZWFkSWRJAA50aHJlYWRQcmlvcml0eUoACnRpbWVNaWxsaXNMAAtjb250ZXh0RGF0YXQAKUxvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovdXRpbC9TdHJpbmdNYXA7TAAMY29udGV4dFN0YWNrdAA1TG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9UaHJlYWRDb250ZXh0JENvbnRleHRTdGFjaztMAAVsZXZlbHQAIExvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovTGV2ZWw7TAAKbG9nZ2VyRlFDTnQAEkxqYXZhL2xhbmc [...]
+ // final String base64Str = java.util.Base64.getEncoder().encodeToString(binary);
+ // System.out.println("final String base64 = \"" + base64Str.replaceAll(".{88}", "$0\" + \"") + "\";");
+
+ final String base64 = "rO0ABXNyAD5vcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkxvZzRqTG9nRXZlbnQkTG9nRXZlbnRQ"
+ + "cm94eYgtmn+yXsP9AwATWgAMaXNFbmRPZkJhdGNoWgASaXNMb2NhdGlvblJlcXVpcmVkSQARbmFub09mTWlsbGlz"
+ + "ZWNvbmRKAAh0aHJlYWRJZEkADnRocmVhZFByaW9yaXR5SgAKdGltZU1pbGxpc0wAC2NvbnRleHREYXRhdAApTG9y"
+ + "Zy9hcGFjaGUvbG9nZ2luZy9sb2c0ai91dGlsL1N0cmluZ01hcDtMAAxjb250ZXh0U3RhY2t0ADVMb3JnL2FwYWNo"
+ + "ZS9sb2dnaW5nL2xvZzRqL1RocmVhZENvbnRleHQkQ29udGV4dFN0YWNrO0wABWxldmVsdAAgTG9yZy9hcGFjaGUv"
+ + "bG9nZ2luZy9sb2c0ai9MZXZlbDtMAApsb2dnZXJGUUNOdAASTGphdmEvbGFuZy9TdHJpbmc7TAAKbG9nZ2VyTmFt"
+ + "ZXEAfgAETAAGbWFya2VydAAhTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9NYXJrZXI7TAANbWVzc2FnZVN0cmlu"
+ + "Z3EAfgAETAAGc291cmNldAAdTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDtMAAZzcGFuSWRxAH4ABEwACnRo"
+ + "cmVhZE5hbWVxAH4ABEwAC3Rocm93blByb3h5dAAzTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9jb3JlL2ltcGwv"
+ + "VGhyb3dhYmxlUHJveHk7TAAKdHJhY2VGbGFnc3EAfgAETAAHdHJhY2VJZHEAfgAEeHAAAAAAAAAAAAAAAAAAAQAA"
+ + "AAUAAAAASZYC0nNyADJvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGoudXRpbC5Tb3J0ZWRBcnJheVN0cmluZ01hcLA3"
+ + "yJFz7CvcAwACWgAJaW1tdXRhYmxlSQAJdGhyZXNob2xkeHABAAAAAXcIAAAAAQAAAAB4c3IAPm9yZy5hcGFjaGUu"
+ + "bG9nZ2luZy5sb2c0ai5UaHJlYWRDb250ZXh0JEVtcHR5VGhyZWFkQ29udGV4dFN0YWNrAAAAAAAAAAECAAB4cHNy"
+ + "AB5vcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouTGV2ZWwAAAAAABggGgIAA0kACGludExldmVsTAAEbmFtZXEAfgAE"
+ + "TAANc3RhbmRhcmRMZXZlbHQALExvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovc3BpL1N0YW5kYXJkTGV2ZWw7eHAA"
+ + "AAGQdAAESU5GT35yACpvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouc3BpLlN0YW5kYXJkTGV2ZWwAAAAAAAAAABIA"
+ + "AHhyAA5qYXZhLmxhbmcuRW51bQAAAAAAAAAAEgAAeHB0AARJTkZPdAAAdAAJc29tZS50ZXN0cHQAA2FiY3BxAH4A"
+ + "FXQABG1haW5zcgAxb3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5UaHJvd2FibGVQcm94ednMMNWa"
+ + "e6z6AgAHSQASY29tbW9uRWxlbWVudENvdW50TAAKY2F1c2VQcm94eXEAfgAHWwASZXh0ZW5kZWRTdGFja1RyYWNl"
+ + "dAA/W0xvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovY29yZS9pbXBsL0V4dGVuZGVkU3RhY2tUcmFjZUVsZW1lbnQ7"
+ + "TAAQbG9jYWxpemVkTWVzc2FnZXEAfgAETAAHbWVzc2FnZXEAfgAETAAEbmFtZXEAfgAEWwARc3VwcHJlc3NlZFBy"
+ + "b3hpZXN0ADRbTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9jb3JlL2ltcGwvVGhyb3dhYmxlUHJveHk7eHAAAAAA"
+ + "cHVyAD9bTG9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuRXh0ZW5kZWRTdGFja1RyYWNlRWxlbWVu"
+ + "dDvKz4gjpcfPvAIAAHhwAAAATnNyADxvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkV4dGVuZGVk"
+ + "U3RhY2tUcmFjZUVsZW1lbnTh3s+6xraQBwIAAkwADmV4dHJhQ2xhc3NJbmZvdAA2TG9yZy9hcGFjaGUvbG9nZ2lu"
+ + "Zy9sb2c0ai9jb3JlL2ltcGwvRXh0ZW5kZWRDbGFzc0luZm87TAARc3RhY2tUcmFjZUVsZW1lbnRxAH4ABnhwc3IA"
+ + "NG9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuRXh0ZW5kZWRDbGFzc0luZm8AAAAAAAAAAQIAA1oA"
+ + "BWV4YWN0TAAIbG9jYXRpb25xAH4ABEwAB3ZlcnNpb25xAH4ABHhwAHQADXRlc3QtY2xhc3Nlcy90AAE/c3IAG2ph"
+ + "dmEubGFuZy5TdGFja1RyYWNlRWxlbWVudGEJxZomNt2FAgAIQgAGZm9ybWF0SQAKbGluZU51bWJlckwAD2NsYXNz"
+ + "TG9hZGVyTmFtZXEAfgAETAAOZGVjbGFyaW5nQ2xhc3NxAH4ABEwACGZpbGVOYW1lcQB+AARMAAptZXRob2ROYW1l"
+ + "cQB+AARMAAptb2R1bGVOYW1lcQB+AARMAA1tb2R1bGVWZXJzaW9ucQB+AAR4cAEAAAC6dAADYXBwdAA0b3JnLmFw"
+ + "YWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5Mb2c0akxvZ0V2ZW50VGVzdHQAFkxvZzRqTG9nRXZlbnRUZXN0"
+ + "LmphdmF0ACp0ZXN0SmF2YUlvU2VyaWFsaXphYmxlV2l0aFVua25vd25UaHJvd2FibGVwcHNxAH4AH3NxAH4AIgBx"
+ + "AH4AJXEAfgAlc3EAfgAmAv////5wdAAtamRrLmludGVybmFsLnJlZmxlY3QuTmF0aXZlTWV0aG9kQWNjZXNzb3JJ"
+ + "bXBsdAAdTmF0aXZlTWV0aG9kQWNjZXNzb3JJbXBsLmphdmF0AAdpbnZva2UwdAAJamF2YS5iYXNldAAJMTcuMC4y"
+ + "MC4xc3EAfgAfcQB+AC1zcQB+ACYCAAAATXBxAH4AL3EAfgAwdAAGaW52b2tlcQB+ADJxAH4AM3NxAH4AH3NxAH4A"
+ + "IgBxAH4AJXEAfgAlc3EAfgAmAgAAACtwdAAxamRrLmludGVybmFsLnJlZmxlY3QuRGVsZWdhdGluZ01ldGhvZEFj"
+ + "Y2Vzc29ySW1wbHQAIURlbGVnYXRpbmdNZXRob2RBY2Nlc3NvckltcGwuamF2YXEAfgA2cQB+ADJxAH4AM3NxAH4A"
+ + "H3NxAH4AIgBxAH4AJXEAfgAlc3EAfgAmAgAAAjlwdAAYamF2YS5sYW5nLnJlZmxlY3QuTWV0aG9kdAALTWV0aG9k"
+ + "LmphdmFxAH4ANnEAfgAycQB+ADNzcQB+AB9zcQB+ACIAdAAhanVuaXQtcGxhdGZvcm0tY29tbW9ucy0xLjE0LjQu"
+ + "amFydAAGMS4xNC40c3EAfgAmAQAAAxJxAH4AKHQAL29yZy5qdW5pdC5wbGF0Zm9ybS5jb21tb25zLnV0aWwuUmVm"
+ + "bGVjdGlvblV0aWxzdAAUUmVmbGVjdGlvblV0aWxzLmphdmF0AAxpbnZva2VNZXRob2RwcHNxAH4AH3NxAH4AIgB0"
+ + "ACFqdW5pdC1wbGF0Zm9ybS1jb21tb25zLTEuMTQuNC5qYXJxAH4ARHNxAH4AJgEAAAICcQB+ACh0ADRvcmcuanVu"
+ + "aXQucGxhdGZvcm0uY29tbW9ucy5zdXBwb3J0LlJlZmxlY3Rpb25TdXBwb3J0dAAWUmVmbGVjdGlvblN1cHBvcnQu"
+ + "amF2YXEAfgBIcHBzcQB+AB9zcQB+ACIAdAAfanVuaXQtanVwaXRlci1lbmdpbmUtNS4xNC40LmphcnQABjUuMTQu"
+ + "NHNxAH4AJgEAAAA8cQB+ACh0ADNvcmcuanVuaXQuanVwaXRlci5lbmdpbmUuZXhlY3V0aW9uLk1ldGhvZEludm9j"
+ + "YXRpb250ABVNZXRob2RJbnZvY2F0aW9uLmphdmF0AAdwcm9jZWVkcHBzcQB+AB9zcQB+ACIAdAAfanVuaXQtanVw"
+ + "aXRlci1lbmdpbmUtNS4xNC40LmphcnEAfgBSc3EAfgAmAQAAAINxAH4AKHQAUm9yZy5qdW5pdC5qdXBpdGVyLmVu"
+ + "Z2luZS5leGVjdXRpb24uSW52b2NhdGlvbkludGVyY2VwdG9yQ2hhaW4kVmFsaWRhdGluZ0ludm9jYXRpb250AB9J"
+ + "bnZvY2F0aW9uSW50ZXJjZXB0b3JDaGFpbi5qYXZhcQB+AFZwcHNxAH4AH3NxAH4AIgB0AB9qdW5pdC1qdXBpdGVy"
+ + "LWVuZ2luZS01LjE0LjQuamFycQB+AFJzcQB+ACYBAAAAoXEAfgAodAAzb3JnLmp1bml0Lmp1cGl0ZXIuZW5naW5l"
+ + "LmV4dGVuc2lvbi5UaW1lb3V0RXh0ZW5zaW9udAAVVGltZW91dEV4dGVuc2lvbi5qYXZhdAAJaW50ZXJjZXB0cHBz"
+ + "cQB+AB9xAH4AXnNxAH4AJgEAAACYcQB+AChxAH4AYXEAfgBidAAXaW50ZXJjZXB0VGVzdGFibGVNZXRob2RwcHNx"
+ + "AH4AH3EAfgBec3EAfgAmAQAAAFtxAH4AKHEAfgBhcQB+AGJ0ABNpbnRlcmNlcHRUZXN0TWV0aG9kcHBzcQB+AB9z"
+ + "cQB+ACIAdAAfanVuaXQtanVwaXRlci1lbmdpbmUtNS4xNC40LmphcnEAfgBSc3EAfgAmAQAAAHBxAH4AKHQAWm9y"
+ + "Zy5qdW5pdC5qdXBpdGVyLmVuZ2luZS5leGVjdXRpb24uSW50ZXJjZXB0aW5nRXhlY3V0YWJsZUludm9rZXIkUmVm"
+ + "bGVjdGl2ZUludGVyY2VwdG9yQ2FsbHQAIkludGVyY2VwdGluZ0V4ZWN1dGFibGVJbnZva2VyLmphdmF0ABVsYW1i"
+ + "ZGEkb2ZWb2lkTWV0aG9kJDBwcHNxAH4AH3NxAH4AIgB0AB9qdW5pdC1qdXBpdGVyLWVuZ2luZS01LjE0LjQuamFy"
+ + "cQB+AFJzcQB+ACYBAAAAXnEAfgAodABAb3JnLmp1bml0Lmp1cGl0ZXIuZW5naW5lLmV4ZWN1dGlvbi5JbnRlcmNl"
+ + "cHRpbmdFeGVjdXRhYmxlSW52b2tlcnEAfgBvdAAPbGFtYmRhJGludm9rZSQwcHBzcQB+AB9zcQB+ACIAdAAfanVu"
+ + "aXQtanVwaXRlci1lbmdpbmUtNS4xNC40LmphcnEAfgBSc3EAfgAmAQAAAGpxAH4AKHQAU29yZy5qdW5pdC5qdXBp"
+ + "dGVyLmVuZ2luZS5leGVjdXRpb24uSW52b2NhdGlvbkludGVyY2VwdG9yQ2hhaW4kSW50ZXJjZXB0ZWRJbnZvY2F0"
+ + "aW9ucQB+AFxxAH4AVnBwc3EAfgAfc3EAfgAiAHQAH2p1bml0LWp1cGl0ZXItZW5naW5lLTUuMTQuNC5qYXJxAH4A"
+ + "UnNxAH4AJgEAAABAcQB+ACh0AD1vcmcuanVuaXQuanVwaXRlci5lbmdpbmUuZXhlY3V0aW9uLkludm9jYXRpb25J"
+ + "bnRlcmNlcHRvckNoYWlucQB+AFxxAH4AVnBwc3EAfgAfcQB+AH1zcQB+ACYBAAAALXEAfgAocQB+AIBxAH4AXHQA"
+ + "DmNoYWluQW5kSW52b2tlcHBzcQB+AB9xAH4AfXNxAH4AJgEAAAAlcQB+AChxAH4AgHEAfgBccQB+ADZwcHNxAH4A"
+ + "H3EAfgByc3EAfgAmAQAAAF1xAH4AKHEAfgB1cQB+AG9xAH4ANnBwc3EAfgAfcQB+AHJzcQB+ACYBAAAAV3EAfgAo"
+ + "cQB+AHVxAH4Ab3EAfgA2cHBzcQB+AB9zcQB+ACIAdAAfanVuaXQtanVwaXRlci1lbmdpbmUtNS4xNC40LmphcnEA"
+ + "fgBSc3EAfgAmAQAAAN1xAH4AKHQAPG9yZy5qdW5pdC5qdXBpdGVyLmVuZ2luZS5kZXNjcmlwdG9yLlRlc3RNZXRo"
+ + "b2RUZXN0RGVzY3JpcHRvcnQAHVRlc3RNZXRob2RUZXN0RGVzY3JpcHRvci5qYXZhdAAZbGFtYmRhJGludm9rZVRl"
+ + "c3RNZXRob2QkNHBwc3EAfgAfc3EAfgAiAHQAIGp1bml0LXBsYXRmb3JtLWVuZ2luZS0xLjE0LjQuamFydAAGMS4x"
+ + "NC40c3EAfgAmAQAAAElxAH4AKHQAQW9yZy5qdW5pdC5wbGF0Zm9ybS5lbmdpbmUuc3VwcG9ydC5oaWVyYXJjaGlj"
+ + "YWwuVGhyb3dhYmxlQ29sbGVjdG9ydAAXVGhyb3dhYmxlQ29sbGVjdG9yLmphdmF0AAdleGVjdXRlcHBzcQB+AB9x"
+ + "AH4Ai3NxAH4AJgEAAADZcQB+AChxAH4AjnEAfgCPdAAQaW52b2tlVGVzdE1ldGhvZHBwc3EAfgAfcQB+AItzcQB+"
+ + "ACYBAAAAn3EAfgAocQB+AI5xAH4Aj3EAfgCYcHBzcQB+AB9xAH4Ai3NxAH4AJgEAAABGcQB+AChxAH4AjnEAfgCP"
+ + "cQB+AJhwcHNxAH4AH3NxAH4AIgB0ACBqdW5pdC1wbGF0Zm9ybS1lbmdpbmUtMS4xNC40LmphcnEAfgCUc3EAfgAm"
+ + "AQAAAJ1xAH4AKHQAO29yZy5qdW5pdC5wbGF0Zm9ybS5lbmdpbmUuc3VwcG9ydC5oaWVyYXJjaGljYWwuTm9kZVRl"
+ + "c3RUYXNrdAARTm9kZVRlc3RUYXNrLmphdmF0ABtsYW1iZGEkZXhlY3V0ZVJlY3Vyc2l2ZWx5JDZwcHNxAH4AH3EA"
+ + "fgCSc3EAfgAmAQAAAElxAH4AKHEAfgCWcQB+AJdxAH4AmHBwc3EAfgAfcQB+AKFzcQB+ACYBAAAAk3EAfgAocQB+"
+ + "AKRxAH4ApXQAG2xhbWJkYSRleGVjdXRlUmVjdXJzaXZlbHkkOHBwc3EAfgAfc3EAfgAiAHQAIGp1bml0LXBsYXRm"
+ + "b3JtLWVuZ2luZS0xLjE0LjQuamFycQB+AJRzcQB+ACYBAAAAiXEAfgAodAAzb3JnLmp1bml0LnBsYXRmb3JtLmVu"
+ + "Z2luZS5zdXBwb3J0LmhpZXJhcmNoaWNhbC5Ob2RldAAJTm9kZS5qYXZhdAAGYXJvdW5kcHBzcQB+AB9xAH4AoXNx"
+ + "AH4AJgEAAACRcQB+AChxAH4ApHEAfgCldAAbbGFtYmRhJGV4ZWN1dGVSZWN1cnNpdmVseSQ5cHBzcQB+AB9xAH4A"
+ + "knNxAH4AJgEAAABJcQB+AChxAH4AlnEAfgCXcQB+AJhwcHNxAH4AH3EAfgChc3EAfgAmAQAAAJBxAH4AKHEAfgCk"
+ + "cQB+AKV0ABJleGVjdXRlUmVjdXJzaXZlbHlwcHNxAH4AH3EAfgChc3EAfgAmAQAAAGVxAH4AKHEAfgCkcQB+AKVx"
+ + "AH4AmHBwc3EAfgAfc3EAfgAiAHEAfgAlcQB+ACVzcQB+ACYCAAAF53B0ABNqYXZhLnV0aWwuQXJyYXlMaXN0dAAO"
+ + "QXJyYXlMaXN0LmphdmF0AAdmb3JFYWNocQB+ADJxAH4AM3NxAH4AH3NxAH4AIgB0ACBqdW5pdC1wbGF0Zm9ybS1l"
+ + "bmdpbmUtMS4xNC40LmphcnEAfgCUc3EAfgAmAQAAAClxAH4AKHQAWG9yZy5qdW5pdC5wbGF0Zm9ybS5lbmdpbmUu"
+ + "c3VwcG9ydC5oaWVyYXJjaGljYWwuU2FtZVRocmVhZEhpZXJhcmNoaWNhbFRlc3RFeGVjdXRvclNlcnZpY2V0AC5T"
+ + "YW1lVGhyZWFkSGllcmFyY2hpY2FsVGVzdEV4ZWN1dG9yU2VydmljZS5qYXZhdAAJaW52b2tlQWxscHBzcQB+AB9x"
+ + "AH4AoXNxAH4AJgEAAAChcQB+AChxAH4ApHEAfgClcQB+AKZwcHNxAH4AH3EAfgCSc3EAfgAmAQAAAElxAH4AKHEA"
+ + "fgCWcQB+AJdxAH4AmHBwc3EAfgAfcQB+AKFzcQB+ACYBAAAAk3EAfgAocQB+AKRxAH4ApXEAfgCrcHBzcQB+AB9x"
+ + "AH4ArXNxAH4AJgEAAACJcQB+AChxAH4AsHEAfgCxcQB+ALJwcHNxAH4AH3EAfgChc3EAfgAmAQAAAJFxAH4AKHEA"
+ + "fgCkcQB+AKVxAH4AtXBwc3EAfgAfcQB+AJJzcQB+ACYBAAAASXEAfgAocQB+AJZxAH4Al3EAfgCYcHBzcQB+AB9x"
+ + "AH4AoXNxAH4AJgEAAACQcQB+AChxAH4ApHEAfgClcQB+ALpwcHNxAH4AH3EAfgChc3EAfgAmAQAAAGVxAH4AKHEA"
+ + "fgCkcQB+AKVxAH4AmHBwc3EAfgAfcQB+AL5zcQB+ACYCAAAF53BxAH4AwHEAfgDBcQB+AMJxAH4AMnEAfgAzc3EA"
+ + "fgAfcQB+AMRzcQB+ACYBAAAAKXEAfgAocQB+AMdxAH4AyHEAfgDJcHBzcQB+AB9xAH4AoXNxAH4AJgEAAAChcQB+"
+ + "AChxAH4ApHEAfgClcQB+AKZwcHNxAH4AH3EAfgCSc3EAfgAmAQAAAElxAH4AKHEAfgCWcQB+AJdxAH4AmHBwc3EA"
+ + "fgAfcQB+AKFzcQB+ACYBAAAAk3EAfgAocQB+AKRxAH4ApXEAfgCrcHBzcQB+AB9xAH4ArXNxAH4AJgEAAACJcQB+"
+ + "AChxAH4AsHEAfgCxcQB+ALJwcHNxAH4AH3EAfgChc3EAfgAmAQAAAJFxAH4AKHEAfgCkcQB+AKVxAH4AtXBwc3EA"
+ + "fgAfcQB+AJJzcQB+ACYBAAAASXEAfgAocQB+AJZxAH4Al3EAfgCYcHBzcQB+AB9xAH4AoXNxAH4AJgEAAACQcQB+"
+ + "AChxAH4ApHEAfgClcQB+ALpwcHNxAH4AH3EAfgChc3EAfgAmAQAAAGVxAH4AKHEAfgCkcQB+AKVxAH4AmHBwc3EA"
+ + "fgAfcQB+AMRzcQB+ACYBAAAAI3EAfgAocQB+AMdxAH4AyHQABnN1Ym1pdHBwc3EAfgAfc3EAfgAiAHQAIGp1bml0"
+ + "LXBsYXRmb3JtLWVuZ2luZS0xLjE0LjQuamFycQB+AJRzcQB+ACYBAAAAOXEAfgAodABHb3JnLmp1bml0LnBsYXRm"
+ + "b3JtLmVuZ2luZS5zdXBwb3J0LmhpZXJhcmNoaWNhbC5IaWVyYXJjaGljYWxUZXN0RXhlY3V0b3J0AB1IaWVyYXJj"
+ + "aGljYWxUZXN0RXhlY3V0b3IuamF2YXEAfgCYcHBzcQB+AB9zcQB+ACIAdAAganVuaXQtcGxhdGZvcm0tZW5naW5l"
+ + "LTEuMTQuNC5qYXJxAH4AlHNxAH4AJgEAAAA2cQB+ACh0AEVvcmcuanVuaXQucGxhdGZvcm0uZW5naW5lLnN1cHBv"
+ + "cnQuaGllcmFyY2hpY2FsLkhpZXJhcmNoaWNhbFRlc3RFbmdpbmV0ABtIaWVyYXJjaGljYWxUZXN0RW5naW5lLmph"
+ + "dmFxAH4AmHBwc3EAfgAfc3EAfgAiAHQAImp1bml0LXBsYXRmb3JtLWxhdW5jaGVyLTEuMTQuNC5qYXJ0AAYxLjE0"
+ + "LjRzcQB+ACYBAAAA5nEAfgAodAA8b3JnLmp1bml0LnBsYXRmb3JtLmxhdW5jaGVyLmNvcmUuRW5naW5lRXhlY3V0"
+ + "aW9uT3JjaGVzdHJhdG9ydAAgRW5naW5lRXhlY3V0aW9uT3JjaGVzdHJhdG9yLmphdmF0AA1leGVjdXRlRW5naW5l"
+ + "cHBzcQB+AB9xAH4A/nNxAH4AJgEAAADMcQB+AChxAH4BAnEAfgEDdAATZmFpbE9yRXhlY3V0ZUVuZ2luZXBwc3EA"
+ + "fgAfcQB+AP5zcQB+ACYBAAAArHEAfgAocQB+AQJxAH4BA3EAfgCYcHBzcQB+AB9xAH4A/nNxAH4AJgEAAABlcQB+"
+ + "AChxAH4BAnEAfgEDcQB+AJhwcHNxAH4AH3EAfgD+c3EAfgAmAQAAAEBxAH4AKHEAfgECcQB+AQN0ABBsYW1iZGEk"
+ + "ZXhlY3V0ZSQwcHBzcQB+AB9xAH4A/nNxAH4AJgEAAACWcQB+AChxAH4BAnEAfgEDdAAWd2l0aEludGVyY2VwdGVk"
+ + "U3RyZWFtc3Bwc3EAfgAfcQB+AP5zcQB+ACYBAAAAP3EAfgAocQB+AQJxAH4BA3EAfgCYcHBzcQB+AB9zcQB+ACIA"
+ + "dAAianVuaXQtcGxhdGZvcm0tbGF1bmNoZXItMS4xNC40LmphcnEAfgEAc3EAfgAmAQAAAG1xAH4AKHQAMG9yZy5q"
+ + "dW5pdC5wbGF0Zm9ybS5sYXVuY2hlci5jb3JlLkRlZmF1bHRMYXVuY2hlcnQAFERlZmF1bHRMYXVuY2hlci5qYXZh"
+ + "cQB+AJhwcHNxAH4AH3EAfgEVc3EAfgAmAQAAAFtxAH4AKHEAfgEYcQB+ARlxAH4AmHBwc3EAfgAfc3EAfgAiAHQA"
+ + "Imp1bml0LXBsYXRmb3JtLWxhdW5jaGVyLTEuMTQuNC5qYXJxAH4BAHNxAH4AJgEAAAAvcQB+ACh0ADNvcmcuanVu"
+ + "aXQucGxhdGZvcm0ubGF1bmNoZXIuY29yZS5EZWxlZ2F0aW5nTGF1bmNoZXJ0ABdEZWxlZ2F0aW5nTGF1bmNoZXIu"
+ + "amF2YXEAfgCYcHBzcQB+AB9zcQB+ACIAdAAianVuaXQtcGxhdGZvcm0tbGF1bmNoZXItMS4xNC40LmphcnEAfgEA"
+ + "c3EAfgAmAQAAACdxAH4AKHQANW9yZy5qdW5pdC5wbGF0Zm9ybS5sYXVuY2hlci5jb3JlLkludGVyY2VwdGluZ0xh"
+ + "dW5jaGVydAAZSW50ZXJjZXB0aW5nTGF1bmNoZXIuamF2YXQAEGxhbWJkYSRleGVjdXRlJDFwcHNxAH4AH3NxAH4A"
+ + "IgF0ACJqdW5pdC1wbGF0Zm9ybS1sYXVuY2hlci0xLjE0LjQuamFycQB+AQBzcQB+ACYBAAAAGXEAfgAodABOb3Jn"
+ + "Lmp1bml0LnBsYXRmb3JtLmxhdW5jaGVyLmNvcmUuQ2xhc3NwYXRoQWxpZ25tZW50Q2hlY2tpbmdMYXVuY2hlcklu"
+ + "dGVyY2VwdG9ydAAyQ2xhc3NwYXRoQWxpZ25tZW50Q2hlY2tpbmdMYXVuY2hlckludGVyY2VwdG9yLmphdmFxAH4A"
+ + "Y3Bwc3EAfgAfc3EAfgAiAXQAImp1bml0LXBsYXRmb3JtLWxhdW5jaGVyLTEuMTQuNC5qYXJxAH4BAHNxAH4AJgEA"
+ + "AAAmcQB+AChxAH4BJnEAfgEncQB+AJhwcHNxAH4AH3NxAH4AIgF0ACJqdW5pdC1wbGF0Zm9ybS1sYXVuY2hlci0x"
+ + "LjE0LjQuamFycQB+AQBzcQB+ACYBAAAAL3EAfgAocQB+ASBxAH4BIXEAfgCYcHBzcQB+AB9zcQB+ACIBdAAhc3Vy"
+ + "ZWZpcmUtanVuaXQtcGxhdGZvcm0tMy41LjIuamFydAAFMy41LjJzcQB+ACYBAAAAOHEAfgAodAA0b3JnLmFwYWNo"
+ + "ZS5tYXZlbi5zdXJlZmlyZS5qdW5pdHBsYXRmb3JtLkxhenlMYXVuY2hlcnQAEUxhenlMYXVuY2hlci5qYXZhcQB+"
+ + "AJhwcHNxAH4AH3NxAH4AIgF0ACFzdXJlZmlyZS1qdW5pdC1wbGF0Zm9ybS0zLjUuMi5qYXJxAH4BOnNxAH4AJgEA"
+ + "AAC4cQB+ACh0AD1vcmcuYXBhY2hlLm1hdmVuLnN1cmVmaXJlLmp1bml0cGxhdGZvcm0uSlVuaXRQbGF0Zm9ybVBy"
+ + "b3ZpZGVydAAaSlVuaXRQbGF0Zm9ybVByb3ZpZGVyLmphdmFxAH4AmHBwc3EAfgAfc3EAfgAiAXQAIXN1cmVmaXJl"
+ + "LWp1bml0LXBsYXRmb3JtLTMuNS4yLmphcnEAfgE6c3EAfgAmAQAAAJRxAH4AKHEAfgFCcQB+AUN0AA5pbnZva2VB"
+ + "bGxUZXN0c3Bwc3EAfgAfc3EAfgAiAXQAIXN1cmVmaXJlLWp1bml0LXBsYXRmb3JtLTMuNS4yLmphcnEAfgE6c3EA"
+ + "fgAmAQAAAHhxAH4AKHEAfgFCcQB+AUNxAH4ANnBwc3EAfgAfc3EAfgAiAXQAGXN1cmVmaXJlLWJvb3Rlci0zLjUu"
+ + "Mi5qYXJ0AAUzLjUuMnNxAH4AJgEAAAGBcQB+ACh0AC1vcmcuYXBhY2hlLm1hdmVuLnN1cmVmaXJlLmJvb3Rlci5G"
+ + "b3JrZWRCb290ZXJ0ABFGb3JrZWRCb290ZXIuamF2YXQAEnJ1blN1aXRlc0luUHJvY2Vzc3Bwc3EAfgAfc3EAfgAi"
+ + "AXQAGXN1cmVmaXJlLWJvb3Rlci0zLjUuMi5qYXJxAH4BUHNxAH4AJgEAAACicQB+AChxAH4BUnEAfgFTcQB+AJhw"
+ + "cHNxAH4AH3NxAH4AIgF0ABlzdXJlZmlyZS1ib290ZXItMy41LjIuamFycQB+AVBzcQB+ACYBAAAB+3EAfgAocQB+"
+ + "AVJxAH4BU3QAA3J1bnBwc3EAfgAfc3EAfgAiAXQAGXN1cmVmaXJlLWJvb3Rlci0zLjUuMi5qYXJxAH4BUHNxAH4A"
+ + "JgEAAAHvcQB+AChxAH4BUnEAfgFTdAAEbWFpbnBwdAAWT01HIEkndmUgYmVlbiBkZWxldGVkIXEAfgFjdABFb3Jn"
+ + "LmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5Mb2c0akxvZ0V2ZW50VGVzdCREZWxldGVkRXhjZXB0aW9u"
+ + "dXIANFtMb3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5UaHJvd2FibGVQcm94eTv67QHghaLrOQIA"
+ + "AHhwAAAAAHEAfgAVcQB+ABV1cgACW0Ks8xf4BghU4AIAAHhwAAAAaaztAAVzcgAub3JnLmFwYWNoZS5sb2dnaW5n"
+ + "LmxvZzRqLm1lc3NhZ2UuU2ltcGxlTWVzc2FnZYt0TTBgt6KoAwABTAAHbWVzc2FnZXQAEkxqYXZhL2xhbmcvU3Ry"
+ + "aW5nO3hwdAADYWJjeHg=";
final byte[] binaryDecoded = Base64Converter.parseBase64Binary(base64);
final Log4jLogEvent evt2 = deserialize(binaryDecoded);
@@ -206,6 +384,64 @@ public class Log4jLogEventTest {
assertEquals(errorMessage, evt2.getThrownProxy().getMessage());
}
+ // DO NOT REMOVE THIS COMMENT:
+ // UNCOMMENT WHEN GENERATING SERIALIZED EVENT FOR #testJavaIoSerializableWithUnknownMessage
+ // public static class DeletedMessage implements Message {
+ // private static final long serialVersionUID = 1L;
+ // public String getFormattedMessage() { return "abc"; }
+ // public String getFormat() { return "abc"; }
+ // public Object[] getParameters() { return null; }
+ // public Throwable getThrowable() { return null; }
+ // };
+
+ /**
+ * The class of the message is allowed by the deserialization filter, but not available to the reader:
+ * the message degrades to a {@link SimpleMessage} with the formatted message.
+ */
+ @Test
+ @Tag("serialization")
+ void testJavaIoSerializableWithUnknownMessage() {
+ final String loggerName = "some.test";
+ final Level level = Level.INFO;
+
+ // DO NOT DELETE THIS COMMENT:
+ // UNCOMMENT TO RE-GENERATE SERIALIZED EVENT WHEN UPDATING THIS TEST.
+ // final Log4jLogEvent evt = Log4jLogEvent.newBuilder()
+ // .setLoggerName(loggerName)
+ // .setLevel(level)
+ // .setMessage(new DeletedMessage())
+ // .build();
+ // final byte[] binary = serialize(evt);
+ // final String base64Str = java.util.Base64.getEncoder().encodeToString(binary);
+ // System.out.println("final String base64 = \"" + base64Str.replaceAll(".{88}", "$0\" + \"") + "\";");
+
+ final String base64 = "rO0ABXNyAD5vcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkxvZzRqTG9nRXZlbnQkTG9nRXZlbnRQ"
+ + "cm94eYgtmn+yXsP9AwATWgAMaXNFbmRPZkJhdGNoWgASaXNMb2NhdGlvblJlcXVpcmVkSQARbmFub09mTWlsbGlz"
+ + "ZWNvbmRKAAh0aHJlYWRJZEkADnRocmVhZFByaW9yaXR5SgAKdGltZU1pbGxpc0wAC2NvbnRleHREYXRhdAApTG9y"
+ + "Zy9hcGFjaGUvbG9nZ2luZy9sb2c0ai91dGlsL1N0cmluZ01hcDtMAAxjb250ZXh0U3RhY2t0ADVMb3JnL2FwYWNo"
+ + "ZS9sb2dnaW5nL2xvZzRqL1RocmVhZENvbnRleHQkQ29udGV4dFN0YWNrO0wABWxldmVsdAAgTG9yZy9hcGFjaGUv"
+ + "bG9nZ2luZy9sb2c0ai9MZXZlbDtMAApsb2dnZXJGUUNOdAASTGphdmEvbGFuZy9TdHJpbmc7TAAKbG9nZ2VyTmFt"
+ + "ZXEAfgAETAAGbWFya2VydAAhTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9NYXJrZXI7TAANbWVzc2FnZVN0cmlu"
+ + "Z3EAfgAETAAGc291cmNldAAdTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDtMAAZzcGFuSWRxAH4ABEwACnRo"
+ + "cmVhZE5hbWVxAH4ABEwAC3Rocm93blByb3h5dAAzTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9jb3JlL2ltcGwv"
+ + "VGhyb3dhYmxlUHJveHk7TAAKdHJhY2VGbGFnc3EAfgAETAAHdHJhY2VJZHEAfgAEeHAAAAAAAAAAAAAAAAAAAQAA"
+ + "AAUAAAAASZYC0nNyADJvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGoudXRpbC5Tb3J0ZWRBcnJheVN0cmluZ01hcLA3"
+ + "yJFz7CvcAwACWgAJaW1tdXRhYmxlSQAJdGhyZXNob2xkeHABAAAAAXcIAAAAAQAAAAB4c3IAPm9yZy5hcGFjaGUu"
+ + "bG9nZ2luZy5sb2c0ai5UaHJlYWRDb250ZXh0JEVtcHR5VGhyZWFkQ29udGV4dFN0YWNrAAAAAAAAAAECAAB4cHNy"
+ + "AB5vcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouTGV2ZWwAAAAAABggGgIAA0kACGludExldmVsTAAEbmFtZXEAfgAE"
+ + "TAANc3RhbmRhcmRMZXZlbHQALExvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovc3BpL1N0YW5kYXJkTGV2ZWw7eHAA"
+ + "AAGQdAAESU5GT35yACpvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouc3BpLlN0YW5kYXJkTGV2ZWwAAAAAAAAAABIA"
+ + "AHhyAA5qYXZhLmxhbmcuRW51bQAAAAAAAAAAEgAAeHB0AARJTkZPcHQACXNvbWUudGVzdHB0AANhYmNwdAAAdAAE"
+ + "bWFpbnBxAH4AF3EAfgAXdXIAAltCrPMX+AYIVOACAAB4cAAAAFis7QAFc3IAQ29yZy5hcGFjaGUubG9nZ2luZy5s"
+ + "b2c0ai5jb3JlLmltcGwuTG9nNGpMb2dFdmVudFRlc3QkRGVsZXRlZE1lc3NhZ2UAAAAAAAAAAQIAAHhweA==";
+
+ final Log4jLogEvent evt2 = deserialize(Base64Converter.parseBase64Binary(base64));
+
+ assertEquals(loggerName, evt2.getLoggerName());
+ assertEquals(level, evt2.getLevel());
+ assertEquals(new SimpleMessage("abc"), evt2.getMessage());
+ }
+
@Test
void testNullLevelReplacedWithOFF() {
final Level NULL_LEVEL = null;
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/UnserializableMessage.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/UnserializableMessage.java
new file mode 100644
index 0000000000..93c230dbb4
--- /dev/null
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/UnserializableMessage.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.core.impl;
+
+import org.apache.logging.log4j.message.Message;
+
+/**
+ * A {@link Message} that cannot be serialized, although it implements {@link java.io.Serializable}.
+ * <p>
+ * One of its fields is not serializable, so serializing it throws {@link java.io.NotSerializableException}.
+ * It can be used to test that serializable Log4j classes, which contain arbitrary messages or objects,
+ * fall back to a serializable representation, like the formatted message.
+ * </p>
+ */
+final class UnserializableMessage implements Message {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String text;
+
+ @SuppressWarnings({"serial", "unused"})
+ private final Object unserializableField = new Object();
+
+ UnserializableMessage(final String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String getFormattedMessage() {
+ return text;
+ }
+
+ @Override
+ public String getFormat() {
+ return text;
+ }
+
+ @Override
+ public Object[] getParameters() {
+ return null;
+ }
+
+ @Override
+ public Throwable getThrowable() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+}
diff --git a/log4j-core-test/src/test/resources/serializedEvent.dat b/log4j-core-test/src/test/resources/serializedEvent.dat
deleted file mode 100644
index 5bb9874758..0000000000
Binary files a/log4j-core-test/src/test/resources/serializedEvent.dat and /dev/null differ
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 e47fa88049..9132e24305 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
@@ -20,7 +20,6 @@ import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
-import java.rmi.MarshalledObject;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -48,6 +47,7 @@ import org.apache.logging.log4j.util.ReadOnlyStringMap;
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.
@@ -1129,9 +1129,7 @@ public class Log4jLogEvent implements LogEvent {
private final Level level;
private final String loggerName;
// transient since 2.8
- private final transient Message message;
- /** @since 2.8 */
- private MarshalledObject<Message> marshalledMessage;
+ private transient Message message;
/** @since 2.8 */
private String messageString;
@@ -1220,18 +1218,17 @@ public class Log4jLogEvent implements LogEvent {
return result;
}
- private static MarshalledObject<Message> marshall(final Message msg) {
- try {
- return new MarshalledObject<>(msg);
- } catch (final Exception ex) {
- return null;
- }
- }
-
private void writeObject(final java.io.ObjectOutputStream s) throws IOException {
this.messageString = message.getFormattedMessage();
- this.marshalledMessage = marshall(message);
s.defaultWriteObject();
+ // Messages that cannot be serialized are replaced with a `SimpleMessage`
+ SerializationUtil.writeWrappedObject(message, () -> new SimpleMessage(messageString), s);
+ }
+
+ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ final Object wrapped = SerializationUtil.readWrappedObject(in);
+ message = wrapped instanceof Message ? (Message) wrapped : null;
}
/**
@@ -1263,14 +1260,7 @@ public class Log4jLogEvent implements LogEvent {
}
private Message message() {
- if (marshalledMessage != null) {
- try {
- return marshalledMessage.get();
- } catch (final Exception ex) {
- // ignore me
- }
- }
- return new SimpleMessage(messageString);
+ return message != null ? message : new SimpleMessage(messageString);
}
}
}
diff --git a/src/changelog/.2.x.x/4271_remove_marshalled_object_from_log_event_serialization.xml b/src/changelog/.2.x.x/4271_remove_marshalled_object_from_log_event_serialization.xml
new file mode 100644
index 0000000000..48c4a494a4
--- /dev/null
+++ b/src/changelog/.2.x.x/4271_remove_marshalled_object_from_log_event_serialization.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns="https://logging.apache.org/xml/ns"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ https://logging.apache.org/xml/ns
+ https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
+ type="changed">
+ <issue id="4271" link="https://github.com/apache/logging-log4j2/pull/4271"/>
+ <description format="asciidoc">
+ Align the serialization format of `Log4jLogEvent` with that of `ObjectMessage`: log events serialized by earlier versions can no longer be deserialized.
+ </description>
+</entry>
diff --git a/src/changelog/.2.x.x/4271_throw_on_rejected_nested_objects.xml b/src/changelog/.2.x.x/4271_throw_on_rejected_nested_objects.xml
new file mode 100644
index 0000000000..86db4c5c54
--- /dev/null
+++ b/src/changelog/.2.x.x/4271_throw_on_rejected_nested_objects.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns="https://logging.apache.org/xml/ns"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ https://logging.apache.org/xml/ns
+ https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
+ type="changed">
+ <issue id="4271" link="https://github.com/apache/logging-log4j2/pull/4271"/>
+ <description format="asciidoc">
+ Throw instead of ignoring nested objects rejected during deserialization of messages and log events.
+ </description>
+</entry>