json-snapshot / json-snapshot.github.io

Snapshot Testing for Java
https://json-snapshot.github.io
MIT License
33 stars 17 forks source link

Lib can not be used with Jackson 2.10.0 or later #27

Open grimsa opened 4 years ago

grimsa commented 4 years ago

Jackson 2.10 was released 2019-09-26. It contains a fix for https://github.com/FasterXML/jackson-core/issues/502, which makes snapshot building fail with the following exception:

io.github.jsonSnapshot.SnapshotMatchException: Failed `createInstance()`: io.github.jsonSnapshot.SnapshotMatcher$1 does not override method; it has to

    at io.github.jsonSnapshot.SnapshotMatcher.lambda$defaultJsonFunction$0(SnapshotMatcher.java:116)
    at io.github.jsonSnapshot.Snapshot.takeSnapshot(Snapshot.java:87)
    at io.github.jsonSnapshot.Snapshot.toMatchSnapshot(Snapshot.java:43)

The cause of this is io.github.jsonSnapshot.SnapshotMatcher#buildDefaultPrettyPrinter where DefaultPrettyPrinter is extended, but now required createInstance method is not overridden.

This makes serializing JSON fail with the following stack trace:

java.lang.IllegalStateException: Failed `createInstance()`: io.github.jsonSnapshot.SnapshotMatcher$1 does not override method; it has to
    at com.fasterxml.jackson.core.util.DefaultPrettyPrinter.createInstance(DefaultPrettyPrinter.java:256)
    at com.fasterxml.jackson.core.util.DefaultPrettyPrinter.createInstance(DefaultPrettyPrinter.java:15)
    at com.fasterxml.jackson.databind.ObjectWriter$GeneratorSettings.initialize(ObjectWriter.java:1299)
    at com.fasterxml.jackson.databind.ObjectWriter._configureGenerator(ObjectWriter.java:1174)
    at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:1129)
    at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1005)
    at io.github.jsonSnapshot.SnapshotMatcher.lambda$defaultJsonFunction$0(SnapshotMatcher.java:114)
paul-pop commented 4 years ago

Any ideas when / if work can start on this? As Spring Boot 2.2.x uses Jackson 2.10.x this becomes a problem for everyone using Spring Boot 2.2.

grimsa commented 4 years ago

Workaround In all tests replace SnapshotMatcher.start() with SnapshotMatcher.start(Snapshot::asJsonString), where Snapshot#asJsonString is implemented like this:

public final class Snapshot {
    private static final ObjectMapper objectMapper = buildObjectMapper();
    private static final PrettyPrinter pp = buildDefaultPrettyPrinter();

    /**
     * Workaround for an incompatibility between latest Jackson and json-snapshot libs.
     * <p>
     * Intended to replace {@code io.github.jsonSnapshot.SnapshotMatcher#defaultJsonFunction}
     *
     * @see <a href="https://github.com/json-snapshot/json-snapshot.github.io/issues/27">Issue in json-snapshot project</a>
     */
    public static String asJsonString(Object object) {
        try {
            return objectMapper.writer(pp).writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new UncheckedIOException(e);
        }
    }

    /**
     * Unmodified copy of {@code io.github.jsonSnapshot.SnapshotMatcher#buildObjectMapper}
     */
    private static ObjectMapper buildObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        objectMapper.setVisibility(
                objectMapper
                        .getSerializationConfig()
                        .getDefaultVisibilityChecker()
                        .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                        .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                        .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                        .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
        return objectMapper;
    }

    /**
     * Modified copy of {@code io.github.jsonSnapshot.SnapshotMatcher#buildDefaultPrettyPrinter}
     */
    private static PrettyPrinter buildDefaultPrettyPrinter() {
        DefaultPrettyPrinter pp =
                new DefaultPrettyPrinter("") {
                    @Override
                    public DefaultPrettyPrinter createInstance() {
                        return this;
                    }

                    @Override
                    public DefaultPrettyPrinter withSeparators(Separators separators) {
                        this._separators = separators;
                        this._objectFieldValueSeparatorWithSpaces =
                                separators.getObjectFieldValueSeparator() + " ";
                        return this;
                    }
                };
        DefaultPrettyPrinter.Indenter lfOnlyIndenter = new DefaultIndenter("  ", "\n");
        pp.indentArraysWith(lfOnlyIndenter);
        pp.indentObjectsWith(lfOnlyIndenter);
        return pp;
    }
}
jpommerening commented 3 years ago

Hi @grimsa & @paul-pop! We're using the library to great success, thank you for that!

We recently updated our Jackson dependency and ran straight into this issue. The workaround works for us. Is there a chance that there will be an update to json-snapshot in the future that fixes the issue?

Regarding a possible backwards-compatible fix: Shouldn't it be possible to also override createInstance() with Jackson <= 2.9? As far as I can tell, all DefaultPrettyPrinter versions already have it, so calling super.createInstance() should be enough… But, of course, that's for you to decide :+1:

Thanks & have a good weekend!

shahparth199730 commented 2 years ago

Hi, @grimsa similar to the workaround you proposed, can we also introduce the workaround for having different modes of matching? i.e Introduce different matching modes