http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java
 
b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java
new file mode 100644
index 0000000..224cfb4
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java
@@ -0,0 +1,327 @@
+/*
+ * 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.jackson.json.layout;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.util.KeyValuePair;
+import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
+import org.apache.logging.log4j.jackson.XmlConstants;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+
+/**
+ * Appends a series of JSON events as strings serialized as bytes.
+ *
+ * <h3>Complete well-formed JSON vs. fragment JSON</h3>
+ * <p>
+ * If you configure {@code complete="true"}, the appender outputs a 
well-formed JSON document. By default, with
+ * {@code complete="false"}, you should include the output as an <em>external 
file</em> in a separate file to form a
+ * well-formed JSON document.
+ * </p>
+ * <p>
+ * If {@code complete="false"}, the appender does not write the JSON open 
array character "[" at the start
+ * of the document, "]" and the end, nor comma "," between records.
+ * </p>
+ * <h3>Encoding</h3>
+ * <p>
+ * Appenders using this layout should have their {@code charset} set to {@code 
UTF-8} or {@code UTF-16}, otherwise
+ * events containing non ASCII characters could result in corrupted log files.
+ * </p>
+ * <h3>Pretty vs. compact JSON</h3>
+ * <p>
+ * By default, the JSON layout is not compact (a.k.a. "pretty") with {@code 
compact="false"}, which means the
+ * appender uses end-of-line characters and indents lines to format the text. 
If {@code compact="true"}, then no
+ * end-of-line or indentation is used. Message content may contain, of course, 
escaped end-of-lines.
+ * </p>
+ * <h3>Additional Fields</h3>
+ * <p>
+ * This property allows addition of custom fields into generated JSON.
+ * {@code <JsonLayout><KeyValuePair key="foo" value="bar"/></JsonLayout>} 
inserts {@code "foo":"bar"} directly
+ * into JSON output. Supports Lookup expressions.
+ * </p>
+ */
+@Plugin(name = "JsonLayout", category = Node.CATEGORY, elementType = 
Layout.ELEMENT_TYPE, printObject = true)
+public final class JsonLayout extends AbstractJacksonLayout {
+
+    public static class Builder<B extends Builder<B>> extends 
AbstractJacksonLayout.Builder<B>
+            implements org.apache.logging.log4j.core.util.Builder<JsonLayout> {
+
+        @PluginBuilderAttribute
+        private boolean propertiesAsList;
+
+        @PluginBuilderAttribute
+        private boolean objectMessageAsJsonObject;
+
+        @PluginElement("AdditionalField")
+        private KeyValuePair[] additionalFields;
+
+        public Builder() {
+            super();
+            setCharset(StandardCharsets.UTF_8);
+        }
+
+        @Override
+        public JsonLayout build() {
+            final boolean encodeThreadContextAsList = isProperties() && 
propertiesAsList;
+            final String headerPattern = toStringOrNull(getHeader());
+            final String footerPattern = toStringOrNull(getFooter());
+            return new JsonLayout(getConfiguration(), isLocationInfo(), 
isProperties(), encodeThreadContextAsList,
+                    isComplete(), isCompact(), getEventEol(), headerPattern, 
footerPattern, getCharset(),
+                    isIncludeStacktrace(), isStacktraceAsString(), 
isIncludeNullDelimiter(),
+                    getAdditionalFields(), getObjectMessageAsJsonObject());
+        }
+
+        @Override
+        public KeyValuePair[] getAdditionalFields() {
+            return additionalFields;
+        }
+
+        public boolean getObjectMessageAsJsonObject() {
+            return objectMessageAsJsonObject;
+        }
+
+        public boolean isPropertiesAsList() {
+            return propertiesAsList;
+        }
+
+        @Override
+        public B setAdditionalFields(final KeyValuePair[] additionalFields) {
+            this.additionalFields = additionalFields;
+            return asBuilder();
+        }
+
+        public B setObjectMessageAsJsonObject(final boolean 
objectMessageAsJsonObject) {
+            this.objectMessageAsJsonObject = objectMessageAsJsonObject;
+            return asBuilder();
+        }
+
+        public B setPropertiesAsList(final boolean propertiesAsList) {
+            this.propertiesAsList = propertiesAsList;
+            return asBuilder();
+        }
+    }
+
+    @JsonRootName(XmlConstants.ELT_EVENT)
+    public static class JsonLogEventWithAdditionalFields extends 
LogEventWithAdditionalFields {
+
+        public JsonLogEventWithAdditionalFields(final Object logEvent, final 
Map<String, String> additionalFields) {
+            super(logEvent, additionalFields);
+        }
+
+        @Override
+        @JsonAnyGetter
+        public Map<String, String> getAdditionalFields() {
+            return super.getAdditionalFields();
+        }
+
+        @Override
+        @JsonUnwrapped
+        public Object getLogEvent() {
+            return super.getLogEvent();
+        }
+    }
+
+    private static final String DEFAULT_FOOTER = "]";
+
+    private static final String DEFAULT_HEADER = "[";
+
+
+    static final String CONTENT_TYPE = "application/json";
+
+    /**
+     * Creates a JSON Layout using the default settings. Useful for testing.
+     *
+     * @return A JSON Layout.
+     */
+    public static JsonLayout createDefaultLayout() {
+        return new JsonLayout(new DefaultConfiguration(), false, false, false, 
false, false, false,
+                DEFAULT_HEADER, DEFAULT_FOOTER, StandardCharsets.UTF_8, true, 
false, false, null, false);
+    }
+
+    /**
+     * Creates a JSON Layout.
+     * @param config
+     *           The plugin configuration.
+     * @param locationInfo
+     *            If "true", includes the location information in the 
generated JSON.
+     * @param properties
+     *            If "true", includes the thread context map in the generated 
JSON.
+     * @param propertiesAsList
+     *            If true, the thread context map is included as a list of map 
entry objects, where each entry has
+     *            a "key" attribute (whose value is the key) and a "value" 
attribute (whose value is the value).
+     *            Defaults to false, in which case the thread context map is 
included as a simple map of key-value
+     *            pairs.
+     * @param complete
+     *            If "true", includes the JSON header and footer, and comma 
between records.
+     * @param compact
+     *            If "true", does not use end-of-lines and indentation, 
defaults to "false".
+     * @param eventEol
+     *            If "true", forces an EOL after each log event (even if 
compact is "true"), defaults to "false". This
+     *            allows one even per line, even in compact mode.
+     * @param headerPattern
+     *            The header pattern, defaults to {@code "["} if null.
+     * @param footerPattern
+     *            The header pattern, defaults to {@code "]"} if null.
+     * @param charset
+     *            The character set to use, if {@code null}, uses "UTF-8".
+     * @param includeStacktrace
+     *            If "true", includes the stacktrace of any Throwable in the 
generated JSON, defaults to "true".
+     * @return A JSON Layout.
+     *
+     * @deprecated Use {@link #newBuilder()} instead
+     */
+    @Deprecated
+    public static JsonLayout createLayout(
+            final Configuration config,
+            final boolean locationInfo,
+            final boolean properties,
+            final boolean propertiesAsList,
+            final boolean complete,
+            final boolean compact,
+            final boolean eventEol,
+            final String headerPattern,
+            final String footerPattern,
+            final Charset charset,
+            final boolean includeStacktrace) {
+        final boolean encodeThreadContextAsList = properties && 
propertiesAsList;
+        return new JsonLayout(config, locationInfo, properties, 
encodeThreadContextAsList, complete, compact, eventEol,
+                headerPattern, footerPattern, charset, includeStacktrace, 
false, false, null, false);
+    }
+
+    @PluginBuilderFactory
+    public static <B extends Builder<B>> B newBuilder() {
+        return new Builder<B>().asBuilder();
+    }
+
+    /**
+     * @deprecated Use {@link #newBuilder()} instead
+     */
+    @Deprecated
+    protected JsonLayout(final Configuration config, final boolean 
locationInfo, final boolean properties,
+            final boolean encodeThreadContextAsList,
+            final boolean complete, final boolean compact, final boolean 
eventEol, final String headerPattern,
+            final String footerPattern, final Charset charset, final boolean 
includeStacktrace) {
+        super(config, new JsonJacksonFactory(encodeThreadContextAsList, 
includeStacktrace, false, false).newWriter(
+                locationInfo, properties, compact),
+                charset, compact, complete, eventEol,
+                
PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern(DEFAULT_HEADER).build(),
+                
PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern(DEFAULT_FOOTER).build(),
+                false, null);
+    }
+
+    private JsonLayout(final Configuration config, final boolean locationInfo, 
final boolean properties,
+                       final boolean encodeThreadContextAsList,
+                       final boolean complete, final boolean compact, final 
boolean eventEol,
+                       final String headerPattern, final String footerPattern, 
final Charset charset,
+                       final boolean includeStacktrace, final boolean 
stacktraceAsString,
+                       final boolean includeNullDelimiter,
+                       final KeyValuePair[] additionalFields, final boolean 
objectMessageAsJsonObject) {
+        super(config, new JsonJacksonFactory(encodeThreadContextAsList, 
includeStacktrace, stacktraceAsString, objectMessageAsJsonObject).newWriter(
+                locationInfo, properties, compact),
+                charset, compact, complete, eventEol,
+                
PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern(DEFAULT_HEADER).build(),
+                
PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern(DEFAULT_FOOTER).build(),
+                includeNullDelimiter,
+                additionalFields);
+    }
+
+    @Override
+    protected LogEventWithAdditionalFields 
createLogEventWithAdditionalFields(final LogEvent event,
+            final Map<String, String> additionalFieldsMap) {
+        return new JsonLogEventWithAdditionalFields(event, 
additionalFieldsMap);
+    }
+
+    @Override
+    public Map<String, String> getContentFormat() {
+        final Map<String, String> result = new HashMap<>();
+        result.put("version", "2.0");
+        return result;
+    }
+
+    /**
+     * @return The content type.
+     */
+    @Override
+    public String getContentType() {
+        return CONTENT_TYPE + "; charset=" + this.getCharset();
+    }
+
+    /**
+     * Returns appropriate JSON footer.
+     *
+     * @return a byte array containing the footer, closing the JSON array.
+     */
+    @Override
+    public byte[] getFooter() {
+        if (!this.complete) {
+            return null;
+        }
+        final StringBuilder buf = new StringBuilder();
+        buf.append(this.eol);
+        final String str = serializeToString(getFooterSerializer());
+        if (str != null) {
+            buf.append(str);
+        }
+        buf.append(this.eol);
+        return getBytes(buf.toString());
+    }
+
+    /**
+     * Returns appropriate JSON header.
+     *
+     * @return a byte array containing the header, opening the JSON array.
+     */
+    @Override
+    public byte[] getHeader() {
+        if (!this.complete) {
+            return null;
+        }
+        final StringBuilder buf = new StringBuilder();
+        final String str = serializeToString(getHeaderSerializer());
+        if (str != null) {
+            buf.append(str);
+        }
+        buf.append(this.eol);
+        return getBytes(buf.toString());
+    }
+
+    @Override
+    public void toSerializable(final LogEvent event, final Writer writer) 
throws IOException {
+        if (complete && eventCount > 0) {
+            writer.append(", ");
+        }
+        super.toSerializable(event, writer);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParser.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParser.java
 
b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParser.java
new file mode 100644
index 0000000..28279d1
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParser.java
@@ -0,0 +1,32 @@
+/*
+ * 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.jackson.json.parser;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.parser.AbstractJacksonLogEventParser;
+import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper;
+
+/**
+ * Parses the output from XmlLayout layout into instances of {@link LogEvent}.
+ */
+public class JsonLogEventParser extends AbstractJacksonLogEventParser {
+
+    public JsonLogEventParser() {
+        super(new Log4jJsonObjectMapper());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/site/manual/index.md
----------------------------------------------------------------------
diff --git a/log4j-layout-jackson-json/src/site/manual/index.md 
b/log4j-layout-jackson-json/src/site/manual/index.md
new file mode 100644
index 0000000..6cadb78
--- /dev/null
+++ b/log4j-layout-jackson-json/src/site/manual/index.md
@@ -0,0 +1,33 @@
+<!-- vim: set syn=markdown : -->
+<!--
+    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.
+-->
+
+# Apache Log4j Layout for Jackson JSON module
+
+As of Log4j 3.0.0, the layout based on Jackson JSON has moved from the 
existing module logj-core to the new modules log4j-layout-jackson-json.
+
+## Requirements
+
+This module was introduced in Log4j 2.11.0 and requires Jackson.
+
+Some features may require optional
+[dependencies](../runtime-dependencies.html). These dependencies are specified 
in the
+documentation for those features.
+
+Some Log4j features require external dependencies.
+See the [Dependency Tree](dependencies.html#Dependency_Tree)
+for the exact list of JAR files needed for these features.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/site/site.xml
----------------------------------------------------------------------
diff --git a/log4j-layout-jackson-json/src/site/site.xml 
b/log4j-layout-jackson-json/src/site/site.xml
new file mode 100644
index 0000000..6d4cddc
--- /dev/null
+++ b/log4j-layout-jackson-json/src/site/site.xml
@@ -0,0 +1,52 @@
+<!--
+ 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.
+
+-->
+<project name="Log4j Core"
+         xmlns="http://maven.apache.org/DECORATION/1.4.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 
http://maven.apache.org/xsd/decoration-1.4.0.xsd";>
+  <body>
+    <links>
+      <item name="Apache" href="http://www.apache.org/"; />
+      <item name="Logging Services" href="http://logging.apache.org/"/>
+      <item name="Log4j" href="../index.html"/>
+    </links>
+
+    <!-- Component-specific reports -->
+    <menu ref="reports"/>
+
+       <!-- Overall Project Info -->
+    <menu name="Log4j Project Information" img="icon-info-sign">
+      <item name="Dependencies" href="../dependencies.html" />
+      <item name="Dependency Convergence" 
href="../dependency-convergence.html" />
+      <item name="Dependency Management" href="../dependency-management.html" 
/>
+      <item name="Project Team" href="../team-list.html" />
+      <item name="Mailing Lists" href="../mail-lists.html" />
+      <item name="Issue Tracking" href="../issue-tracking.html" />
+      <item name="Project License" href="../license.html" />
+      <item name="Source Repository" href="../source-repository.html" />
+      <item name="Project Summary" href="../project-summary.html" />
+    </menu>
+
+    <menu name="Log4j Project Reports" img="icon-cog">
+      <item name="Changes Report" href="../changes-report.html" />
+      <item name="JIRA Report" href="../jira-report.html" />
+      <item name="Surefire Report" href="../surefire-report.html" />
+      <item name="RAT Report" href="../rat-report.html" />
+    </menu>
+  </body>
+</project>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429MyNamesTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429MyNamesTest.java
 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429MyNamesTest.java
new file mode 100644
index 0000000..acc15c2
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429MyNamesTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.jackson.json;
+
+import java.io.IOException;
+
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+@Category(Layouts.Json.class)
+public class JacksonIssue429MyNamesTest {
+
+    @SuppressWarnings("serial")
+    static class MyStackTraceElementDeserializer extends 
StdScalarDeserializer<StackTraceElement> {
+        private static final long serialVersionUID = 1L;
+
+        public final static MyStackTraceElementDeserializer instance = new 
MyStackTraceElementDeserializer();
+
+        public MyStackTraceElementDeserializer() {
+            super(StackTraceElement.class);
+        }
+
+        @Override
+        public StackTraceElement deserialize(final JsonParser jp, final 
DeserializationContext ctxt) throws IOException,
+                JsonProcessingException {
+            JsonToken t = jp.getCurrentToken();
+            // Must get an Object
+            if (t == JsonToken.START_OBJECT) {
+                String className = Strings.EMPTY, methodName = Strings.EMPTY, 
fileName = Strings.EMPTY;
+                int lineNumber = -1;
+
+                while ((t = jp.nextValue()) != JsonToken.END_OBJECT) {
+                    final String propName = jp.getCurrentName();
+                    if ("class".equals(propName)) {
+                        className = jp.getText();
+                    } else if ("file".equals(propName)) {
+                        fileName = jp.getText();
+                    } else if ("line".equals(propName)) {
+                        if (t.isNumeric()) {
+                            lineNumber = jp.getIntValue();
+                        } else {
+                            throw JsonMappingException.from(jp, "Non-numeric 
token (" + t
+                                    + ") for property 'lineNumber'");
+                        }
+                    } else if ("method".equals(propName)) {
+                        methodName = jp.getText();
+                    } else if ("nativeMethod".equals(propName)) {
+                        // no setter, not passed via constructor: ignore
+                    } else {
+                        handleUnknownProperty(jp, ctxt, _valueClass, propName);
+                    }
+                }
+                return new StackTraceElement(className, methodName, fileName, 
lineNumber);
+            }
+            throw ctxt.mappingException(_valueClass, t);
+        }
+    }
+
+    static class StackTraceBean {
+        public final static int NUM = 13;
+
+        @JsonProperty("Location")
+        @JsonDeserialize(using = MyStackTraceElementDeserializer.class)
+        private StackTraceElement location;
+    }
+
+    private final static ObjectMapper SHARED_MAPPER = new ObjectMapper();
+
+    private final ObjectMapper MAPPER = objectMapper();
+
+    protected String aposToQuotes(final String json) {
+        return json.replace("'", "\"");
+    }
+
+    protected ObjectMapper objectMapper() {
+        return SHARED_MAPPER;
+    }
+
+    @Test
+    public void testStackTraceElementWithCustom() throws Exception {
+        // first, via bean that contains StackTraceElement
+        final StackTraceBean bean = MAPPER
+                .readValue(
+                        
aposToQuotes("{'Location':{'class':'package.SomeClass','method':'someMethod','file':'SomeClass.java','line':13}}"),
+                        StackTraceBean.class);
+        Assert.assertNotNull(bean);
+        Assert.assertNotNull(bean.location);
+        Assert.assertEquals(StackTraceBean.NUM, bean.location.getLineNumber());
+
+        // and then directly, iff registered
+        final ObjectMapper mapper = new ObjectMapper();
+        final SimpleModule module = new SimpleModule();
+        module.addDeserializer(StackTraceElement.class, new 
MyStackTraceElementDeserializer());
+        mapper.registerModule(module);
+
+        final StackTraceElement elem = mapper.readValue(
+                
aposToQuotes("{'class':'package.SomeClass','method':'someMethod','file':'SomeClass.java','line':13}"),
+                StackTraceElement.class);
+        Assert.assertNotNull(elem);
+        Assert.assertEquals(StackTraceBean.NUM, elem.getLineNumber());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429Test.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429Test.java
 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429Test.java
new file mode 100644
index 0000000..93d1d53
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429Test.java
@@ -0,0 +1,95 @@
+/*
+ * 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.jackson.json;
+
+import java.io.IOException;
+
+import org.apache.logging.log4j.categories.Layouts;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+@Category(Layouts.Json.class)
+public class JacksonIssue429Test {
+
+    @SuppressWarnings("serial")
+    static class Jackson429StackTraceElementDeserializer extends 
StdDeserializer<StackTraceElement> {
+        private static final long serialVersionUID = 1L;
+
+        public Jackson429StackTraceElementDeserializer() {
+            super(StackTraceElement.class);
+        }
+
+        @Override
+        public StackTraceElement deserialize(final JsonParser jp, final 
DeserializationContext ctxt) throws IOException,
+                JsonProcessingException {
+            jp.skipChildren();
+            return new StackTraceElement("a", "b", "b", StackTraceBean.NUM);
+        }
+
+    }
+
+    static class StackTraceBean {
+        public final static int NUM = 13;
+
+        @JsonProperty("Location")
+        @JsonDeserialize(using = Jackson429StackTraceElementDeserializer.class)
+        private StackTraceElement location;
+    }
+
+    private final static ObjectMapper SHARED_MAPPER = new ObjectMapper();
+
+    private final ObjectMapper MAPPER = objectMapper();
+
+    protected String aposToQuotes(final String json) {
+        return json.replace("'", "\"");
+    }
+
+    protected ObjectMapper objectMapper() {
+        return SHARED_MAPPER;
+    }
+
+    @Test
+    public void testStackTraceElementWithCustom() throws Exception {
+        // first, via bean that contains StackTraceElement
+        final StackTraceBean bean = 
MAPPER.readValue(aposToQuotes("{'Location':'foobar'}"), StackTraceBean.class);
+        Assert.assertNotNull(bean);
+        Assert.assertNotNull(bean.location);
+        Assert.assertEquals(StackTraceBean.NUM, bean.location.getLineNumber());
+
+        // and then directly, iff registered
+        final ObjectMapper mapper = new ObjectMapper();
+        final SimpleModule module = new SimpleModule();
+        module.addDeserializer(StackTraceElement.class, new 
Jackson429StackTraceElementDeserializer());
+        mapper.registerModule(module);
+
+        final StackTraceElement elem = mapper.readValue(
+                
aposToQuotes("{'class':'package.SomeClass','method':'someMethod','file':'SomeClass.java','line':123}"),
+                StackTraceElement.class);
+        Assert.assertNotNull(elem);
+        Assert.assertEquals(StackTraceBean.NUM, elem.getLineNumber());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/LevelMixInJsonTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/LevelMixInJsonTest.java
 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/LevelMixInJsonTest.java
new file mode 100644
index 0000000..7f75148
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/LevelMixInJsonTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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.jackson.json;
+
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.jackson.LevelMixInTest;
+import org.junit.experimental.categories.Category;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@Category(Layouts.Json.class)
+public class LevelMixInJsonTest extends LevelMixInTest {
+
+    @Override
+    protected ObjectMapper newObjectMapper() {
+        return new Log4jJsonObjectMapper(false, true, false, false);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/MarkerMixInJsonTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/MarkerMixInJsonTest.java
 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/MarkerMixInJsonTest.java
new file mode 100644
index 0000000..db9588b
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/MarkerMixInJsonTest.java
@@ -0,0 +1,34 @@
+/*
+* 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.jackson.json;
+
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.jackson.AbstractMarkerMixInTest;
+import org.junit.experimental.categories.Category;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@Category(Layouts.Json.class)
+public class MarkerMixInJsonTest extends AbstractMarkerMixInTest {
+
+    @Override
+    protected ObjectMapper newObjectMapper() {
+        return new Log4jJsonObjectMapper();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/StackTraceElementJsonMixInTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/StackTraceElementJsonMixInTest.java
 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/StackTraceElementJsonMixInTest.java
new file mode 100644
index 0000000..fc0b459
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/StackTraceElementJsonMixInTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.jackson.json;
+
+import java.io.IOException;
+
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.jackson.Log4jStackTraceElementDeserializer;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+@Category(Layouts.Json.class)
+public class StackTraceElementJsonMixInTest {
+
+    protected String aposToQuotes(final String json) {
+        return json.replace("'", "\"");
+    }
+
+    /**
+     * @param mapper
+     * @throws JsonProcessingException
+     * @throws IOException
+     * @throws JsonParseException
+     * @throws JsonMappingException
+     */
+    private void roundtrip(final ObjectMapper mapper) throws 
JsonProcessingException, IOException, JsonParseException, JsonMappingException {
+        final StackTraceElement expected = new 
StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", 123);
+        final String s = mapper.writeValueAsString(expected);
+        final StackTraceElement actual = mapper.readValue(s, 
StackTraceElement.class);
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testFromJsonWithLog4jModule() throws Exception {
+        final ObjectMapper mapper = new ObjectMapper();
+        final boolean encodeThreadContextAsList = false;
+        final SimpleModule module = new 
Log4jJsonModule(encodeThreadContextAsList, true, false, false);
+        module.addDeserializer(StackTraceElement.class, new 
Log4jStackTraceElementDeserializer());
+        mapper.registerModule(module);
+        final StackTraceElement expected = new 
StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", 123);
+        final String s = 
this.aposToQuotes("{'class':'package.SomeClass','method':'someMethod','file':'SomeClass.java','line':123}");
+        final StackTraceElement actual = mapper.readValue(s, 
StackTraceElement.class);
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testFromJsonWithSimpleModule() throws Exception {
+        final ObjectMapper mapper = new ObjectMapper();
+        final SimpleModule module = new SimpleModule();
+        module.addDeserializer(StackTraceElement.class, new 
Log4jStackTraceElementDeserializer());
+        mapper.registerModule(module);
+        final StackTraceElement expected = new 
StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", 123);
+        final String s = 
this.aposToQuotes("{'class':'package.SomeClass','method':'someMethod','file':'SomeClass.java','line':123}");
+        final StackTraceElement actual = mapper.readValue(s, 
StackTraceElement.class);
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testLog4jJsonObjectMapper() throws Exception {
+        this.roundtrip(new Log4jJsonObjectMapper());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ConcurrentLoggingWithJsonLayoutTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ConcurrentLoggingWithJsonLayoutTest.java
 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ConcurrentLoggingWithJsonLayoutTest.java
new file mode 100644
index 0000000..5d6f02d
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ConcurrentLoggingWithJsonLayoutTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.jackson.json.layout;
+
+import static org.hamcrest.CoreMatchers.endsWith;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.AfterClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+/**
+ * Test for LOG4J2-1769.
+ *
+ * @since 2.8
+ */
+public class ConcurrentLoggingWithJsonLayoutTest {
+
+    private class LoggingThread extends Thread {
+        private final Set<Thread> threads;
+        private final Logger log;
+
+        LoggingThread(final Set<Thread> threads, final Logger log) {
+            this.threads = threads;
+            this.log = log;
+        }
+
+        @Override
+        public void run() {
+            log.info(threads.size());
+            try {
+                for (int i = 0; i < 64; i++) {
+                    log.info("First message.");
+                    log.info("Second message.");
+                }
+            } finally {
+                threads.remove(this);
+            }
+        }
+    }
+    @ClassRule
+    public static LoggerContextRule context = new 
LoggerContextRule("log4j2-json-layout.xml");
+
+    private static final String PATH = "target/test-json-layout.log";
+
+    @AfterClass
+    public static void after() {
+        new File(PATH).delete();
+    }
+
+    @Test
+    public void testConcurrentLogging() throws Throwable {
+        final Logger log = 
context.getLogger(ConcurrentLoggingWithJsonLayoutTest.class);
+        final Set<Thread> threads = Collections.synchronizedSet(new 
HashSet<Thread>());
+        final List<Throwable> thrown = Collections.synchronizedList(new 
ArrayList<Throwable>());
+
+        for (int x = 0; x < Runtime.getRuntime().availableProcessors() * 2; 
x++) {
+            final Thread t = new LoggingThread(threads, log);
+            threads.add(t);
+
+            // Appender is configured with ignoreExceptions="false";
+            // any exceptions are propagated to the caller, so we can catch 
them here.
+            t.setUncaughtExceptionHandler(new 
Thread.UncaughtExceptionHandler() {
+                @Override
+                public void uncaughtException(final Thread t, final Throwable 
e) {
+                    thrown.add(e);
+                }
+            });
+            t.start();
+        }
+
+        while (!threads.isEmpty()) {
+            log.info("not done going to sleep...");
+            Thread.sleep(10);
+        }
+
+        // if any error occurred, fail this test
+        if (!thrown.isEmpty()) {
+            throw thrown.get(0);
+        }
+
+        // simple test to ensure content is not corrupted
+        if (new File(PATH).exists()) {
+            final List<String> lines = Files.readAllLines(new 
File(PATH).toPath(), Charset.defaultCharset());
+            for (final String line : lines) {
+                assertThat(line, startsWith("{\"thread\":"));
+                assertThat(line, endsWith("\"threadPriority\":5}"));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java
 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java
new file mode 100644
index 0000000..f8afb51
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java
@@ -0,0 +1,489 @@
+/*
+ * 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.jackson.json.layout;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.categories.Layouts;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.BasicConfigurationFactory;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.layout.LogEventFixtures;
+import org.apache.logging.log4j.core.lookup.JavaLookup;
+import org.apache.logging.log4j.core.util.KeyValuePair;
+import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
+import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper;
+import org.apache.logging.log4j.message.ObjectMessage;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.spi.AbstractLogger;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * Tests the JsonLayout class.
+ */
+@Category(Layouts.Json.class)
+public class JsonLayoutTest {
+    private static class TestClass {
+               private int value;
+
+               public int getValue() {
+                       return value;
+               }
+
+               public void setValue(final int value) {
+                       this.value = value;
+               }
+       }
+
+    static ConfigurationFactory cf = new BasicConfigurationFactory();
+
+    private static final String DQUOTE = "\"";
+
+    @AfterClass
+    public static void cleanupClass() {
+        ConfigurationFactory.removeConfigurationFactory(cf);
+        ThreadContext.clearAll();
+    }
+
+    @BeforeClass
+    public static void setupClass() {
+        ThreadContext.clearAll();
+        ConfigurationFactory.setConfigurationFactory(cf);
+        final LoggerContext ctx = LoggerContext.getContext();
+        ctx.reconfigure();
+    }
+
+    LoggerContext ctx = LoggerContext.getContext();
+
+    Logger rootLogger = this.ctx.getRootLogger();
+
+    private void checkAt(final String expected, final int lineIndex, final 
List<String> list) {
+        final String trimedLine = list.get(lineIndex).trim();
+        assertTrue("Incorrect line index " + lineIndex + ": " + 
Strings.dquote(trimedLine), trimedLine.equals(expected));
+    }
+
+    private void checkContains(final String expected, final List<String> list) 
{
+        for (final String string : list) {
+            final String trimedLine = string.trim();
+            if (trimedLine.equals(expected)) {
+                return;
+            }
+        }
+        Assert.fail("Cannot find " + expected + " in " + list);
+    }
+
+    private void checkMapEntry(final String key, final String value, final 
boolean compact, final String str,
+            final boolean contextMapAslist) {
+        this.toPropertySeparator(compact);
+        if (contextMapAslist) {
+            // {"key":"KEY", "value":"VALUE"}
+            final String expected = 
String.format("{\"key\":\"%s\",\"value\":\"%s\"}", key, value);
+            assertTrue("Cannot find contextMapAslist " + expected + " in " + 
str, str.contains(expected));
+        } else {
+            // "KEY":"VALUE"
+            final String expected = String.format("\"%s\":\"%s\"", key, value);
+            assertTrue("Cannot find contextMap " + expected + " in " + str, 
str.contains(expected));
+        }
+    }
+
+    private void checkProperty(final String key, final String value, final 
boolean compact, final String str) {
+        final String propSep = this.toPropertySeparator(compact);
+        // {"key":"MDC.B","value":"B_Value"}
+        final String expected = String.format("\"%s\"%s\"%s\"", key, propSep, 
value);
+        assertTrue("Cannot find " + expected + " in " + str, 
str.contains(expected));
+    }
+
+    private void checkPropertyName(final String name, final boolean compact, 
final String str) {
+        final String propSep = this.toPropertySeparator(compact);
+        assertTrue(str, str.contains(DQUOTE + name + DQUOTE + propSep));
+    }
+
+    private void checkPropertyNameAbsent(final String name, final boolean 
compact, final String str) {
+        final String propSep = this.toPropertySeparator(compact);
+        assertFalse(str, str.contains(DQUOTE + name + DQUOTE + propSep));
+    }
+
+    private String prepareJsonForObjectMessageAsJsonObjectTests(final int 
value, final boolean objectMessageAsJsonObject) {
+       final TestClass testClass = new TestClass();
+               testClass.setValue(value);
+               // @formatter:off
+               final Log4jLogEvent expected = Log4jLogEvent.newBuilder()
+            .setLoggerName("a.B")
+            .setLoggerFqcn("f.q.c.n")
+            .setLevel(Level.DEBUG)
+            .setMessage(new ObjectMessage(testClass))
+            .setThreadName("threadName")
+            .setTimeMillis(1).build();
+        // @formatter:off
+               final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+                               .setCompact(true)
+                               
.setObjectMessageAsJsonObject(objectMessageAsJsonObject)
+                               .build();
+        // @formatter:off
+        return layout.toSerializable(expected);
+    }
+
+    private String prepareJsonForStacktraceTests(final boolean 
stacktraceAsString) {
+        final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
+        // @formatter:off
+        final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+                .setCompact(true)
+                .setIncludeStacktrace(true)
+                .setStacktraceAsString(stacktraceAsString)
+                .build();
+        // @formatter:off
+        return layout.toSerializable(expected);
+    }
+
+    @Test
+    public void testAdditionalFields() throws Exception {
+        final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+                .setLocationInfo(false)
+                .setProperties(false)
+                .setComplete(false)
+                .setCompact(true)
+                .setEventEol(false)
+                .setIncludeStacktrace(false)
+                .setAdditionalFields(new KeyValuePair[] {
+                    new KeyValuePair("KEY1", "VALUE1"),
+                    new KeyValuePair("KEY2", "${java:runtime}"), })
+                .setCharset(StandardCharsets.UTF_8)
+                .setConfiguration(ctx.getConfiguration())
+                .build();
+        final String str = 
layout.toSerializable(LogEventFixtures.createLogEvent());
+        assertTrue(str, str.contains("\"KEY1\":\"VALUE1\""));
+        assertTrue(str, str.contains("\"KEY2\":\"" + new 
JavaLookup().getRuntime() + "\""));
+    }
+
+    private void testAllFeatures(final boolean locationInfo, final boolean 
compact, final boolean eventEol,
+            final boolean includeContext, final boolean contextMapAslist, 
final boolean includeStacktrace)
+            throws Exception {
+        final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
+        // @formatter:off
+        final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+                .setLocationInfo(locationInfo)
+                .setProperties(includeContext)
+                .setPropertiesAsList(contextMapAslist)
+                .setComplete(false)
+                .setCompact(compact)
+                .setEventEol(eventEol)
+                .setCharset(StandardCharsets.UTF_8)
+                .setIncludeStacktrace(includeStacktrace)
+                .build();
+        // @formatter:off
+        final String str = layout.toSerializable(expected);
+        this.toPropertySeparator(compact);
+        // Just check for \n since \r might or might not be there.
+        assertEquals(str, !compact || eventEol, str.contains("\n"));
+        assertEquals(str, locationInfo, str.contains("source"));
+        assertEquals(str, includeContext, str.contains("contextMap"));
+        final Log4jLogEvent actual = new 
Log4jJsonObjectMapper(contextMapAslist, includeStacktrace, false, 
false).readValue(str, Log4jLogEvent.class);
+        LogEventFixtures.assertEqualLogEvents(expected, actual, locationInfo, 
includeContext, includeStacktrace);
+        if (includeContext) {
+            this.checkMapEntry("MDC.A", "A_Value", compact, str, 
contextMapAslist);
+            this.checkMapEntry("MDC.B", "B_Value", compact, str, 
contextMapAslist);
+        }
+        //
+        assertNull(actual.getThrown());
+        // make sure the names we want are used
+        this.checkPropertyName("instant", compact, str);
+        this.checkPropertyName("thread", compact, str); // and not threadName
+        this.checkPropertyName("level", compact, str);
+        this.checkPropertyName("loggerName", compact, str);
+        this.checkPropertyName("marker", compact, str);
+        this.checkPropertyName("name", compact, str);
+        this.checkPropertyName("parents", compact, str);
+        this.checkPropertyName("message", compact, str);
+        this.checkPropertyName("thrown", compact, str);
+        this.checkPropertyName("cause", compact, str);
+        this.checkPropertyName("commonElementCount", compact, str);
+        this.checkPropertyName("localizedMessage", compact, str);
+        if (includeStacktrace) {
+            this.checkPropertyName("extendedStackTrace", compact, str);
+            this.checkPropertyName("class", compact, str);
+            this.checkPropertyName("method", compact, str);
+            this.checkPropertyName("file", compact, str);
+            this.checkPropertyName("line", compact, str);
+            this.checkPropertyName("exact", compact, str);
+            this.checkPropertyName("location", compact, str);
+            this.checkPropertyName("version", compact, str);
+        } else {
+            this.checkPropertyNameAbsent("extendedStackTrace", compact, str);
+        }
+        this.checkPropertyName("suppressed", compact, str);
+        this.checkPropertyName("loggerFqcn", compact, str);
+        this.checkPropertyName("endOfBatch", compact, str);
+        if (includeContext) {
+            this.checkPropertyName("contextMap", compact, str);
+        } else {
+            this.checkPropertyNameAbsent("contextMap", compact, str);
+        }
+        this.checkPropertyName("contextStack", compact, str);
+        if (locationInfo) {
+            this.checkPropertyName("source", compact, str);
+        } else {
+            this.checkPropertyNameAbsent("source", compact, str);
+        }
+        // check some attrs
+        this.checkProperty("loggerFqcn", "f.q.c.n", compact, str);
+        this.checkProperty("loggerName", "a.B", compact, str);
+    }
+
+    @Test
+    public void testContentType() {
+        final AbstractJacksonLayout layout = JsonLayout.createDefaultLayout();
+        assertEquals("application/json; charset=UTF-8", 
layout.getContentType());
+    }
+
+    @Test
+    public void testDefaultCharset() {
+        final AbstractJacksonLayout layout = JsonLayout.createDefaultLayout();
+        assertEquals(StandardCharsets.UTF_8, layout.getCharset());
+    }
+
+    @Test
+    public void testEscapeLayout() throws Exception {
+        final Map<String, Appender> appenders = this.rootLogger.getAppenders();
+        for (final Appender appender : appenders.values()) {
+            this.rootLogger.removeAppender(appender);
+        }
+        final Configuration configuration = 
rootLogger.getContext().getConfiguration();
+        // set up appender
+        final boolean propertiesAsList = false;
+        // @formatter:off
+        final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+                .setConfiguration(configuration)
+                .setLocationInfo(true)
+                .setProperties(true)
+                .setPropertiesAsList(propertiesAsList)
+                .setComplete(true)
+                .setCompact(false)
+                .setEventEol(false)
+                .setIncludeStacktrace(true)
+                .build();
+        // @formatter:on
+        final ListAppender appender = new ListAppender("List", null, layout, 
true, false);
+        appender.start();
+
+        // set appender on root and set level to debug
+        this.rootLogger.addAppender(appender);
+        this.rootLogger.setLevel(Level.DEBUG);
+
+        // output starting message
+        this.rootLogger.debug("Here is a quote ' and then a double quote \"");
+
+        appender.stop();
+
+        final List<String> list = appender.getMessages();
+
+        this.checkAt("[", 0, list);
+        this.checkAt("{", 1, list);
+        this.checkContains("\"level\" : \"DEBUG\",", list);
+        this.checkContains("\"message\" : \"Here is a quote ' and then a 
double quote \\\"\",", list);
+        this.checkContains("\"loggerFqcn\" : \"" + 
AbstractLogger.class.getName() + "\",", list);
+        for (final Appender app : appenders.values()) {
+            this.rootLogger.addAppender(app);
+        }
+    }
+
+    @Test
+    public void testExcludeStacktrace() throws Exception {
+        this.testAllFeatures(false, false, false, false, false, false);
+    }
+
+    @Test
+    public void testIncludeNullDelimiterFalse() throws Exception {
+        final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+                .setCompact(true)
+                .setIncludeNullDelimiter(false)
+                .build();
+        final String str = 
layout.toSerializable(LogEventFixtures.createLogEvent());
+        assertFalse(str.endsWith("\0"));
+    }
+
+    @Test
+    public void testIncludeNullDelimiterTrue() throws Exception {
+        final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+                .setCompact(true)
+                .setIncludeNullDelimiter(true)
+                .build();
+        final String str = 
layout.toSerializable(LogEventFixtures.createLogEvent());
+        assertTrue(str.endsWith("\0"));
+    }
+
+    /**
+     * Test case for MDC conversion pattern.
+     */
+    @Test
+    public void testLayout() throws Exception {
+        final Map<String, Appender> appenders = this.rootLogger.getAppenders();
+        for (final Appender appender : appenders.values()) {
+            this.rootLogger.removeAppender(appender);
+        }
+        final Configuration configuration = 
rootLogger.getContext().getConfiguration();
+        // set up appender
+        // Use [[ and ]] to test header and footer (instead of [ and ])
+        final boolean propertiesAsList = false;
+        // @formatter:off
+        final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+                .setConfiguration(configuration)
+                .setLocationInfo(true)
+                .setProperties(true)
+                .setPropertiesAsList(propertiesAsList)
+                .setComplete(true)
+                .setCompact(false)
+                .setEventEol(false)
+                .setHeader("[[".getBytes(Charset.defaultCharset()))
+                .setFooter("]]".getBytes(Charset.defaultCharset()))
+                .setIncludeStacktrace(true)
+                .build();
+        // @formatter:on
+        final ListAppender appender = new ListAppender("List", null, layout, 
true, false);
+        appender.start();
+
+        // set appender on root and set level to debug
+        this.rootLogger.addAppender(appender);
+        this.rootLogger.setLevel(Level.DEBUG);
+
+        // output starting message
+        this.rootLogger.debug("starting mdc pattern test");
+
+        this.rootLogger.debug("empty mdc");
+
+        ThreadContext.put("key1", "value1");
+        ThreadContext.put("key2", "value2");
+
+        this.rootLogger.debug("filled mdc");
+
+        ThreadContext.remove("key1");
+        ThreadContext.remove("key2");
+
+        this.rootLogger.error("finished mdc pattern test", new 
NullPointerException("test"));
+
+        appender.stop();
+
+        final List<String> list = appender.getMessages();
+
+        this.checkAt("[[", 0, list);
+        this.checkAt("{", 1, list);
+        this.checkContains("\"loggerFqcn\" : \"" + 
AbstractLogger.class.getName() + "\",", list);
+        this.checkContains("\"level\" : \"DEBUG\",", list);
+        this.checkContains("\"message\" : \"starting mdc pattern test\",", 
list);
+        for (final Appender app : appenders.values()) {
+            this.rootLogger.addAppender(app);
+        }
+    }
+
+    @Test
+    public void testLayoutLoggerName() throws Exception {
+        final boolean propertiesAsList = false;
+        // @formatter:off
+        final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+                .setLocationInfo(false)
+                .setProperties(false)
+                .setPropertiesAsList(propertiesAsList)
+                .setComplete(false)
+                .setCompact(true)
+                .setEventEol(false)
+                .setCharset(StandardCharsets.UTF_8)
+                .setIncludeStacktrace(true)
+                .build();
+        // @formatter:on
+        // @formatter:off
+        final Log4jLogEvent expected = Log4jLogEvent.newBuilder()
+                .setLoggerName("a.B")
+                .setLoggerFqcn("f.q.c.n")
+                .setLevel(Level.DEBUG)
+                .setMessage(new SimpleMessage("M"))
+                .setThreadName("threadName")
+                .setTimeMillis(1).build();
+        // @formatter:on
+        final String str = layout.toSerializable(expected);
+        assertTrue(str, str.contains("\"loggerName\":\"a.B\""));
+        final Log4jLogEvent actual = new 
Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, 
Log4jLogEvent.class);
+        assertEquals(expected.getLoggerName(), actual.getLoggerName());
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testLocationOffCompactOffMdcOff() throws Exception {
+        this.testAllFeatures(false, false, false, false, false, true);
+    }
+
+    @Test
+    public void testLocationOnCompactOnEventEolOnMdcOn() throws Exception {
+        this.testAllFeatures(true, true, true, true, false, true);
+    }
+
+    @Test
+    public void testLocationOnCompactOnEventEolOnMdcOnMdcAsList() throws 
Exception {
+        this.testAllFeatures(true, true, true, true, true, true);
+    }
+
+    @Test
+    public void testLocationOnCompactOnMdcOn() throws Exception {
+        this.testAllFeatures(true, true, false, true, false, true);
+    }
+
+    @Test
+    public void testObjectMessageAsJsonObject() {
+               final String str = 
prepareJsonForObjectMessageAsJsonObjectTests(1234, true);
+               assertTrue(str, str.contains("\"message\":{\"value\":1234}"));
+    }
+
+    @Test
+    public void testObjectMessageAsJsonString() {
+               final String str = 
prepareJsonForObjectMessageAsJsonObjectTests(1234, false);
+               assertTrue(str, str.contains("\"message\":\"" + 
this.getClass().getCanonicalName() + "$TestClass@"));
+    }
+
+    @Test
+    public void testStacktraceAsNonString() throws Exception {
+        final String str = prepareJsonForStacktraceTests(false);
+        assertTrue(str, str.contains("\"extendedStackTrace\":["));
+    }
+
+    @Test
+    public void testStacktraceAsString() throws Exception {
+        final String str = prepareJsonForStacktraceTests(true);
+        assertTrue(str, 
str.contains("\"extendedStackTrace\":\"java.lang.NullPointerException"));
+    }
+
+       private String toPropertySeparator(final boolean compact) {
+        return compact ? ":" : " : ";
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ThrowableProxyJsonTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ThrowableProxyJsonTest.java
 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ThrowableProxyJsonTest.java
new file mode 100644
index 0000000..c5b0355
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ThrowableProxyJsonTest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.jackson.json.layout;
+
+import java.io.IOException;
+
+import org.apache.logging.log4j.jackson.ThrowableProxyJacksonTest;
+import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper;
+import org.junit.Test;
+
+public class ThrowableProxyJsonTest extends ThrowableProxyJacksonTest {
+
+    @Test
+    public void testIoContainerAsJson() throws IOException {
+        testIoContainer(new Log4jJsonObjectMapper());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParserTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParserTest.java
 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParserTest.java
new file mode 100644
index 0000000..a6b3cc7
--- /dev/null
+++ 
b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParserTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.jackson.json.parser;
+
+import java.nio.charset.StandardCharsets;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.parser.AbstractLogEventParserTest;
+import org.apache.logging.log4j.core.parser.ParseException;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JsonLogEventParserTest extends AbstractLogEventParserTest {
+
+    private static final String JSON = "{\n" +
+            "  \"timeMillis\" : 1493121664118,\n" +
+            "  
\"instant\":{\"epochSecond\":1493121664,\"nanoOfSecond\":118000000},\n" +
+            "  \"thread\" : \"main\",\n" +
+            "  \"threadId\" : 1,\n" +
+            "  \"threadPriority\" : 5,\n" +
+            "  \"level\" : \"INFO\",\n" +
+            "  \"loggerName\" : \"HelloWorld\",\n" +
+            "  \"marker\" : {\n" +
+            "    \"name\" : \"child\",\n" +
+            "    \"parents\" : [ {\n" +
+            "      \"name\" : \"parent\",\n" +
+            "      \"parents\" : [ {\n" +
+            "        \"name\" : \"grandparent\"\n" +
+            "      } ]\n" +
+            "    } ]\n" +
+            "  },\n" +
+            "  \"message\" : \"Hello, world!\",\n" +
+            "  \"thrown\" : {\n" +
+            "    \"commonElementCount\" : 0,\n" +
+            "    \"message\" : \"error message\",\n" +
+            "    \"name\" : \"java.lang.RuntimeException\",\n" +
+            "    \"extendedStackTrace\" : [ {\n" +
+            "      \"class\" : \"logtest.Main\",\n" +
+            "      \"method\" : \"main\",\n" +
+            "      \"file\" : \"Main.java\",\n" +
+            "      \"line\" : 29,\n" +
+            "      \"exact\" : true,\n" +
+            "      \"location\" : \"classes/\",\n" +
+            "      \"version\" : \"?\"\n" +
+            "    } ]\n" +
+            "  },\n" +
+            "  \"contextStack\" : [ \"one\", \"two\" ],\n" +
+            "  \"loggerFqcn\" : 
\"org.apache.logging.log4j.spi.AbstractLogger\",\n" +
+            "  \"endOfBatch\" : false,\n" +
+            "  \"contextMap\" : {\n" +
+            "    \"bar\" : \"BAR\",\n" +
+            "    \"foo\" : \"FOO\"\n" +
+            "  },\n" +
+            "  \"source\" : {\n" +
+            "    \"class\" : \"logtest.Main\",\n" +
+            "    \"method\" : \"main\",\n" +
+            "    \"file\" : \"Main.java\",\n" +
+            "    \"line\" : 29\n" +
+            "  }\n" +
+            "}";
+
+    private JsonLogEventParser parser;
+
+    @Before
+    public void setup() {
+        parser = new JsonLogEventParser();
+    }
+
+    @Test
+    public void testByteArray() throws ParseException {
+        final LogEvent logEvent = 
parser.parseFrom(JSON.getBytes(StandardCharsets.UTF_8));
+        assertLogEvent(logEvent);
+    }
+
+    @Test
+    public void testByteArrayOffsetLength() throws ParseException {
+        final byte[] bytes = ("abc" + JSON + 
"def").getBytes(StandardCharsets.UTF_8);
+        final LogEvent logEvent = parser.parseFrom(bytes, 3, bytes.length - 6);
+        assertLogEvent(logEvent);
+    }
+
+    @Test
+    public void testEmptyObject() throws ParseException {
+        parser.parseFrom("{}");
+    }
+
+    @Test
+    public void testString() throws ParseException {
+        final LogEvent logEvent = parser.parseFrom(JSON);
+        assertLogEvent(logEvent);
+    }
+
+    @Test(expected = ParseException.class)
+    public void testStringEmpty() throws ParseException {
+        parser.parseFrom("");
+    }
+
+    @Test
+    public void testStringIgnoreInvalidProperty() throws ParseException {
+        parser.parseFrom("{\"foo\":\"bar\"}");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testStringInvalidJson() throws ParseException {
+        parser.parseFrom("foobar");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testStringJsonArray() throws ParseException {
+        parser.parseFrom("[]");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testStringWrongPropertyType() throws ParseException {
+        parser.parseFrom("{\"threadId\":\"foobar\"}");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-json/src/test/resources/log4j2-json-layout.xml
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-json/src/test/resources/log4j2-json-layout.xml 
b/log4j-layout-jackson-json/src/test/resources/log4j2-json-layout.xml
new file mode 100644
index 0000000..c7af4e9
--- /dev/null
+++ b/log4j-layout-jackson-json/src/test/resources/log4j2-json-layout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+<Configuration status="INFO" packages="">
+  <Appenders>
+    <File name="stdout" ignoreExceptions="false" 
fileName="target/test-xml-layout.log" append="false">
+      <JsonLayout compact="true" eventEol="true" />
+    </File>
+  </Appenders>
+
+  <Loggers>
+    <Root level="INFO">
+      <AppenderRef ref="stdout" />
+    </Root>
+  </Loggers>
+</Configuration>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java
 
b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java
new file mode 100644
index 0000000..0980f94
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java
@@ -0,0 +1,49 @@
+/*
+ * 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.jackson.xml;
+
+import org.apache.logging.log4j.core.jackson.SimpleModuleInitializer;
+
+import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
+
+/**
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ */
+final class Log4jXmlModule extends JacksonXmlModule {
+
+    private static final long serialVersionUID = 1L;
+    private final boolean includeStacktrace;
+    private final boolean stacktraceAsString;
+
+    Log4jXmlModule(final boolean includeStacktrace, final boolean 
stacktraceAsString) {
+        super();
+        this.includeStacktrace = includeStacktrace;
+        this.stacktraceAsString = stacktraceAsString;
+        // MUST init here.
+        // Calling this from setupModule is too late!
+        new SimpleModuleInitializer().initialize(this, false);
+    }
+
+    @Override
+    public void setupModule(final SetupContext context) {
+        // Calling super is a MUST!
+        super.setupModule(context);
+        new XmlSetupContextInitializer().setupModule(context, 
includeStacktrace, stacktraceAsString);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java
 
b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java
new file mode 100644
index 0000000..632b83f
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java
@@ -0,0 +1,48 @@
+/*
+ * 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.jackson.xml;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+
+/**
+ * A Jackson XML {@link ObjectMapper} initialized for Log4j.
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ */
+public class Log4jXmlObjectMapper extends XmlMapper {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Create a new instance using the {@link Log4jXmlModule}.
+     */
+    public Log4jXmlObjectMapper() {
+        this(true, false);
+    }
+
+    /**
+     * Create a new instance using the {@link Log4jXmlModule}.
+     */
+    public Log4jXmlObjectMapper(final boolean includeStacktrace, final boolean 
stacktraceAsString) {
+        super(new Log4jXmlModule(includeStacktrace, stacktraceAsString));
+        this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlInstantMixIn.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlInstantMixIn.java
 
b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlInstantMixIn.java
new file mode 100644
index 0000000..0e18154
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlInstantMixIn.java
@@ -0,0 +1,56 @@
+/*
+ * 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.jackson.xml;
+
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.jackson.InstantMixIn;
+import org.apache.logging.log4j.core.time.Instant;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+
+/**
+ * Jackson mix-in for {@link Instant}.
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ *
+ * @see Marker
+ */
+abstract class XmlInstantMixIn extends InstantMixIn {
+
+    @JsonCreator
+    protected XmlInstantMixIn(
+    // @formatter:off
+            @JsonProperty(ATTR_EPOCH_SECOND) final long epochSecond,
+            @JsonProperty(ATTR_NANO_OF_SECOND) final int nanoOfSecond)
+    // @formatter:on
+    {
+        super(epochSecond, nanoOfSecond);
+    }
+
+    @Override
+    @JacksonXmlProperty(localName = ATTR_EPOCH_SECOND, isAttribute = true)
+    protected abstract long getEpochSecond();
+
+    @Override
+    @JacksonXmlProperty(localName = ATTR_NANO_OF_SECOND, isAttribute = true)
+    protected abstract int getNanoOfSecond();
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlLogEventWithContextListMixIn.java
----------------------------------------------------------------------
diff --git 
a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlLogEventWithContextListMixIn.java
 
b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlLogEventWithContextListMixIn.java
new file mode 100644
index 0000000..771f955
--- /dev/null
+++ 
b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlLogEventWithContextListMixIn.java
@@ -0,0 +1,50 @@
+/*
+ * 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.jackson.xml;
+
+import org.apache.logging.log4j.core.jackson.AbstractXmlLogEventMixIn;
+import 
org.apache.logging.log4j.core.jackson.ContextDataAsEntryListDeserializer;
+import org.apache.logging.log4j.core.jackson.ContextDataAsEntryListSerializer;
+import org.apache.logging.log4j.core.jackson.XmlConstants;
+import org.apache.logging.log4j.util.ReadOnlyStringMap;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+
+/**
+ * <pre>
+ * AbstractLogEventMixIn
+*├─ XmlLogEventMixIn
+*├──── XmlLogEventWithContextListMixIn
+*├──── XmlLogEventWithContextMapMixIn
+*├─ JsonLogEventMixIn
+*├──── JsonLogEventWithContextListMixIn
+*├──── JsonLogEventWithContextMapMixIn
+ * </pre>
+ */
+public abstract class XmlLogEventWithContextListMixIn extends 
AbstractXmlLogEventMixIn {
+
+    private static final long serialVersionUID = 1L;
+
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = 
XmlConstants.ELT_CONTEXT_MAP)
+    @JsonSerialize(using = ContextDataAsEntryListSerializer.class)
+    @JsonDeserialize(using = ContextDataAsEntryListDeserializer.class)
+    @Override
+    public abstract ReadOnlyStringMap getContextData();
+
+}

Reply via email to