Compare JSON in your Unit Tests

Related tags

JSON JsonUnit
Overview

JsonUnit Apache License 2 Build Status Maven Central

JsonUnit is a library that simplifies JSON comparison in tests.

APIs

There are several different APIs you can use. They all have more or less the same features, just the usage is slightly different.

AssertJ integration

This is brand new API which combines power of JsonUnit and AssertJ. If you are not sure, which API to use, pick this one.

import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json;

...

// compares two JSON documents (note lenient parsing of expected value)
assertThatJson("{\"a\":1, \"b\":2}").isEqualTo("{b:2, a:1}");

// objects are automatically serialized before comparison
assertThatJson(jsonObject).isEqualTo("{\n\"test\": 1\n}");

// AssertJ map assertions (numbers are converted to BigDecimals)
assertThatJson("{\"a\":1}").isObject().containsEntry("a", BigDecimal.valueOf(1));

// Type placeholders
assertThatJson("{\"a\":1, \"b\": {\"c\" :3}}")
    .isObject().containsValue(json("{\"c\" :\"${json-unit.any-number}\"}"));

// AssertJ array assertion
assertThatJson("{\"a\":[{\"b\": 1}, {\"c\": 1}, {\"d\": 1}]}")
    .node("a").isArray().contains(json("{\"c\": 1}"));

// Can ignore array order
assertThatJson("{\"a\":[{\"b\": 1}, {\"c\": 1}, {\"d\": 1}]}")
    .when(Option.IGNORING_ARRAY_ORDER).node("a").isArray()
    .isEqualTo(json("[{\"c\": 1}, {\"b\": 1} ,{\"d\": 1}]"));

// custom matcher
assertThatJson("{\"test\":-1}")
    .withConfiguration(c -> c.withMatcher("positive", greaterThan(valueOf(0))))
    .isEqualTo("{\"test\": \"${json-unit.matches:positive}\"}");

// and
assertThatJson("{\"test\":{\"a\":1, \"b\":2, \"c\":3}}").and(
    a -> a.node("test.a").isEqualTo(1),
    a -> a.node("test.b").isEqualTo(2)
);

// JsonPath support
assertThatJson(json)
    .inPath("$.store.book")
    .isArray()
    .contains(json(
        "            {\n" +
            "                \"category\": \"reference\",\n" +
            "                \"author\": \"Nigel Rees\",\n" +
            "                \"title\": \"Sayings of the Century\",\n" +
            "                \"price\": 8.96\n" +
            "            }"
    ));

JsonUnit tries to be clever when parsing the expected value. If the value can be parsed as valid JSON, it's parsed so. If it can't be parsed, it's considered to be just a string to be compared. It usually works, but it can lead to unexpected situations, usually with primitive values like numbers and booleans.

// This test does NOT pass. "1" is parsed as JSON containing number 1, actual value is a string.
assertThatJson("{\"id\":\"1\", \"children\":[{\"parentId\":\"1\"}]}")
    .inPath("children[*].parentId")
    .isArray()
    .containsOnly("1");

// You have to wrap the expected value by `JsonAssertions.value()`
// to prevent parsing
assertThatJson("{\"id\":\"1\", \"children\":[{\"parentId\":\"1\"}]}")
    .inPath("children[*].parentId")
    .isArray()
    .containsOnly(value("1"));

// "true" is valid JSON so it gets parsed to primitive `true`
// Have to wrap it to JsonAssertions.value() in order to make sure it's not parsed
assertThatJson("{\"root\":[\"true\"]}").node("root").isArray().containsExactly(value("true"));

On the other hand, if you want to make sure that the expected value is parsed as JSON, use JsonAssertions.json().

Kotlin support

Following Kotlin API is supported (notice different import)

// Kotlin
import net.javacrumbs.jsonunit.assertj.assertThatJson

assertThatJson("""{"root":{"a":1, "b": 2}}""") {
    isObject
    node("root.a").isEqualTo(1)
    node("root.b").isEqualTo(2)
}

To use AssertJ integration, import

<dependency>
    <groupId>net.javacrumbs.json-unit</groupId>
    <artifactId>json-unit-assertj</artifactId>
    <version>2.24.0</version>
    <scope>test</scope>
</dependency>

For more examples see the tests.

Hamcrests matchers

You use Hamcrest matchers in the following way

import static net.javacrumbs.jsonunit.JsonMatchers.*;
import static org.junit.Assert.*;
import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource;
...

assertThat("{\"test\":1}", jsonEquals("{\"test\": 1}"));
assertThat("{\"test\":1}", jsonPartEquals("test", 1));
assertThat("{\"test\":[1, 2, 3]}", jsonPartEquals("test[0]", 1));

assertThat("{\"test\":{\"a\":1, \"b\":2, \"c\":3}}",
    jsonEquals("{\"test\":{\"b\":2}}").when(IGNORING_EXTRA_FIELDS));

// Can use other Hamcrest matchers too
assertThat("{\"test\":1}", jsonPartMatches("test", is(valueOf(1))))

assertThat("{\"test\":1}", jsonEquals(resource("test.json")));

To use import

<dependency>
    <groupId>net.javacrumbs.json-unit</groupId>
    <artifactId>json-unit</artifactId>
    <version>2.24.0</version>
    <scope>test</scope>
</dependency>

For more examples see the tests.

Spring MVC assertions

JsonUnit supports Spring MVC test assertions. For example

import static net.javacrumbs.jsonunit.spring.JsonUnitResultMatchers.json;
...

