Skip to content

Commit f7d3725

Browse files
authored
Fix JsonLayout failures under JPMS (#2815)
Fix `JsonLayout` failures under JPMS To avoid opening the `o.a.l.l.core.layout` package to the Jackson Java 9 module, we: - register an instance of `LogEvent` serializers explicitly, - change the access type of the `MapEntry` class to `public`. Closes #2814 and contains review suggestions (#2815).
1 parent e6c7f19 commit f7d3725

14 files changed

+114
-259
lines changed

log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataAsEntryListDeserializer.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@
1717
package org.apache.logging.log4j.core.jackson;
1818

1919
import com.fasterxml.jackson.core.JsonParser;
20-
import com.fasterxml.jackson.core.JsonProcessingException;
2120
import com.fasterxml.jackson.core.type.TypeReference;
2221
import com.fasterxml.jackson.databind.DeserializationContext;
2322
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
2423
import java.io.IOException;
2524
import java.util.List;
26-
import java.util.Map;
2725
import org.apache.logging.log4j.core.impl.ContextDataFactory;
2826
import org.apache.logging.log4j.util.StringMap;
2927

@@ -37,17 +35,16 @@ public class ContextDataAsEntryListDeserializer extends StdDeserializer<StringMa
3735
private static final long serialVersionUID = 1L;
3836

3937
ContextDataAsEntryListDeserializer() {
40-
super(Map.class);
38+
super(StringMap.class);
4139
}
4240

4341
@Override
44-
public StringMap deserialize(final JsonParser jp, final DeserializationContext ctxt)
45-
throws IOException, JsonProcessingException {
42+
public StringMap deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException {
4643
final List<MapEntry> list = jp.readValueAs(
4744
new TypeReference<List<MapEntry>>() {
4845
// empty
4946
});
50-
final StringMap contextData = new ContextDataFactory().createContextData();
47+
final StringMap contextData = ContextDataFactory.createContextData();
5148
for (final MapEntry mapEntry : list) {
5249
contextData.putValue(mapEntry.getKey(), mapEntry.getValue());
5350
}

log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataAsEntryListSerializer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import com.fasterxml.jackson.databind.SerializerProvider;
2222
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
2323
import java.io.IOException;
24-
import java.util.Map;
2524
import org.apache.logging.log4j.util.BiConsumer;
2625
import org.apache.logging.log4j.util.ReadOnlyStringMap;
2726

@@ -35,7 +34,7 @@ public class ContextDataAsEntryListSerializer extends StdSerializer<ReadOnlyStri
3534
private static final long serialVersionUID = 1L;
3635

3736
protected ContextDataAsEntryListSerializer() {
38-
super(Map.class, false);
37+
super(ReadOnlyStringMap.class);
3938
}
4039

4140
@Override

log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataDeserializer.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@
1717
package org.apache.logging.log4j.core.jackson;
1818

1919
import com.fasterxml.jackson.core.JsonParser;
20-
import com.fasterxml.jackson.core.JsonProcessingException;
2120
import com.fasterxml.jackson.core.JsonToken;
2221
import com.fasterxml.jackson.databind.DeserializationContext;
2322
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
2423
import java.io.IOException;
25-
import java.util.Map;
2624
import org.apache.logging.log4j.core.impl.ContextDataFactory;
2725
import org.apache.logging.log4j.util.StringMap;
2826

@@ -36,12 +34,11 @@ public class ContextDataDeserializer extends StdDeserializer<StringMap> {
3634
private static final long serialVersionUID = 1L;
3735

3836
ContextDataDeserializer() {
39-
super(Map.class);
37+
super(StringMap.class);
4038
}
4139

4240
@Override
43-
public StringMap deserialize(final JsonParser jp, final DeserializationContext ctxt)
44-
throws IOException, JsonProcessingException {
41+
public StringMap deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException {
4542

4643
// Sanity check: verify that we got "Json Object":
4744
// JsonToken tok = jp.nextToken();
@@ -51,7 +48,7 @@ public StringMap deserialize(final JsonParser jp, final DeserializationContext c
5148
final StringMap contextData = ContextDataFactory.createContextData();
5249
// Iterate over object fields:
5350
while (jp.nextToken() != JsonToken.END_OBJECT) {
54-
final String fieldName = jp.getCurrentName();
51+
final String fieldName = jp.currentName();
5552

5653
// move to value
5754
jp.nextToken();

log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataSerializer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import com.fasterxml.jackson.databind.SerializerProvider;
2222
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
2323
import java.io.IOException;
24-
import java.util.Map;
2524
import org.apache.logging.log4j.util.ReadOnlyStringMap;
2625
import org.apache.logging.log4j.util.TriConsumer;
2726

@@ -35,7 +34,7 @@ public class ContextDataSerializer extends StdSerializer<ReadOnlyStringMap> {
3534
private static final long serialVersionUID = 1L;
3635

3736
protected ContextDataSerializer() {
38-
super(Map.class, false);
37+
super(ReadOnlyStringMap.class);
3938
}
4039

4140
@Override

log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,13 @@
1616
*/
1717
package org.apache.logging.log4j.core.jackson;
1818

19+
import static java.util.Collections.singletonList;
20+
import static java.util.Collections.singletonMap;
21+
1922
import com.fasterxml.jackson.databind.Module.SetupContext;
23+
import com.fasterxml.jackson.databind.module.SimpleDeserializers;
2024
import com.fasterxml.jackson.databind.module.SimpleModule;
25+
import com.fasterxml.jackson.databind.module.SimpleSerializers;
2126
import org.apache.logging.log4j.Level;
2227
import org.apache.logging.log4j.Marker;
2328
import org.apache.logging.log4j.ThreadContext.ContextStack;
@@ -27,6 +32,7 @@
2732
import org.apache.logging.log4j.core.time.Instant;
2833
import org.apache.logging.log4j.message.Message;
2934
import org.apache.logging.log4j.message.ObjectMessage;
35+
import org.apache.logging.log4j.util.StringMap;
3036

3137
/**
3238
* Initialization utils.
@@ -36,10 +42,7 @@
3642
*/
3743
class Initializers {
3844

39-
/**
40-
* Used to set up {@link SetupContext} from different {@link SimpleModule}s.
41-
*/
42-
static class SetupContextInitializer {
45+
private abstract static class AbstractInitializer {
4346

4447
void setupModule(
4548
final SetupContext context, final boolean includeStacktrace, final boolean stacktraceAsString) {
@@ -50,7 +53,7 @@ void setupModule(
5053
context.setMixInAnnotations(Marker.class, MarkerMixIn.class);
5154
context.setMixInAnnotations(Level.class, LevelMixIn.class);
5255
context.setMixInAnnotations(Instant.class, InstantMixIn.class);
53-
context.setMixInAnnotations(LogEvent.class, LogEventWithContextListMixIn.class);
56+
context.setMixInAnnotations(LogEvent.class, LogEventMixIn.class);
5457
// Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to.
5558
context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class);
5659
context.setMixInAnnotations(
@@ -62,33 +65,43 @@ void setupModule(
6265
: ThrowableProxyWithoutStacktraceMixIn.class);
6366
}
6467
}
68+
/**
69+
* Used to set up {@link SetupContext} from different {@link SimpleModule}s.
70+
* <p>
71+
* Serializes the context map as list of objects.
72+
* </p>
73+
*/
74+
static class SetupContextAsEntryListInitializer extends AbstractInitializer {
75+
76+
@Override
77+
void setupModule(
78+
final SetupContext context, final boolean includeStacktrace, final boolean stacktraceAsString) {
79+
super.setupModule(context, includeStacktrace, stacktraceAsString);
80+
// These classes don't have public constructors, so we instantiate them directly.
81+
// See https://github.com/apache/logging-log4j2/issues/2814
82+
context.addSerializers(new SimpleSerializers(singletonList(new ContextDataAsEntryListSerializer())));
83+
context.addDeserializers(
84+
new SimpleDeserializers(singletonMap(StringMap.class, new ContextDataAsEntryListDeserializer())));
85+
}
86+
}
6587

6688
/**
6789
* Used to set up {@link SetupContext} from different {@link SimpleModule}s.
68-
* Differs from SetupContextInitializer by installing {@code LogEventJsonMixIn} for LogEvents,
69-
* not {@code LogEventMixIn}, so it handles ThreadContext serialization differently.
90+
* <p>
91+
* Serializes the context map as object.
92+
* </p>
7093
*/
71-
static class SetupContextJsonInitializer {
94+
static class SetupContextInitializer extends AbstractInitializer {
7295

96+
@Override
7397
void setupModule(
7498
final SetupContext context, final boolean includeStacktrace, final boolean stacktraceAsString) {
75-
// JRE classes: we cannot edit those with Jackson annotations
76-
context.setMixInAnnotations(StackTraceElement.class, StackTraceElementMixIn.class);
77-
// Log4j API classes: we do not want to edit those with Jackson annotations because the API module should
78-
// not depend on Jackson.
79-
context.setMixInAnnotations(Marker.class, MarkerMixIn.class);
80-
context.setMixInAnnotations(Level.class, LevelMixIn.class);
81-
context.setMixInAnnotations(Instant.class, InstantMixIn.class);
82-
context.setMixInAnnotations(LogEvent.class, LogEventJsonMixIn.class); // different ThreadContext handling
83-
// Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to.
84-
context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class);
85-
context.setMixInAnnotations(
86-
ThrowableProxy.class,
87-
includeStacktrace
88-
? (stacktraceAsString
89-
? ThrowableProxyWithStacktraceAsStringMixIn.class
90-
: ThrowableProxyMixIn.class)
91-
: ThrowableProxyWithoutStacktraceMixIn.class);
99+
super.setupModule(context, includeStacktrace, stacktraceAsString);
100+
// These classes don't have public constructors, so we instantiate them directly.
101+
// See https://github.com/apache/logging-log4j2/issues/2814
102+
context.addSerializers(new SimpleSerializers(singletonList(new ContextDataSerializer())));
103+
context.addDeserializers(
104+
new SimpleDeserializers(singletonMap(StringMap.class, new ContextDataDeserializer())));
92105
}
93106
}
94107

log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,31 @@
1616
*/
1717
package org.apache.logging.log4j.core.jackson;
1818

19+
import aQute.bnd.annotation.baseline.BaselineIgnore;
20+
1921
/**
2022
* Keeps constants separate from any class that may depend on third party jars.
2123
*/
24+
@BaselineIgnore("2.24.0")
2225
public final class JsonConstants {
2326
public static final String ELT_CAUSE = "cause";
2427
public static final String ELT_CONTEXT_MAP = "contextMap";
2528
public static final String ELT_CONTEXT_STACK = "contextStack";
29+
public static final String ELT_END_OF_BATCH = "endOfBatch";
30+
public static final String ELT_LEVEL = "level";
31+
public static final String ELT_LOGGER_FQCN = "loggerFqcn";
32+
public static final String ELT_LOGGER_NAME = "loggerName";
2633
public static final String ELT_MARKER = "marker";
2734
public static final String ELT_PARENTS = "parents";
2835
public static final String ELT_SOURCE = "source";
2936
public static final String ELT_SUPPRESSED = "suppressed";
37+
public static final String ELT_THREAD = "thread";
3038
public static final String ELT_THROWN = "thrown";
3139
public static final String ELT_MESSAGE = "message";
3240
public static final String ELT_EXTENDED_STACK_TRACE = "extendedStackTrace";
3341
public static final String ELT_NANO_TIME = "nanoTime";
3442
public static final String ELT_INSTANT = "instant";
3543
public static final String ELT_TIME_MILLIS = "timeMillis";
44+
45+
private JsonConstants() {}
3646
}

log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonModule.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
import com.fasterxml.jackson.core.Version;
2020
import com.fasterxml.jackson.databind.module.SimpleModule;
21+
import org.apache.logging.log4j.core.jackson.Initializers.SetupContextAsEntryListInitializer;
2122
import org.apache.logging.log4j.core.jackson.Initializers.SetupContextInitializer;
22-
import org.apache.logging.log4j.core.jackson.Initializers.SetupContextJsonInitializer;
2323
import org.apache.logging.log4j.core.jackson.Initializers.SimpleModuleInitializer;
2424

2525
/**
@@ -33,7 +33,6 @@ class Log4jJsonModule extends SimpleModule {
3333
private final boolean encodeThreadContextAsList;
3434
private final boolean includeStacktrace;
3535
private final boolean stacktraceAsString;
36-
private final boolean objectMessageAsJsonObject;
3736

3837
Log4jJsonModule(
3938
final boolean encodeThreadContextAsList,
@@ -44,7 +43,6 @@ class Log4jJsonModule extends SimpleModule {
4443
this.encodeThreadContextAsList = encodeThreadContextAsList;
4544
this.includeStacktrace = includeStacktrace;
4645
this.stacktraceAsString = stacktraceAsString;
47-
this.objectMessageAsJsonObject = objectMessageAsJsonObject;
4846
// MUST init here.
4947
// Calling this from setupModule is too late!
5048
//noinspection ThisEscapedInObjectConstruction
@@ -56,9 +54,9 @@ public void setupModule(final SetupContext context) {
5654
// Calling super is a MUST!
5755
super.setupModule(context);
5856
if (encodeThreadContextAsList) {
59-
new SetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString);
57+
new SetupContextAsEntryListInitializer().setupModule(context, includeStacktrace, stacktraceAsString);
6058
} else {
61-
new SetupContextJsonInitializer().setupModule(context, includeStacktrace, stacktraceAsString);
59+
new SetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString);
6260
}
6361
}
6462
}

log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jXmlModule.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package org.apache.logging.log4j.core.jackson;
1818

1919
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
20-
import org.apache.logging.log4j.core.jackson.Initializers.SetupContextInitializer;
20+
import org.apache.logging.log4j.core.jackson.Initializers.SetupContextAsEntryListInitializer;
2121
import org.apache.logging.log4j.core.jackson.Initializers.SimpleModuleInitializer;
2222

2323
/**
@@ -43,6 +43,6 @@ final class Log4jXmlModule extends JacksonXmlModule {
4343
public void setupModule(final SetupContext context) {
4444
// Calling super is a MUST!
4545
super.setupModule(context);
46-
new SetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString);
46+
new SetupContextAsEntryListInitializer().setupModule(context, includeStacktrace, stacktraceAsString);
4747
}
4848
}

log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlModule.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
import com.fasterxml.jackson.core.Version;
2020
import com.fasterxml.jackson.databind.module.SimpleModule;
21+
import org.apache.logging.log4j.core.jackson.Initializers.SetupContextAsEntryListInitializer;
2122
import org.apache.logging.log4j.core.jackson.Initializers.SetupContextInitializer;
22-
import org.apache.logging.log4j.core.jackson.Initializers.SetupContextJsonInitializer;
2323
import org.apache.logging.log4j.core.jackson.Initializers.SimpleModuleInitializer;
2424

2525
/**
@@ -53,9 +53,9 @@ public void setupModule(final SetupContext context) {
5353
// Calling super is a MUST!
5454
super.setupModule(context);
5555
if (encodeThreadContextAsList) {
56-
new SetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString);
56+
new SetupContextAsEntryListInitializer().setupModule(context, includeStacktrace, stacktraceAsString);
5757
} else {
58-
new SetupContextJsonInitializer().setupModule(context, includeStacktrace, stacktraceAsString);
58+
new SetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString);
5959
}
6060
}
6161
}

0 commit comments

Comments
 (0)