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>