mockMvc.perform(get("/sample").andExpect(
    json().isEqualTo("{\"result\":{\"string\":\"stringValue\", \"array\":[1, 2, 3],\"decimal\":1.00001}}")
);
mockMvc.perform(get("/sample").andExpect(
    json().node("result.string2").isAbsent()
);
mockMvc.perform(get("/sample").andExpect(
    json().node("result.array").when(Option.IGNORING_ARRAY_ORDER).isEqualTo(new int[]{3, 2, 1})
);
mockMvc.perform(get("/sample").andExpect(
    json().node("result.array").matches(everyItem(lessThanOrEqualTo(valueOf(4))))
);

Following Kotlin DSL si supported:

mockMvc.get(path).andExpect {
    jsonContent {
        node("root").isEqualTo(CORRECT_JSON)
    }
}

Inside jsonContent you have access to all AssertJ API capabilities as described here.

To use import

<dependency>
    <groupId>net.javacrumbs.json-unit</groupId>
    <artifactId>json-unit-spring</artifactId>
    <version>2.24.0</version>
    <scope>test</scope>
</dependency>

For more examples see the tests.

Spring WebTestClient

To integrate with Spring WebTest client do

import static net.javacrumbs.jsonunit.spring.WebTestClientJsonMatcher.json;
...

client.get().uri(path).exchange().expectBody().consumeWith(
    json().isEqualTo("{\"result\":{\"string\":\"stringValue\", \"array\":[1, 2, 3],\"decimal\":1.00001}}")
);
client.get().uri(path).exchange().expectBody().consumeWith(
    json().node("result.string2").isAbsent()
);
client.get().uri(path).exchange().expectBody().consumeWith(
    json().node("result.array").when(Option.IGNORING_ARRAY_ORDER).isEqualTo(new int[]{3, 2, 1})
);
client.get().uri(path).exchange().expectBody().consumeWith(
    json().node("result.array").matches(everyItem(lessThanOrEqualTo(valueOf(4))))
);

For Kotlin, you can use our bespoke DSL

import net.javacrumbs.jsonunit.spring.jsonContent
...
client.get().uri(path).exchange().expectBody()
    .jsonContent {
        isEqualTo(CORRECT_JSON)
    }

Import

<dependency>
    <groupId>net.javacrumbs.json-unit</groupId>
    <artifactId>json-unit-spring</artifactId>
    <version>2.24.0</version>
    <scope>test</scope>
</dependency>

Spring REST client assertions

import static net.javacrumbs.jsonunit.spring.JsonUnitRequestMatchers.json;
...
mockServer.expect(requestTo(URI))
      .andExpect(json().isEqualTo(json))
      .andRespond(withSuccess(jsonResponse, MediaType.APPLICATION_JSON_UTF8));

To use import

<dependency>
    <groupId>net.javacrumbs.json-unit</groupId>
    <artifactId>json-unit-spring</artifactId>
    <version>2.24.0</version>
    <scope>test</scope>
</dependency>

Vintage APIs

There are two API types that are still supported but not recommnded to use for new tests - Fluent assertions and Standard assert. They are documented here

Features

JsonUnit support all this features regardless of API you use.

JsonPath support

You can use JsonPath navigation together with JsonUnit. It has native support in AssertJ integration so you can do something like this:

// AssertJ style
assertThatJson(json)
    .inPath("$.store.book")
    .isArray()
    .contains(json(
        "            {\n" +
            "                \"category\": \"reference\",\n" +
            "                \"author\": \"Nigel Rees\",\n" +
            "                \"title\": \"Sayings of the Century\",\n" +
            "                \"price\": 8.96\n" +
            "            }"
    ));

For other API styles you have to first import JsonPath support module

<dependency>
    <groupId>net.javacrumbs.json-unit</groupId>
    <artifactId>json-unit-json-path</artifactId>
    <version>2.24.0</version>
    <scope>test</scope>
</dependency>

and then use instead of actual value

import static net.javacrumbs.jsonunit.jsonpath.JsonPathAdapter.inPath;

...
// Fluent assertions
assertThatJson(inPath(json, "$.store.book[*].author"))
    .when(Option.IGNORING_ARRAY_ORDER)
    .isEqualTo("['J. R. R. Tolkien', 'Nigel Rees', 'Evelyn Waugh', 'Herman Melville']");

Ignoring values

Sometimes you need to ignore certain values when comparing. It is possible to use ${json-unit.ignore} or #{json-unit.ignore} placeholder like this

// AssertJ API
assertThatJson("{\"a\":1}")
    .isEqualTo(json("{\"a\":\"${json-unit.ignore}\"}"));

Please note that the assertion will fail if the test element is missing in the actual value.

Ignoring elements

If the element needs to be ignored completely you can use ${json-unit.ignore-element} placeholder.

// AssertJ API
assertThatJson("{\"root\":{\"test\":1, \"ignored\": null}}")
      .isEqualTo("{\"root\":{\"test\":1, \"ignored\": \"${json-unit.ignore-element}\"}}");

The assertion will not fail if the element is missing in the actual value.

Ignoring paths

whenIgnoringPaths configuration option makes JsonUnit ignore the specified paths in the actual value. If the path matches, it's completely ignored. It may be missing, null or have any value. Also when(paths(...), thenIgnore() can be used.

// AssertJ style
assertThatJson("{\"root\":{\"test\":1, \"ignored\": 1}}")
    .whenIgnoringPaths("root.ignored"))
    .isEqualTo("{\"root\":{\"test\":1}}");

// Hamcrest matcher
assertThat(
  "{\"root\":{\"test\":1, \"ignored\": 2}}",
  jsonEquals("{\"root\":{\"test\":1, \"ignored\": 1}}").whenIgnoringPaths("root.ignored")
);

Array index placeholder

assertThatJson("[{\"a\":1, \"b\":2},{\"a\":1, \"b\":3}]")
    .whenIgnoringPaths("[*].b")
    .isEqualTo("[{\"a\":1, \"b\":0},{\"a\":1, \"b\":0}]");

Please note that if you use JsonPath, you should start the path to be ignored by $ Also note that whenIgnoringPaths method supports full JsonPath syntax only in AssertJ API, all the other flavors support only exact path or array index placeholder as described above.

JsonPath with whenIgnoringPaths example:

// AssertJ API
assertThatJson("{\"fields\":[" +
        "{\"key\":1, \"name\":\"AA\"}," +
        "{\"key\":2, \"name\":\"AB\"}," +
        "{\"key\":3, \"name\":\"AC\"}" +
    "]}")
    .whenIgnoringPaths("$.fields[?(@.name=='AA')].key")
    .isEqualTo("{\"fields\":[" +
        "{\"key\":2, \"name\":\"AA\"}," +
        "{\"key\":2, \"name\":\"AB\"}," +
        "{\"key\":3, \"name\":\"AC\"}" +
    "]}");

Regular expressions

It is also possible to use regular expressions to compare string values

assertThatJson("{\"test\": \"ABCD\"}")
    .isEqualTo("{\"test\": \"${json-unit.regex}[A-Z]+\"}");

For matching just part of the string, you can use this (we have to escape twice, one for Java, once for JSON)

assertThatJson("{\"test\": \"This is some text followed by: ABCD, followed by this\"}")
            .isEqualTo("{\"test\": \"${json-unit.regex}^\\\\QThis is some text followed by: \\\\E[A-Z]+\\\\Q, followed by this\\\\E$\"}");

Since this is quite hard to write, you can implement an expression builder like this.

Type placeholders

If you want to assert just a type, but you do not care about the exact value, you can use any-* placeholder like this

assertThatJson("{\"test\":\"value\"}")
    .isEqualTo("{test:'${json-unit.any-string}'}");

assertThatJson("{\"test\":true}")
    .isEqualTo("{\"test\":\"${json-unit.any-boolean}\"}");

assertThatJson("{\"test\":1.1}")
    .isEqualTo("{\"test\":\"${json-unit.any-number}\"}");

You can also use hash instead of string #{json-unit.any-string} for example if you are using language with string interpolation like Kotlin.

Custom matchers

In some special cases you might want to use your own matcher in the expected document.

 assertThatJson("{\"test\":-1}")
             .withMatcher("positive", greaterThan(valueOf(0)))
             .isEqualTo("{\"test\": \"${json-unit.matches:positive}\"}");

In even more special cases, you might want to parametrize your matcher.

 Matcher<?> divisionMatcher = new DivisionMatcher();
 assertThatJson("{\"test\":5}")
    .withMatcher("isDivisibleBy", divisionMatcher)
    .isEqualTo("{\"test\": \"${json-unit.matches:isDivisibleBy}3\"}");

 private static class DivisionMatcher extends BaseMatcher<Object> implements ParametrizedMatcher {
     private BigDecimal param;

     public boolean matches(Object item) {
         return ((BigDecimal)item).remainder(param).compareTo(ZERO) == 0;
     }

     public void describeTo(Description description) {
         description.appendValue(param);
     }

     @Override
     public void describeMismatch(Object item, Description description) {
         description.appendText("It is not divisible by ").appendValue(param);
     }

     public void setParameter(String parameter) {
         this.param = new BigDecimal(parameter);
     }
 }

If you need a matcher with more than one parameter, you can implement it like this.

Options

There are multiple options how you can configure the comparison

TREATING_NULL_AS_ABSENT - fields with null values are equivalent to absent fields. For example, this test passes

assertThatJson("{\"test\":{\"a\":1, \"b\": null}}")
    .when(TREATING_NULL_AS_ABSENT)
    .isEqualTo("{\"test\":{\"a\":1}}");

IGNORING_ARRAY_ORDER - ignores order in arrays

assertThatJson("{\"test\":[1,2,3]}")
    .when(IGNORING_ARRAY_ORDER)
    .isEqualTo("{\"test\":[3,2,1]}");

IGNORING_EXTRA_ARRAY_ITEMS - ignores unexpected array items

assertThatJson("{\"test\":[1,2,3,4]}")
    .when(IGNORING_EXTRA_ARRAY_ITEMS)
    .isEqualTo("{\"test\":[1,2,3]}");


assertThatJson("{\"test\":[5,5,4,4,3,3,2,2,1,1]}")
    .when(IGNORING_EXTRA_ARRAY_ITEMS, IGNORING_ARRAY_ORDER)
    .isEqualTo("{\"test\":[1,2,3]}");

IGNORING_EXTRA_FIELDS - ignores extra fields in the compared value

assertThatJson("{\"test\":{\"a\":1, \"b\":2, \"c\":3}}")
    .when(IGNORING_EXTRA_FIELDS)
    .isEqualTo("{\"test\":{\"b\":2}}");

IGNORE_VALUES - ignores values and compares only types

assertThatJson("{\"a\":2,\"b\":\"string2\"}")
    .when(paths("a", "b"), then(IGNORING_VALUES))
    .isEqualTo("{\"a\":1,\"b\":\"string\"}");

It is possible to combine options.

assertThatJson("{\"test\":[{\"key\":3},{\"key\":2, \"extraField\":2},{\"key\":1}]}")
    .when(IGNORING_EXTRA_FIELDS, IGNORING_ARRAY_ORDER)
    .isEqualTo("{\"test\":[{\"key\":1},{\"key\":2},{\"key\":3}]}");

In Hamcrest assertion you can set the option like this

assertThat("{\"test\":{\"a\":1, \"b\":2, \"c\":3}}",
    jsonEquals("{\"test\":{\"b\":2}}").when(IGNORING_EXTRA_FIELDS));

You can define options locally (for specific paths) by using when(path(...), then(...)):

// ignore array order for [*].a
// AssertJ
assertThatJson("{\"test\":{\"a\":1,\"b\":2,\"c\":3}}").when(paths("test.c"), then(IGNORING_VALUES))
    .isEqualTo("{\"test\":{\"a\":1,\"b\":2,\"c\":4}}");
// ignore array order everywhere but [*].b
assertThatJson("[{\"b\":[4,5,6]},{\"b\":[1,2,3]}]")
    .when(IGNORING_ARRAY_ORDER)
    .when(path("[*].b"), thenNot(IGNORING_ARRAY_ORDER))
    .isEqualTo("[{\"b\":[1,2,3]},{\"b\":[4,5,6]}]");
// ignore extra fields in the object "a"
assertThatJson("{\"a\":{\"a1\":1,\"a2\":2},\"b\":{\"b1\":1,\"b2\":2}}")
    .when(path("a"), then(IGNORING_EXTRA_FIELDS))
    .isEqualTo("{\"a\":{\"a1\":1},\"b\":{\"b1\":1}}"))
// ignore extra array items in the array
assertThatJson("{\"a\":[1,2,3]}")
    .when(path("a"), then(IGNORING_EXTRA_ARRAY_ITEMS))
    .isEqualTo("{\"a\":[1,2]}");
// Hamcrest
assertThat("{\"test\":{\"a\":1,\"b\":2,\"c\":3}}",
    jsonEquals("{\"test\":{\"a\":1,\"b\":2,\"c\":4}}").when(path("test.c"), then(IGNORING_VALUES)));

Note that TREATING_NULL_AS_ABSENT and IGNORING_VALUES require exact paths to ignored fields:

// ignoring number and str
assertThatJson("{\"a\":2,\"b\":\"string2\"}")
    .when(paths("a", "b"), then(IGNORING_VALUES))
    .isEqualTo("{\"a\":1,\"b\":\"string\"}");
// treat null B as absent B
assertThatJson("{\"A\":1,\"B\":null}")
    .when(path("B"), then(TREATING_NULL_AS_ABSENT))
    .isEqualTo("{\"A\":1}");

All other options require paths to objects or arrays where values or order should be ignored.

Array indexing

You can use negative numbers to index arrays form the end

assertThatJson("{\"root\":{\"test\":[1,2,3]}}")
    .node("root.test[-1]").isEqualTo(3);

Numerical comparison

Numbers are by default compared in the following way:

  • If the type differs, the number is different. So 1 and 1.0 are different (int vs. float). This does not apply when Moshi is used since it parses all numbers as Doubles.
  • Floating number comparison is exact

You can change this behavior by setting tolerance. If you set tolerance to 0 two numbers are considered equal if they are equal mathematically even though they have different type (a.compareTo(b) == 0)).

assertThatJson("{\"test\":1.00}").node("test").withTolerance(0).isEqualTo(1);

If you set tolerance to non-zero value, the values are considered equal if abs(a-b) < tolerance.

assertThatJson("{\"test\":1.00001}").node("test").withTolerance(0.001).isEqualTo(1);

Or you can use Hamcrest matcher

import static java.math.BigDecimal.valueOf;
...
assertThatJson("{\"test\":1.10001}").node("test")
    .matches(closeTo(valueOf(1.1), valueOf(0.001)));

If you are interested why 1 and 1.0 are treated as different numbers please read this comment.

Escaping dots

Sometimes you have dots in JSON element names and you need to address those elements. It is possible to escape dots like this

assertThatJson("{\"name.with.dot\": \"value\"}").node("name\\.with\\.dot").isStringEqualTo("value");

Lenient parsing of expected value

Writing JSON string in Java is huge pain. JsonUnit parses expected values leniently so you do not have to quote keys and you can use single quotes instead of double quotes. Please note that the actual value being compared is parsed in strict mode.

assertThatJson("{\"a\":\"1\", \"b\":2}").isEqualTo("{b:2, a:'1'}");

Jackson Object Mapper customization

If you need to customize Jacson 2 Object Mapper, you can do using SPI. Implement net.javacrumbs.jsonunit.providers.Jackson2ObjectMapperProvider.

public class Java8ObjectMapperProvider implements Jackson2ObjectMapperProvider {
    private final ObjectMapper mapper;

    private final ObjectMapper lenientMapper;


    public Java8ObjectMapperProvider() {
        mapper = new ObjectMapper().registerModule(new JavaTimeModule());
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        lenientMapper = new ObjectMapper().registerModule(new JavaTimeModule());
        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;
    }
}

and register it in META-INF/services/net.javacrumbs.jsonunit.providers.Jackson2ObjectMapperProvider. See this example.

Logging

Although the differences are printed out by the assert statement, sometimes you use JsonUnit with other libraries like Jadler that do not print the differences between documents. In such case, you can switch on the logging. JsonUnit uses SLF4J. The only thing you need to do is to configure your logging framework to log net.javacrumbs.jsonunit.difference on DEBUG level.

Selecting underlying library

JsonUnit is trying to cleverly match which JSON library to use. In case you need to change the default behavior, you can use json-unit.libraries system property. For example -Djson-unit.libraries=jackson2,gson or System.setProperty("json-unit.libraries", "jackson2");. Supported values are gson, json.org, moshi, jackson2

Licence

JsonUnit is licensed under Apache 2.0 licence.

Release notes

2.24.0

  • Fix OSGi configuration
  • AssertJ updated to 3.19.0

2.23.0

  • Better error message for multiple matches in isAbsent check
  • Various library upgrades

2.22.1

  • Better exception message in case of JSON that can not be parsed

2.22.0

  • Support for Spring WebTestClient

2.21.0

  • Fixed Kotlin AssertJ bundle #299

2.20.0

  • assertThatJson accepts null as the actual value

2.19.0

  • opentest4j made optional #276
  • updated all dependencies

2.18.1

  • Fix multiple when method application #234

2.18.0

  • Support for URI assertions

2.17.0

  • Do not append tolerance with zero value to diff message (thanks @valfirst)

2.16.2

  • Fix regex issues on older Androids #227 (thanks @Sirrah)

2.16.1

  • Add missing Kotlin classes to distribution Jars

2.16.0

  • Kotlin DSL for AssertJ API

2.15.0

  • Spring DSL Koltin support
  • JUnit upgraded to 5.6.0

2.14.0

  • Allow differentiating between number and integer

2.13.1

  • Fix Jackson2NodeFactory thread safety issue in usage of ServiceLoader (thanks @cnauroth)

2.13.0

2.12.0

  • Updated dependencies
  • Jackson node is not reparsed when compared #214

2.11.1

  • Parse content as UTF-8 in Spring MVC test if not specified otherwise #212

2.11.0

  • Fix Kotlin 'Inaccessible type' warning in when-path (@Vladiatro)
  • Load resources as UTF-8 (@bencampion)

2.10.0

  • Support for PathOptions
  • AssertJ - support for chaining assertions in the same root
  • Support for json-path in AssertJ whenIgnoringPaths

2.9.0

  • Hamcrest upgraded to 2.1
  • AssertJ dependency upgraded to 3.12.3 (requires AssertJ > 3.10.0)

2.8.1

  • hamcrest-core dependency marked as required

2.8.0

  • #185 JsonUnitRequestMatchers for client-side REST testing
  • Support for array (non)emptiness in Fluent assert

2.7.0

  • Support for Johnzon (requires 1.1.12) (thanks to elexx)

2.6.3

  • Ignoring paths even when present in expected value #182

2.6.2

  • Fixed AssertionErrors messages in MultipleFailuresError #181

2.6.1

  • Path with backspaces matching fixed #176

2.6.0

  • ${json-unit.ignore-elements} introduced

2.5.1

  • Array comparison optimization

2.5.0

  • Fix bug and performance issues in array comparison
  • Performance optimizations

2.4.0

  • Introduced JsonAssertions.value()
  • Fixed AssertJ withFailMessage

2.3.0

  • Support for Jackson 2 ObjectMapper customization
  • Some AbstractObjectAssert marked as unsupported

2.2.0

  • Using opentest4j
  • Refactored exception reporting

2.1.1

  • Better exception reporting
  • Fixed invalid Automatic-Module-Name

2.0.3

  • Fixed missing node handling with JsonPath
  • Fixed some complex AsserJ comaprisons

2.0.2

  • Fixed #144 (AssertJ object handling)

2.0.1

  • Support for # instead of $ in placeholders

2.0.0.RC5

  • More expressive Spring assertions (isNull, isNotNull, isTrue, isFalse)

2.0.0.RC4

  • AssertJ - fix bug with '%' in error message
  • Removed support for Jackson 1

2.0.0.RC3

  • Support for and() in AssertJ assert
  • asNumber() in AssertJ added
  • Allow description before inPath() in AssertJ

2.0.0.RC2

  • Fixed JsonPath bug #132
  • Fixed AssertJ number comparison with Jackson 2 #130
  • Fixed AssertJ asString() #131

2.0.0.RC1

  • Depends on Java 8
  • Some deprecated APis removed
  • Introduces AssertJ module
  • Introduces JsonPath module

Please do not hesitate to report issues.

1.31.0

  • Introduced DifferenceContext into DifferenceListener

1.30.0

  • Introduced DifferenceListener
  • Array comparison reports extra/missing elements when comparing with array order preserved.

1.29.1

  • Fixed error in JsonFluentAssert.ofLength error message
  • Fixed matcher handling when comparing arrays #111

1.29.0

  • [*] placeholder works even when ignoring array order

1.28.2

  • Fixing matcher pattern

1.28.1

  • Fixing NPE when accessing element of nonexistent array

1.28.0

  • Support for [*] placeholder in ignored path

1.27.0

  • Better array comparison and error messages

1.26.0

  • IDE friendly error messages
  • isStringEqualTo is chainable (thanks to @gsson)
  • Dropped support of Java 5
  • Automatic module names added

1.25.1

  • Support for Jackson BinaryNode

1.25.0

  • Support for ignoring paths whenIgnoringPaths()

1.24.0

  • Support for parametres in custom matchers ${json-unit.matches:matcherName}param

1.23.0

  • Support for custom matchers ${json-unit.matches:matcherName}

1.22.0

  • Support for Moshi

1.21.0

  • Better diff reporting for unordered arrays with single difference

1.20.0

  • Negative array indexes added (thanks roxspring)

1.19.0

  • isArray().thatContains(...) fluent assert added

1.18.0

  • Resource reading helper added

1.17.0

  • System property to specify JSON libraries to be used

1.16.1

  • Array pattern accepts non-word characters

1.16.0

  • isAbsent and isPresent checks take TREAT_NULL_AS_ABSENT into account

1.15.0

  • Dependency on slf4j made optional

1.14.1

  • Preferring org.json library to process JSONArray

1.14.0

  • Support for org.json library
  • Fix: Element out of array bounds is treated as missing

1.13.0

  • Support for any-* placeholders

1.12.1

  • Single quote values in expected String allowed

1.12.0

  • Lenient parsing of expected values

1.11.0

  • Option setting methods made deprecated if called after assertion in JsonFluentAssert
  • JsonFluentAssert constructors made private. Please file an issue if you need them.

1.10.0

  • Added support for IGNORING_EXTRA_ARRAY_ITEMS

1.9.0

  • Made compatible with Jackson 1.4

1.8.0

  • OSGi support thanks to @amergey

1.7.0

  • Support for Spring MVC tests assertions

1.6.1

  • Gson nodes are not reconverted

1.6.0

  • Added support for Hamcrest matchers

1.5.6

  • Fixed handling of empty value in the expected parameter

1.5.5

  • Support for dot in node name

1.5.4

  • Added isObject method to fluent assertions

1.5.3

  • Jackson 1 is preferred if the serialized class contains Jackson1 annotation

1.5.2

  • Added support for regular expressions

1.5.1

  • isStringEqualTo() added to fluent assertions
  • isArray added to fluent assertions

1.5.0

  • One runtime now supports Jackson 1.x, Jackson 2.x and Gson
  • Internal JsonUnit class changed in backwards incompatible way

1.3.0 + 0.3.0

  • Options renamed
  • assertJsonNot* asserts added
  • Support for online configuration in Hamcrest and standard asserts added

1.2.0 + 0.2.0

  • Error messages changed a bit when comparing structures
  • Refactoring of internal classes
  • Support for ignoring array order
  • Support for ignoring values
  • Support for ignoring extra fields

1.1.6 + 0.1.6

  • Treat null as absent added

1.1.5 + 0.1.5

  • Absence/presence tests added

1.1.4 + 0.1.4

  • Path to array in root fixed

1.1.3 + 0.1.3

  • Numeric comparison tolerance added

1.1.2 + 0.1.2

  • jsonStringEquals and jsonStringPartEquals added

1.1.1 + 0.1.1

  • Generics in JsonMatchers fixed

1.1.0 + 0.1.0

  • Simplified API
  • Invalid JSONs in String comparison quoted
  • Runtime incompatible (compile-time compatible) changes

1.0.0

  • Switched to Jackson 2.x
  • Fluent JsonAssert renamed to JsonFluentAssert

0.0.16

  • Fluent assertions made framework independent.

0.0.15

  • Switched from FEST to AssertJ

0.0.14

  • Modules refactored
  • Added support for FEST assert

0.0.13

  • Logging categories changed

0.0.12

  • Added logging

0.0.11

  • Ignore placeholder "${json-unit.ignore}" added

0.0.10

  • Text differences are closed in quotes

0.0.9

  • Matchers added

0.0.7

  • Made Java 5 compatible

0.0.6

  • assertJsonPartStructureEquals added

0.0.5

  • assertJsonPartEquals added

0.0.4

  • Better error messages in case of different types

0.0.3

  • Support for array types and other oddities in root

0.0.2

  • Support for nulls
Comments
  • Implement extracting/contains assertions

    Implement extracting/contains assertions

    AssertJ has really powerful extracting/contains mechanism. See: http://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html Section: Assertions on extracted properties/fields of iterable/array elements

    I think it worth to implement similar/same for fluent part of the library. I think we can just add assertJ core as a dependency and implement extracting method which returns: "AbstractListAssert" and we'll just leverage assertions they have. In the end we'll have something like: JsonFluentAssert.assertThatJson(jsonResponse.getBody().getObject()) .node("data").isPresent().isArray().ofLength(3) .extracting(“name”, “age”, “race.name”) .contains(tuple(“Boromir”, 37, “Man”), tuple(“Sam”, 38, “Hobbit”), tuple(“Legolas”, 1000, “Elf”));

    What do you think? If you are agree and like the idea, I can work on it.

    opened by xp-vit 22
  • Jackson handling of numbers is wrong?

    Jackson handling of numbers is wrong?

    Groovy script to demonstrate the problem:

    @Grab(group='com.fasterxml.jackson.core', module='jackson-databind', version='2.9.10.3')
    // @Grab(group='com.google.code.gson', module='gson', version='2.8.6')
    @Grab(group='net.javacrumbs.json-unit', module='json-unit', version='2.17.0')
    
    import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals
    
    class Test {
    
        BigDecimal demo;
    
        Test(BigDecimal demo) {
            this.demo = demo
        }
    }
    
    Test expected = new Test(new BigDecimal("2.00"))
    String actual = "{ \"demo\": 2.00 }"
    
    assertJsonEquals(expected, actual)
    
    

    org.opentest4j.AssertionFailedError: JSON documents are different: Different value found in node "demo", expected: <2> but was: <2.0>.

    But why??

    Using gson, it works just fine.

    opened by tlefevre 19
  • [Feature] Ignoring fields with keys and values

    [Feature] Ignoring fields with keys and values

    Hi, JsonUnit have method whenIgnoringPaths, that ignores only value of fields. It will be great to have additional method that ignores whole field with key and value. It will be usefull, if some fields are loaded asynchronously.

    opened by viclovsky 17
  • isEqualsTo with String node

    isEqualsTo with String node

    May I miss something but when trying the following assertion:

    JsonNode jsonNode = new ObjectMapper().readTree("{\"meta\":{\"version\":\"1.0\"}}");
    assertThatJson(jsonNode).node("meta.version").isEqualTo("1.0");
    

    I had the following error Different value found in node "meta.version". Expected '1.0', got '"1.0"'.

    I think it's because you are using .toString() instead of .asText().

    opened by kakawait 13
  • whenIgnoringPaths doesn't ignore missing paths

    whenIgnoringPaths doesn't ignore missing paths

    I'm using the AssertJ integration of JsonUnit (net.javacrumbs.json-unit:json-unit-assertj:2.6.1) and expected JsonAssert#whenIgnoringPaths(String ...) to ignore missing paths/keys as well.

    The documentation at https://github.com/lukas-krecan/JsonUnit/tree/json-unit-parent-2.6.1#ignorepaths says (emphasize by me):

    whenIgnoringPaths configuration option makes JsonUnit ignore the specified paths in the actual value. If the path matches, it's completely ignored. It may be missing, null or have any value.

    The following test is failing, though:

    assertThatJson("{\"root\":{\"foo\":1}}")
            .whenIgnoringPaths("root.bar", "missing")
            .isEqualTo("{\"root\":{\"foo\":1, \"bar\":2}, \"missing\":{\"quux\":\"test\"}}");
    
    net.javacrumbs.jsonunit.core.internal.JsonAssertError: JSON documents are different:
    Different keys found in node "", missing: "missing", expected: <{"missing":{"quux":"test"},"root":{"bar":2,"foo":1}}> but was: <{"root":{"foo":1}}>
    Different keys found in node "root", missing: "root.bar", expected: <{"bar":2,"foo":1}> but was: <{"foo":1}>
    
    	at net.javacrumbs.jsonunit.core.internal.ExceptionUtils.createException(ExceptionUtils.java:50)
    	at net.javacrumbs.jsonunit.core.internal.Diff.failIfDifferent(Diff.java:612)
    	at net.javacrumbs.jsonunit.assertj.JsonAssert.isEqualTo(JsonAssert.java:106)
    
    opened by joschi 11
  • an extension point similar to json-unit.regex

    an extension point similar to json-unit.regex

    Hi,

    I have a use case where I'd like to capture data during the comparison process, and store it into a variable. One way to do that would be to make an expression like so:

    ${json-unit.capture}variable-name

    Adding this directly to json-unit would not make a lot of sense as it is too specific to my needs.

    However, I was thinking possibly this could be accommodated as a generalisation of json-unit.regex, since they both take the same form:

    ${json-unit.<name>}<value>

    Would you consider a customisation point that allows the creation of expressions like so?

    Thanks

    opened by k1w1m8 11
  • Support asserting for absent element

    Support asserting for absent element

    Is your feature request related to a problem? Please describe.

    When we have a rather large json structure I want to validate the presence of some fields and absence of some. Currently, I need to write a hamcrest matcher in order to achieve that.

    Describe the solution you'd like

    It would be great if I can use something like ${json-unit.absent}.

    The json looks something like:

    [
      {
        name: '', taskVar: '...', processVar: '...', ....,
        customer: { ... },
        root: {
          ...
        }
      },
    ...
    ]
    

    It is an array with a lot of entries and each entry has complex structure. I would like to assert the presence of some and the explicit absence of certain elements in certain levels.

    e.g. Write something like:

    assertThatJson(json)
        .when(Option.IGNORING_EXTRA_FIELDS, Option.IGNORING_ARRAY_ORDER)
        .isEqualTo("["
                      + " {"
                      + "    taskVar: 'Process Task 1', processVar: 'Process 1', customerName: 'Gonzo',"
                      + "    root: {"
                      + "      customerName: 'Kermit 1', processVar: 'Process 1', taskVar: '${json-unit.absent}'"
                      + "    }"
                      + "  },"
                      + " {"
                      + "    taskVar: 'Process Task 2', processVar: 'Process 2', customerName: 'Fozzie',"
                      + "    root: {"
                      + "      customerName: 'Kermit 2', processVar: 'Process 2', taskVar: '${json-unit.absent}'"
                      + "    }"
                      + "  }"
                      + "]");
    

    Describe alternatives you've considered

    I know that I can use a hamcrest matchers, but that would mean that I need to add it every time and I would need to assert for null, but this is not 100% correct, since null doesn't have to mean that it is absent from the json.

    Additional context

    If the idea is interesting I can try to have a look at providing a PR for this.

    opened by filiphr 10
  • ClassCastException in

    ClassCastException in "isArray" (JsonAssertList)

    I am using AssertJ with 3.22.0 (latest at date) and json-unit 2.31.0

    The following code was working before:

        @Test
        void test_cce_error() {
           // import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
            String json = "[ [ \"a\", \"b\", \"c\", \"d\","
                    + " \"e\", \"f\", \"g\", \"h\", \"i\" ] ]";
            assertThatJson(json).inPath("$.[0]")
                                .isArray()
                                .elements(3 /* d */, 4 /* e */, 5 /* f */ , 6 /* g */, 7 /* h */, 8 /* i */ )
                                .containsExactly("d", "e", "f", "g", "h", "i");
        }
    

    However, this no longer work due to change in assertj:

    java.lang.ClassCastException: org.assertj.core.api.FactoryBasedNavigableListAssert cannot be cast to net.javacrumbs.jsonunit.assertj.JsonListAssert
    

    I tried to pinpoint the issue: the elements is creating a new list out of the current. By default (= case of JsonAssertList) it uses this implements:

      @SuppressWarnings("unchecked")
      @Override
      protected SELF newAbstractIterableAssert(Iterable<? extends ELEMENT> iterable) {
        checkArgument(iterable instanceof List, "Expecting %s to be a List", iterable);
        return (SELF) new FactoryBasedNavigableListAssert<>((List<? extends ELEMENT>) iterable,
                                                            FactoryBasedNavigableListAssert.class,
                                                            assertFactory);
      }
    

    I think that JsonAssertList should implement it and probably that assertj-core should make the class abstract and force an implementation of said method.

    If possible, I'll try to attach a PR with test.

    opened by glhez 9
  • Ignore element and child element order

    Ignore element and child element order

    I'm wondering whether JsonUnit can meeting my requirement: https://stackoverflow.com/questions/62277192/how-to-compare-2-json-by-ignoring-some-attributes-and-child-element-orders

    By roughly go thru document, I found IGNORING_ARRAY_ORDER and IGNORING_VALUES might help in my case.

    Yet I'm not sure whether I can get a "difference list" after applied those rules, rather than assertEquals.

    opened by tutufool 9
  • Allow differentiating between number and integer

    Allow differentiating between number and integer

    Although integer is not part of the JSON Schema data model (from the spec: Note that JSON Schema vocabularies are free to define their own extended type system. This should not be confused with the core data model types defined here. As an example, "integer" is a reasonable type for a vocabulary to define as a value for a keyword, but the data model makes no distinction between integers and other numbers.) in practice it is heavily used in vocabulary and allowed as a type by several applications, libraries, and frameworks (e.g. http://fasterxml.github.io/jackson-core/javadoc/2.10/com/fasterxml/jackson/core/JsonToken.html). For this reason, it would be helpful to be able distinguish between them, i.e. having an isNumber() and an isInteger() in JsonAssert.

    opened by joca-bt 9
  • Johnzon NodeFactory

    Johnzon NodeFactory

    Hello,

    I am using Apache Johnzon in a project as JSON-library, unfortunatly JsonUnit does not support Johnzon out of the box. I had a quick look at net.javacrumbs.jsonunit.core.internal.Converter - it doesn't seem to be plugable in a way where I just can add my custom NodeFactory. Are you interested in a PR for a Johnzon-based NodeFactory or maybe even a rewrite of this part of JsonUnit to use a completly modular system (ServiceLoader)?

    Regards, Alex

    opened by elexx 9
  • Bump spring.version from 5.3.23 to 6.0.3

    Bump spring.version from 5.3.23 to 6.0.3

    Bumps spring.version from 5.3.23 to 6.0.3. Updates spring-test from 5.3.23 to 6.0.3

    Release notes

    Sourced from spring-test's releases.

    v6.0.3

    :star: New Features

    • Throw PessimisticLockingFailureException/CannotAcquireLockException instead of plain ConcurrencyFailureException #29675
    • Introduce additional constructors in MockClientHttpRequest and MockClientHttpResponse #29670
    • Fall back to JdkClientHttpConnector as ClientHttpConnector #29645
    • Optimize object creation in RequestMappingHandlerMapping#handleNoMatch #29634
    • Align multipart codecs on client and server #29630
    • Deprecate "application/graphql+json" media type after spec changes #29617
    • HTTP interface client does not call FormHttpMessageWriter when writing form data #29615
    • ProblemDetail doesn't override the equals method #29606
    • Add title to SockJS iFrames for accessibility compliance #29594
    • Forbid loading of a test's ApplicationContext in AOT mode if AOT processing failed #29579
    • Deprecate JettyWebSocketClient in favor of StandardWebSocketClient #29576
    • Improve options to expose MessageSource formatted errors for a ProblemDetail response #29574
    • Make @ModelAttribute and @InitBinder annotations @Reflective #29572
    • Update BindingReflectionHintsRegistrar to support properties on records #29571

    :lady_beetle: Bug Fixes

    • Cannot use WebDAV methods in Spring MVC 6.0 anymore #29689
    • AnnotatedElementUtils.findMergedRepeatableAnnotations does not fetch results when other attributes exist in container annotation #29685
    • BeanWrapperImpl NPE in setWrappedInstance after invoking getPropertyValue #29681
    • SpEL ConstructorReference does not generate AST representation of arrays #29665
    • NullPointerException in BindingReflectionHintsRegistrar for anonymous classes #29657
    • DataBufferInputStream violates InputStream contract #29642
    • Component scanning no longer uses component index for @Named, @ManagedBean, and other Jakarta annotations #29641
    • Fix canWrite in PartHttpMessageWriter #29631
    • NoHandlerFoundException mistakenly returns request headers from ErrorResponse#getHeaders #29626
    • URI override for @HttpExchange doesn't work if there are both URI and @PathVariable method parameters #29624
    • Unnecessary parameter name introspection for constructor-arg resolution (leading to LocalVariableTableParameterNameDiscoverer warnings) #29612
    • Set detail from reason in both constructors of ResponseStatusException #29608
    • SpEL string literal misses single quotation marks in toStringAST() #29604
    • AOT code generation fails for bean of type boolean #29598
    • request-scoped bean with @Lazy fails in native image (due to missing detection of CGLIB lazy resolution proxies) #29584
    • 500 error from WebFlux when parsing Content-Type leads to InvalidMediaTypeException #29565
    • ConcurrentLruCache implementation is using too much heap memory #29520
    • Duplicate key violation gets translated to DataIntegrityViolationException instead of DuplicateKeyException in Spring 6 #29511
    • SpEL: Two double quotes are replaced by one double quote in single quoted String literal (and vice versa) #28356

    :notebook_with_decorative_cover: Documentation

    • Fix ErrorResponse#type documentation #29632
    • Fix typo in observability documentation #29590
    • Consistent documentation references to Jakarta WebSocket (2.1) #29581
    • Unrendered asciidoc headings in reference documentation #29569
    • Document observability support #29524

    :hammer: Dependency Upgrades

    ... (truncated)

    Commits
    • 0fbc94f Release v6.0.3
    • 6e08c56 Improve Javadoc for RepeatableContainers
    • fb6d3f5 Remove duplicated test code
    • 6fe5652 Support non-standard HTTP methods in FrameworkServlet
    • ca68bbc Upgrade to Reactor 2022.0.1
    • e7bcb48 Remove obsolete AttributeMethods.hasOnlyValueAttribute() method
    • 433b1c4 Support repeatable annotation containers with multiple attributes
    • 0b08246 Revise RepeatableContainersTests
    • c7bdfbe Add missing Javadoc
    • 618989d Update copyright date
    • Additional commits viewable in compare view

    Updates spring-webmvc from 5.3.23 to 6.0.3

    Release notes

    Sourced from spring-webmvc's releases.

    v6.0.3

    :star: New Features

    • Throw PessimisticLockingFailureException/CannotAcquireLockException instead of plain ConcurrencyFailureException #29675
    • Introduce additional constructors in MockClientHttpRequest and MockClientHttpResponse #29670
    • Fall back to JdkClientHttpConnector as ClientHttpConnector #29645
    • Optimize object creation in RequestMappingHandlerMapping#handleNoMatch #29634
    • Align multipart codecs on client and server #29630
    • Deprecate "application/graphql+json" media type after spec changes #29617
    • HTTP interface client does not call FormHttpMessageWriter when writing form data #29615
    • ProblemDetail doesn't override the equals method #29606
    • Add title to SockJS iFrames for accessibility compliance #29594
    • Forbid loading of a test's ApplicationContext in AOT mode if AOT processing failed #29579
    • Deprecate JettyWebSocketClient in favor of StandardWebSocketClient #29576
    • Improve options to expose MessageSource formatted errors for a ProblemDetail response #29574
    • Make @ModelAttribute and @InitBinder annotations @Reflective #29572
    • Update BindingReflectionHintsRegistrar to support properties on records #29571

    :lady_beetle: Bug Fixes

    • Cannot use WebDAV methods in Spring MVC 6.0 anymore #29689
    • AnnotatedElementUtils.findMergedRepeatableAnnotations does not fetch results when other attributes exist in container annotation #29685
    • BeanWrapperImpl NPE in setWrappedInstance after invoking getPropertyValue #29681
    • SpEL ConstructorReference does not generate AST representation of arrays #29665
    • NullPointerException in BindingReflectionHintsRegistrar for anonymous classes #29657
    • DataBufferInputStream violates InputStream contract #29642
    • Component scanning no longer uses component index for @Named, @ManagedBean, and other Jakarta annotations #29641
    • Fix canWrite in PartHttpMessageWriter #29631
    • NoHandlerFoundException mistakenly returns request headers from ErrorResponse#getHeaders #29626
    • URI override for @HttpExchange doesn't work if there are both URI and @PathVariable method parameters #29624
    • Unnecessary parameter name introspection for constructor-arg resolution (leading to LocalVariableTableParameterNameDiscoverer warnings) #29612
    • Set detail from reason in both constructors of ResponseStatusException #29608
    • SpEL string literal misses single quotation marks in toStringAST() #29604
    • AOT code generation fails for bean of type boolean #29598
    • request-scoped bean with @Lazy fails in native image (due to missing detection of CGLIB lazy resolution proxies) #29584
    • 500 error from WebFlux when parsing Content-Type leads to InvalidMediaTypeException #29565
    • ConcurrentLruCache implementation is using too much heap memory #29520
    • Duplicate key violation gets translated to DataIntegrityViolationException instead of DuplicateKeyException in Spring 6 #29511
    • SpEL: Two double quotes are replaced by one double quote in single quoted String literal (and vice versa) #28356

    :notebook_with_decorative_cover: Documentation

    • Fix ErrorResponse#type documentation #29632
    • Fix typo in observability documentation #29590
    • Consistent documentation references to Jakarta WebSocket (2.1) #29581
    • Unrendered asciidoc headings in reference documentation #29569
    • Document observability support #29524

    :hammer: Dependency Upgrades

    ... (truncated)

    Commits
    • 0fbc94f Release v6.0.3
    • 6e08c56 Improve Javadoc for RepeatableContainers
    • fb6d3f5 Remove duplicated test code
    • 6fe5652 Support non-standard HTTP methods in FrameworkServlet
    • ca68bbc Upgrade to Reactor 2022.0.1
    • e7bcb48 Remove obsolete AttributeMethods.hasOnlyValueAttribute() method
    • 433b1c4 Support repeatable annotation containers with multiple attributes
    • 0b08246 Revise RepeatableContainersTests
    • c7bdfbe Add missing Javadoc
    • 618989d Update copyright date
    • Additional commits viewable in compare view

    Updates spring-web from 5.3.23 to 6.0.3

    Release notes

    Sourced from spring-web's releases.

    v6.0.3

    :star: New Features

    • Throw PessimisticLockingFailureException/CannotAcquireLockException instead of plain ConcurrencyFailureException #29675
    • Introduce additional constructors in MockClientHttpRequest and MockClientHttpResponse #29670
    • Fall back to JdkClientHttpConnector as ClientHttpConnector #29645
    • Optimize object creation in RequestMappingHandlerMapping#handleNoMatch #29634
    • Align multipart codecs on client and server #29630
    • Deprecate "application/graphql+json" media type after spec changes #29617
    • HTTP interface client does not call FormHttpMessageWriter when writing form data #29615
    • ProblemDetail doesn't override the equals method #29606
    • Add title to SockJS iFrames for accessibility compliance #29594
    • Forbid loading of a test's ApplicationContext in AOT mode if AOT processing failed #29579
    • Deprecate JettyWebSocketClient in favor of StandardWebSocketClient #29576
    • Improve options to expose MessageSource formatted errors for a ProblemDetail response #29574
    • Make @ModelAttribute and @InitBinder annotations @Reflective #29572
    • Update BindingReflectionHintsRegistrar to support properties on records #29571

    :lady_beetle: Bug Fixes

    • Cannot use WebDAV methods in Spring MVC 6.0 anymore #29689
    • AnnotatedElementUtils.findMergedRepeatableAnnotations does not fetch results when other attributes exist in container annotation #29685
    • BeanWrapperImpl NPE in setWrappedInstance after invoking getPropertyValue #29681
    • SpEL ConstructorReference does not generate AST representation of arrays #29665
    • NullPointerException in BindingReflectionHintsRegistrar for anonymous classes #29657
    • DataBufferInputStream violates InputStream contract #29642
    • Component scanning no longer uses component index for @Named, @ManagedBean, and other Jakarta annotations #29641
    • Fix canWrite in PartHttpMessageWriter #29631
    • NoHandlerFoundException mistakenly returns request headers from ErrorResponse#getHeaders #29626
    • URI override for @HttpExchange doesn't work if there are both URI and @PathVariable method parameters #29624
    • Unnecessary parameter name introspection for constructor-arg resolution (leading to LocalVariableTableParameterNameDiscoverer warnings) #29612
    • Set detail from reason in both constructors of ResponseStatusException #29608
    • SpEL string literal misses single quotation marks in toStringAST() #29604
    • AOT code generation fails for bean of type boolean #29598
    • request-scoped bean with @Lazy fails in native image (due to missing detection of CGLIB lazy resolution proxies) #29584
    • 500 error from WebFlux when parsing Content-Type leads to InvalidMediaTypeException #29565
    • ConcurrentLruCache implementation is using too much heap memory #29520
    • Duplicate key violation gets translated to DataIntegrityViolationException instead of DuplicateKeyException in Spring 6 #29511
    • SpEL: Two double quotes are replaced by one double quote in single quoted String literal (and vice versa) #28356

    :notebook_with_decorative_cover: Documentation

    • Fix ErrorResponse#type documentation #29632
    • Fix typo in observability documentation #29590
    • Consistent documentation references to Jakarta WebSocket (2.1) #29581
    • Unrendered asciidoc headings in reference documentation #29569
    • Document observability support #29524

    :hammer: Dependency Upgrades

    ... (truncated)

    Commits
    • 0fbc94f Release v6.0.3
    • 6e08c56 Improve Javadoc for RepeatableContainers
    • fb6d3f5 Remove duplicated test code
    • 6fe5652 Support non-standard HTTP methods in FrameworkServlet
    • ca68bbc Upgrade to Reactor 2022.0.1
    • e7bcb48 Remove obsolete AttributeMethods.hasOnlyValueAttribute() method
    • 433b1c4 Support repeatable annotation containers with multiple attributes
    • 0b08246 Revise RepeatableContainersTests
    • c7bdfbe Add missing Javadoc
    • 618989d Update copyright date
    • Additional commits viewable in compare view

    Updates spring-webflux from 5.3.23 to 6.0.3

    Release notes

    Sourced from spring-webflux's releases.

    v6.0.3

    :star: New Features

    • Throw PessimisticLockingFailureException/CannotAcquireLockException instead of plain ConcurrencyFailureException #29675
    • Introduce additional constructors in MockClientHttpRequest and MockClientHttpResponse #29670
    • Fall back to JdkClientHttpConnector as ClientHttpConnector #29645
    • Optimize object creation in RequestMappingHandlerMapping#handleNoMatch #29634
    • Align multipart codecs on client and server #29630
    • Deprecate "application/graphql+json" media type after spec changes #29617
    • HTTP interface client does not call FormHttpMessageWriter when writing form data #29615
    • ProblemDetail doesn't override the equals method #29606
    • Add title to SockJS iFrames for accessibility compliance #29594
    • Forbid loading of a test's ApplicationContext in AOT mode if AOT processing failed #29579
    • Deprecate JettyWebSocketClient in favor of StandardWebSocketClient #29576
    • Improve options to expose MessageSource formatted errors for a ProblemDetail response #29574
    • Make @ModelAttribute and @InitBinder annotations @Reflective #29572
    • Update BindingReflectionHintsRegistrar to support properties on records #29571

    :lady_beetle: Bug Fixes

    • Cannot use WebDAV methods in Spring MVC 6.0 anymore #29689
    • AnnotatedElementUtils.findMergedRepeatableAnnotations does not fetch results when other attributes exist in container annotation #29685
    • BeanWrapperImpl NPE in setWrappedInstance after invoking getPropertyValue #29681
    • SpEL ConstructorReference does not generate AST representation of arrays #29665
    • NullPointerException in BindingReflectionHintsRegistrar for anonymous classes #29657
    • DataBufferInputStream violates InputStream contract #29642
    • Component scanning no longer uses component index for @Named, @ManagedBean, and other Jakarta annotations #29641
    • Fix canWrite in PartHttpMessageWriter #29631
    • NoHandlerFoundException mistakenly returns request headers from ErrorResponse#getHeaders #29626
    • URI override for @HttpExchange doesn't work if there are both URI and @PathVariable method parameters #29624
    • Unnecessary parameter name introspection for constructor-arg resolution (leading to LocalVariableTableParameterNameDiscoverer warnings) #29612
    • Set detail from reason in both constructors of ResponseStatusException #29608
    • SpEL string literal misses single quotation marks in toStringAST() #29604
    • AOT code generation fails for bean of type boolean #29598
    • request-scoped bean with @Lazy fails in native image (due to missing detection of CGLIB lazy resolution proxies) #29584
    • 500 error from WebFlux when parsing Content-Type leads to InvalidMediaTypeException #29565
    • ConcurrentLruCache implementation is using too much heap memory #29520
    • Duplicate key violation gets translated to DataIntegrityViolationException instead of DuplicateKeyException in Spring 6 #29511
    • SpEL: Two double quotes are replaced by one double quote in single quoted String literal (and vice versa) #28356

    :notebook_with_decorative_cover: Documentation

    • Fix ErrorResponse#type documentation #29632
    • Fix typo in observability documentation #29590
    • Consistent documentation references to Jakarta WebSocket (2.1) #29581
    • Unrendered asciidoc headings in reference documentation #29569
    • Document observability support #29524

    :hammer: Dependency Upgrades

    ... (truncated)

    Commits
    • 0fbc94f Release v6.0.3
    • 6e08c56 Improve Javadoc for RepeatableContainers
    • fb6d3f5 Remove duplicated test code
    • 6fe5652 Support non-standard HTTP methods in FrameworkServlet
    • ca68bbc Upgrade to Reactor 2022.0.1
    • e7bcb48 Remove obsolete AttributeMethods.hasOnlyValueAttribute() method
    • 433b1c4 Support repeatable annotation containers with multiple attributes
    • 0b08246 Revise RepeatableContainersTests
    • c7bdfbe Add missing Javadoc
    • 618989d Update copyright date
    • Additional commits viewable in compare view

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies java 
    opened by dependabot[bot] 0
  • Bump slf4j.version from 1.7.36 to 2.0.6

    Bump slf4j.version from 1.7.36 to 2.0.6

    Bumps slf4j.version from 1.7.36 to 2.0.6. Updates slf4j-simple from 1.7.36 to 2.0.6

    Commits
    • 5ff6f2c prepare for release 2.0.6
    • 2f4aa75 fix SLF4J-575
    • 363f0a5 remove unused parts
    • 171679b SLF4J-574: Add full OSGi headers, especially "uses" clauses
    • 921b5b3 fix FUNDING file
    • e02244c fix FUNDING file
    • 441d458 fix FUNDING file
    • f5e741b add FUNDING file
    • 2e71327 remove unused log4j dependency in the version definition section of pom.xml
    • 3ff2a30 start work on 2.0.6-SNAPSHOT
    • Additional commits viewable in compare view

    Updates slf4j-api from 1.7.36 to 2.0.6

    Commits
    • 5ff6f2c prepare for release 2.0.6
    • 2f4aa75 fix SLF4J-575
    • 363f0a5 remove unused parts
    • 171679b SLF4J-574: Add full OSGi headers, especially "uses" clauses
    • 921b5b3 fix FUNDING file
    • e02244c fix FUNDING file
    • 441d458 fix FUNDING file
    • f5e741b add FUNDING file
    • 2e71327 remove unused log4j dependency in the version definition section of pom.xml
    • 3ff2a30 start work on 2.0.6-SNAPSHOT
    • Additional commits viewable in compare view

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies java 
    opened by dependabot[bot] 0
  • Bump spring-web from 5.3.23 to 6.0.0 in /json-unit-spring

    Bump spring-web from 5.3.23 to 6.0.0 in /json-unit-spring

    Bumps spring-web from 5.3.23 to 6.0.0.

    Release notes

    Sourced from spring-web's releases.

    v6.0.0

    See What's New in Spring Framework 6.x and Upgrading to Spring Framework 6.x for upgrade instructions and details of new features.

    :star: New Features

    • Avoid direct URL construction and URL equality checks #29486
    • Simplify creating RFC 7807 responses from functional endpoints #29462
    • Allow test classes to provide runtime hints via declarative mechanisms #29455

    :notebook_with_decorative_cover: Documentation

    • Align javadoc of DefaultParameterNameDiscoverer with its behavior #29494
    • Document AOT support in the TestContext framework #29482
    • Document Ahead of Time processing in the reference guide #29350

    :hammer: Dependency Upgrades

    • Upgrade to Reactor 2022.0.0 #29465

    :heart: Contributors

    Thank you to all the contributors who worked on this release:

    @​ophiuhus and @​wilkinsona

    v6.0.0-RC4

    :star: New Features

    • Introduce DataFieldMaxValueIncrementer for SQL Server sequences #29447
    • Introduce findAllAnnotationsOnBean variant on ListableBeanFactory #29446
    • Introduce support for Jakarta WebSocket 2.1 #29436
    • Allow @ControllerAdvice in WebFlux to handle exceptions before a handler is selected #22991

    :lady_beetle: Bug Fixes

    • Bean with unresolved generics do not use fallback algorithms with AOT #29454
    • TomcatRequestUpgradeStrategy is not compatible with Tomcat 10.1 #29434
    • Autowiring of a generic type produced by a factory bean fails after AOT processing #29385

    :notebook_with_decorative_cover: Documentation

    • Reference PDF containing full docs not available #28451

    :hammer: Dependency Upgrades

    • Revisit Servlet API baseline: Servlet 6.0 in the build, Servlet 5.0 compatibility at runtime #29435
    • Upgrade to Context Propagation 1.0.0 #29442
    • Upgrade to Jackson 2.14.0 #29351
    • Upgrade to Micrometer 1.10.0 #29441

    ... (truncated)

    Commits
    • 5a30a43 Release v6.0.0
    • 42856ba Add milestone repo for optional Netty 5 support
    • 9be6cea Polishing deprecated methods
    • 37b4391 Align javadoc of DefaultParameterNameDiscoverer with its behavior
    • 09a58a5 Polish
    • 10f4ad1 Assert fixed in DefaultErrorResponseBuilder
    • 9457ed3 Document AOT support in the TestContext framework
    • 074ec97 Fix section formatting in the testing chapter
    • 9ede4af Revert "Ignore HttpComponents Javadoc"
    • bfc1251 Merge branch '5.3.x'
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the Security Alerts page.
    dependencies java 
    opened by dependabot[bot] 0
  • Diff message is lost when using jsonEquals with rest-assured

    Diff message is lost when using jsonEquals with rest-assured

    Describe the bug I'm not 100% sure if this is a rest-assured issue or a JsonUnit issue, but I think it's a JsonUnit issue. One of the reasons I like this project is because of the useful diff messages when an assertion fails.

    • When using this with the hamcrest assertThat, I can see the diff message as expected.
    • However, when I use the exact same code with rest assured, the useful diff message is lost, and I just get a generic "expected x but found y" message.

    Steps to Reproduce

            given()
                    .baseUri("https://reqres.in")
                    .basePath("api")
            .when()
                    .get("users/1")
            .then()
                    .body("", jsonEquals(getResultContent()));
    

    Expected Result:

    Expected: {
      "data": {
        "id": 15,
        "email": "[email protected]",
        "first_name": "George",
        "last_name": "Blunt",
        "avatar": "https://reqres.in/img/faces/1-image.jpg"
      },
      "support": {
        "url": "https://reqres.in/#support-heading",
        "text": "To keep ReqRes free, contributions towards server costs are appreciated!"
      }
    }
         but: JSON documents are different:
    Different value found in node "data.id", expected <15> but was <1>.
    Different value found in node "data.last_name", expected <"Blunt"> but was <"Bluth">.
    

    Actual Result

    Expected: {
      "data": {
        "id": 15,
        "email": "[email protected]",
        "first_name": "George",
        "last_name": "Blunt",
        "avatar": "https://reqres.in/img/faces/1-image.jpg"
      },
      "support": {
        "url": "https://reqres.in/#support-heading",
        "text": "To keep ReqRes free, contributions towards server costs are appreciated!"
      }
    }
      Actual: <{data={id=1, [email protected], first_name=George, last_name=Bluth, avatar=https://reqres.in/img/faces/1-image.jpg}, support={url=https://reqres.in/#support-heading, text=To keep ReqRes free, contributions towards server costs are appreciated!}}>
    
    • Changing the assertion to use .body(jsonPartEquals("", getResultContent())); produces the same result
    • I wrote my own custom matcher which is a wrapper for the jsonEquals matcher (and saves the diff message), and when I use that matcher I do see the diff message in rest-assured as expected
    • Note that in our case, we have some helper methods which read the expected content from an external file (based on the test method name). Below is the content of that file:
    {
      "data": {
        "id": 15,
        "email": "[email protected]",
        "first_name": "George",
        "last_name": "Blunt",
        "avatar": "https://reqres.in/img/faces/1-image.jpg"
      },
      "support": {
        "url": "https://reqres.in/#support-heading",
        "text": "To keep ReqRes free, contributions towards server costs are appreciated!"
      }
    }
    

    Versions Rest Assured 5.2.0 JsonUnit 2.36.0

    opened by mmcdermo2 1
  • Picking gson instance

    Picking gson instance

    The documentation section "Selecting underlying library" mentions how to pick gson but how do you pick a specific instance (e.g. the one with the registered type adapters you need)?

    opened by nickarls 2
  • Ease assertions on content of JSON files

    Ease assertions on content of JSON files

    Is your feature request related to a problem? Please describe. There is no simple way provided by json-unit-assertj module to assert JSON directly from a JSON file. It is always required to read the file content before we can use assertThatJson.

    Describe the solution you'd like Logic to parse a JSON file should be encapsulated in a new class (e.g. JsonFileAssert).

    This class should only read the file and delegate JSON assertions on file content to ConfigurableJsonAssert (e.g. hasContent()):

    assertThatJsonFile(File("file.json")).hasContent().node("key").isEqualTo("value");
    

    Describe alternatives you've considered N/A

    Additional context I can provide a PR for this change

    opened by fstaudt 0
Owner
Lukáš Křečan
Lukáš Křečan
MapNeat is a JVM library written in Kotlin that provides an easy to use DSL (Domain Specific Language) for transforming JSON to JSON, XML to JSON, POJO to JSON in a declarative way.

MapNeat is a JVM library written in Kotlin that provides an easy to use DSL (Domain Specific Language) for transforming JSON to JSON, XML to JSON, POJ

Andrei Ciobanu 59 Sep 17, 2022
Write JSON unit tests in less code. Great for testing REST interfaces.

JSONassert Write JSON unit tests in less code. Great for testing REST interfaces. Summary Write JSON tests as if you are comparing a string. Under the

Skyscreamer 899 Dec 29, 2022
JSON to JSON transformation library written in Java.

Jolt JSON to JSON transformation library written in Java where the "specification" for the transform is itself a JSON document. Useful For Transformin

Bazaarvoice 1.3k Dec 30, 2022
Generate Java types from JSON or JSON Schema and annotates those types for data-binding with Jackson, Gson, etc

jsonschema2pojo jsonschema2pojo generates Java types from JSON Schema (or example JSON) and can annotate those types for data-binding with Jackson 2.x

Joe Littlejohn 5.9k Jan 5, 2023
Essential-json - JSON without fuss

Essential JSON Essential JSON Rationale Description Usage Inclusion in your project Parsing JSON Rendering JSON Building JSON Converting to JSON Refer

Claude Brisson 1 Nov 9, 2021
A simple java JSON deserializer that can convert a JSON into a java object in an easy way

JSavON A simple java JSON deserializer that can convert a JSON into a java object in an easy way. This library also provide a strong object convertion

null 0 Mar 18, 2022
A 250 lines single-source-file hackable JSON deserializer for the JVM. Reinventing the JSON wheel.

JSON Wheel Have you ever written scripts in Java 11+ and needed to operate on some JSON string? Have you ever needed to extract just that one deeply-n

Roman Böhm 14 Jan 4, 2023
Java Concolic Unit Testing Engine

jCUTE The Java Concolic Unit Testing Engine (jCUTE) automatically generates unit tests for Java programs. Concolic execution combines randomized concr

Open Systems Laboratory 81 Nov 7, 2022
Java friendly DSL for defining TestFX tests

TestFX-DSL aims to bring DSL capabilities on top of TestFX. Inspired by Geb, this DSL enables a fluent interface design on top of the facilities exposed by TestFX.

Andres Almiray 5 Aug 21, 2019
High performance JVM JSON library

DSL-JSON library Fastest JVM (Java/Android/Scala/Kotlin) JSON library with advanced compile-time databinding support. Compatible with DSL Platform. Ja

New Generation Software Ltd 835 Jan 2, 2023
A Java serialization/deserialization library to convert Java Objects into JSON and back

Gson Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to a

Google 21.7k Jan 8, 2023
High-performance JSON parser

HikariJSON A High-performance JSON parser. HikariJSON is targeted exclusively at Java 8. If you need legacy support, there are several decent librarie

Brett Wooldridge 454 Dec 31, 2022
Screaming fast JSON parsing and serialization library for Android.

#LoganSquare The fastest JSON parsing and serializing library available for Android. Based on Jackson's streaming API, LoganSquare is able to consiste

BlueLine Labs 3.2k Dec 18, 2022
A modern JSON library for Kotlin and Java.

Moshi Moshi is a modern JSON library for Android and Java. It makes it easy to parse JSON into Java objects: String json = ...; Moshi moshi = new Mos

Square 8.7k Dec 31, 2022
A fast JSON parser/generator for Java.

fastjson Fastjson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON str

Alibaba 25.1k Dec 31, 2022
JSON query and transformation language

JSLT JSLT is a complete query and transformation language for JSON. The language design is inspired by jq, XPath, and XQuery. JSLT can be used as: a q

Schibsted Media Group 510 Dec 30, 2022
Sawmill is a JSON transformation Java library

Update: June 25, 2020 The 2.0 release of Sawmill introduces a breaking change to the GeoIpProcessor to comply with the updated license of the MaxMind

Logz.io 100 Jan 1, 2023
Genson a fast & modular Java <> Json library

Genson Genson is a complete json <-> java conversion library, providing full databinding, streaming and much more. Gensons main strengths? Easy to use

null 212 Jan 3, 2023
A reference implementation of a JSON package in Java.

JSON in Java [package org.json] Click here if you just want the latest release jar file. Overview JSON is a light-weight language-independent data int

Sean Leary 4.2k Jan 6, 2023