diff --git a/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Jackson2NodeFactory.java b/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Jackson2NodeFactory.java index 1358a567a..1761b6808 100644 --- a/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Jackson2NodeFactory.java +++ b/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Jackson2NodeFactory.java @@ -19,12 +19,14 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.NullNode; +import net.javacrumbs.jsonunit.providers.Jackson2ObjectMapperProvider; import java.io.IOException; import java.io.Reader; import java.math.BigDecimal; import java.util.Iterator; import java.util.Map; +import java.util.ServiceLoader; import static net.javacrumbs.jsonunit.core.internal.Utils.closeQuietly; @@ -32,19 +34,11 @@ * Deserializes node using Jackson 2 */ class Jackson2NodeFactory extends AbstractNodeFactory { - private static final ObjectMapper mapper = new ObjectMapper(); - private static final ObjectMapper lenientMapper = new ObjectMapper(); - - static { - lenientMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); - lenientMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); - lenientMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); - } - + private final ServiceLoader serviceLoader = ServiceLoader.load(Jackson2ObjectMapperProvider.class); @Override protected Node doConvertValue(Object source) { - return newNode(mapper.convertValue(source, JsonNode.class)); + return newNode(getMapper(false).convertValue(source, JsonNode.class)); } @Override @@ -63,7 +57,16 @@ protected Node readValue(Reader value, String label, boolean lenient) { } private ObjectMapper getMapper(boolean lenient) { - return lenient ? lenientMapper : mapper; + return getMapperProvider().getObjectMapper(lenient); + } + + private Jackson2ObjectMapperProvider getMapperProvider() { + Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return DefaultObjectMapperProvider.INSTANCE; + } } private static Node newNode(JsonNode jsonNode) { @@ -177,4 +180,21 @@ public String toString() { return jsonNode.toString(); } } + + private static class DefaultObjectMapperProvider implements Jackson2ObjectMapperProvider { + static final Jackson2ObjectMapperProvider INSTANCE = new DefaultObjectMapperProvider(); + + private static final ObjectMapper mapper = new ObjectMapper(); + private static final ObjectMapper lenientMapper = new ObjectMapper(); + + static { + lenientMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); + lenientMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); + lenientMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); + } + @Override + public ObjectMapper getObjectMapper(boolean lenient) { + return lenient ? lenientMapper : mapper; + } + } } diff --git a/json-unit-core/src/main/java/net/javacrumbs/jsonunit/providers/Jackson2ObjectMapperProvider.java b/json-unit-core/src/main/java/net/javacrumbs/jsonunit/providers/Jackson2ObjectMapperProvider.java new file mode 100644 index 000000000..3da0b27e1 --- /dev/null +++ b/json-unit-core/src/main/java/net/javacrumbs/jsonunit/providers/Jackson2ObjectMapperProvider.java @@ -0,0 +1,30 @@ +/** + * Copyright 2009-2017 the original author or authors. + *

+ * Licensed 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 net.javacrumbs.jsonunit.providers; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Interface for customizing Jackson 2 ObjectMapper. {@see https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html} + */ +public interface Jackson2ObjectMapperProvider { + /** + * Provides ObjectMapper + * @param lenient Lenient parsing is used for parsing the expected JSON value + * @return customized ObjectMapper. + */ + ObjectMapper getObjectMapper(boolean lenient); +} diff --git a/tests/pom.xml b/tests/pom.xml index add1831ed..bfbb5f8ea 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -14,6 +14,7 @@ test-base test-jackson2 + test-jackson2-config test-gson test-jsonorg test-moshi diff --git a/tests/test-jackson2-config/pom.xml b/tests/test-jackson2-config/pom.xml new file mode 100644 index 000000000..dcf098990 --- /dev/null +++ b/tests/test-jackson2-config/pom.xml @@ -0,0 +1,36 @@ + + + + tests + net.javacrumbs.json-unit + 2.2.1-SNAPSHOT + + 4.0.0 + + test-jackson2-config + 2.2.1-SNAPSHOT + + + + net.javacrumbs.json-unit + test-base + ${project.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson2.version} + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson2.version} + test + + + org.slf4j + slf4j-simple + + +