Skip to content

Commit

Permalink
#859 Support for JsonPath in Spring
Browse files Browse the repository at this point in the history
  • Loading branch information
lukas-krecan committed Nov 28, 2024
1 parent 3ba3d49 commit 2645ca7
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 74 deletions.
24 changes: 1 addition & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ See the [tests](https://github.com/lukas-krecan/JsonUnit/blob/master/json-unit-k
JsonUnit support all this features regardless of API you use.

## <a name="jsonpath"></a>JsonPath support
You can use JsonPath navigation together with JsonUnit. It has native support in AssertJ integration, so you can do something like this:
You can use JsonPath navigation together with JsonUnit. It has native support in AssertJ and Spring integration, so you can do something like this:

```java
// AssertJ style
Expand All @@ -397,28 +397,6 @@ assertThatJson(json)
));
```

For the other API styles you have to first import JsonPath support module
```xml
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-json-path</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
```

and then use instead of actual value

```xml
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']");
```

## <a name="ignorevalues"></a>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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
*/
package net.javacrumbs.jsonunit.spring;

import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import net.javacrumbs.jsonunit.core.Configuration;
import net.javacrumbs.jsonunit.core.internal.Path;
import net.javacrumbs.jsonunit.core.internal.matchers.InternalMatcher;
Expand All @@ -24,18 +25,21 @@
abstract class AbstractSpringMatcher {
private final Path path;
private final Configuration configuration;
private final BiConsumer<Object, InternalMatcher> matcher;
private final Consumer<InternalMatcher> matcher;
private final Function<Object, Object> jsonTransformer;

AbstractSpringMatcher(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull BiConsumer<Object, InternalMatcher> matcher) {
@NotNull Consumer<InternalMatcher> matcher,
@NotNull Function<Object, Object> jsonTransformer) {
this.path = path;
this.configuration = configuration;
this.matcher = matcher;
this.jsonTransformer = jsonTransformer;
}

void doMatch(Object actual) {
matcher.accept(actual, new InternalMatcher(actual, path, "", configuration));
matcher.accept(new InternalMatcher(jsonTransformer.apply(actual), path, "", configuration));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
package net.javacrumbs.jsonunit.spring;

import java.math.BigDecimal;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import net.javacrumbs.jsonunit.core.Configuration;
import net.javacrumbs.jsonunit.core.ConfigurationWhen;
import net.javacrumbs.jsonunit.core.Option;
import net.javacrumbs.jsonunit.core.internal.Path;
import net.javacrumbs.jsonunit.core.internal.matchers.InternalMatcher;
import net.javacrumbs.jsonunit.core.listener.DifferenceListener;
import net.javacrumbs.jsonunit.jsonpath.JsonPathAdapter;
import org.hamcrest.Matcher;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -35,17 +37,27 @@
abstract class AbstractSpringMatchers<ME, MATCHER> {
final Path path;
final Configuration configuration;
final Function<Object, Object> jsonTransformer;

AbstractSpringMatchers(@NotNull Path path, @NotNull Configuration configuration) {
AbstractSpringMatchers(
@NotNull Path path, @NotNull Configuration configuration, Function<Object, Object> jsonTransformer) {
this.path = path;
this.configuration = configuration;
this.jsonTransformer = jsonTransformer;
}

@NotNull
abstract MATCHER matcher(@NotNull BiConsumer<Object, InternalMatcher> matcher);
abstract MATCHER matcher(@NotNull Consumer<InternalMatcher> matcher);

@NotNull
abstract ME matchers(@NotNull Path path, @NotNull Configuration configuration);
abstract ME matchers(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Function<Object, Object> jsonTransformer);

protected ME matchers(@NotNull Path path, @NotNull Configuration configuration) {
return matchers(path, configuration, jsonTransformer);
}

/**
* Creates a matcher object that only compares given node.
Expand All @@ -55,14 +67,21 @@ abstract class AbstractSpringMatchers<ME, MATCHER> {
* this.mockMvc.perform(get("/sample").accept(MediaType.APPLICATION_JSON)).andExpect(json().node("root.test[0]").isEqualTo("1"));
* </code>
*
* @param newPath
* @return object comparing only node given by path.
*/
@NotNull
public ME node(String newPath) {
return matchers(path.copy(newPath), configuration);
}

/**
* Uses JsonPath to extract values from the actual value.
*/
@NotNull
public ME inPath(String path) {
return matchers(this.path, configuration, json -> JsonPathAdapter.inPath(json, path));
}

/**
* Sets the placeholder that can be used to ignore values.
* The default value is ${json-unit.ignore}
Expand Down Expand Up @@ -143,7 +162,7 @@ public ME when(
*/
@NotNull
public MATCHER isEqualTo(@Nullable Object expected) {
return matcher((actual, ctx) -> ctx.isEqualTo(expected));
return matcher(ctx -> ctx.isEqualTo(expected));
}

/**
Expand All @@ -152,7 +171,7 @@ public MATCHER isEqualTo(@Nullable Object expected) {
*/
@NotNull
public MATCHER isStringEqualTo(@Nullable final String expected) {
return matcher((actual, ctx) -> ctx.isStringEqualTo(expected));
return matcher(ctx -> ctx.isStringEqualTo(expected));
}

/**
Expand All @@ -161,63 +180,63 @@ public MATCHER isStringEqualTo(@Nullable final String expected) {
*/
@NotNull
public MATCHER isNotEqualTo(@Nullable Object expected) {
return matcher((actual, ctx) -> ctx.isNotEqualTo(expected));
return matcher(ctx -> ctx.isNotEqualTo(expected));
}

/**
* Fails if the node exists.
*/
@NotNull
public MATCHER isAbsent() {
return matcher((actual, ctx) -> ctx.isAbsent());
return matcher(ctx -> ctx.isAbsent());
}

/**
* Fails if the node is missing.
*/
@NotNull
public MATCHER isPresent() {
return matcher((actual, ctx) -> ctx.isPresent());
return matcher(InternalMatcher::isPresent);
}

/**
* Fails if the selected JSON is not an Array or is not present.
*/
@NotNull
public MATCHER isArray() {
return matcher((actual, ctx) -> ctx.isArray());
return matcher(InternalMatcher::isArray);
}

/**
* Fails if the selected JSON is not an Object or is not present.
*/
@NotNull
public MATCHER isObject() {
return matcher((actual, ctx) -> ctx.isObject());
return matcher(InternalMatcher::isObject);
}

/**
* Fails if the selected JSON is not a String or is not present.
*/
@NotNull
public MATCHER isString() {
return matcher((actual, ctx) -> ctx.isString());
return matcher(InternalMatcher::isString);
}

/**
* Fails if selected JSON is not null.
*/
@NotNull
public MATCHER isNull() {
return matcher((actual, ctx) -> ctx.isNull());
return matcher(InternalMatcher::isNull);
}

/**
* Fails if selected JSON is null.
*/
@NotNull
public MATCHER isNotNull() {
return matcher((actual, ctx) -> ctx.isNotNull());
return matcher(InternalMatcher::isNotNull);
}

/**
Expand All @@ -234,7 +253,7 @@ public MATCHER isNotNull() {
*/
@NotNull
public MATCHER matches(@NotNull final Matcher<?> matcher) {
return matcher((actual, ctx) -> ctx.matches(matcher));
return matcher(ctx -> ctx.matches(matcher));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
*/
package net.javacrumbs.jsonunit.spring;

import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import net.javacrumbs.jsonunit.core.Configuration;
import net.javacrumbs.jsonunit.core.internal.Path;
import net.javacrumbs.jsonunit.core.internal.matchers.InternalMatcher;
Expand All @@ -37,36 +38,40 @@
*/
public class JsonUnitRequestMatchers extends AbstractSpringMatchers<JsonUnitRequestMatchers, RequestMatcher> {

private JsonUnitRequestMatchers(Path path, Configuration configuration) {
super(path, configuration);
private JsonUnitRequestMatchers(Path path, Configuration configuration, Function<Object, Object> jsonTransformer) {
super(path, configuration, jsonTransformer);
}

@NotNull
@Override
RequestMatcher matcher(@NotNull BiConsumer<Object, InternalMatcher> matcher) {
return new JsonRequestMatcher(path, configuration, matcher);
RequestMatcher matcher(@NotNull Consumer<InternalMatcher> matcher) {
return new JsonRequestMatcher(path, configuration, matcher, jsonTransformer);
}

@Override
@NotNull
JsonUnitRequestMatchers matchers(@NotNull Path path, @NotNull Configuration configuration) {
return new JsonUnitRequestMatchers(path, configuration);
JsonUnitRequestMatchers matchers(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Function<Object, Object> jsonTransformer) {
return new JsonUnitRequestMatchers(path, configuration, jsonTransformer);
}

/**
* Creates JsonUnitResultMatchers to be used for JSON assertions.
*/
@NotNull
public static JsonUnitRequestMatchers json() {
return new JsonUnitRequestMatchers(Path.root(), Configuration.empty());
return new JsonUnitRequestMatchers(Path.root(), Configuration.empty(), Function.identity());
}

private static class JsonRequestMatcher extends AbstractSpringMatcher implements RequestMatcher {
private JsonRequestMatcher(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull BiConsumer<Object, InternalMatcher> matcher) {
super(path, configuration, matcher);
@NotNull Consumer<InternalMatcher> matcher,
@NotNull Function<Object, Object> jsonTransformer) {
super(path, configuration, matcher, jsonTransformer);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import net.javacrumbs.jsonunit.core.Configuration;
import net.javacrumbs.jsonunit.core.internal.Path;
import net.javacrumbs.jsonunit.core.internal.matchers.InternalMatcher;
Expand All @@ -36,35 +37,39 @@
* </code>
*/
public class JsonUnitResultMatchers extends AbstractSpringMatchers<JsonUnitResultMatchers, ResultMatcher> {
private JsonUnitResultMatchers(Path path, Configuration configuration) {
super(path, configuration);
private JsonUnitResultMatchers(Path path, Configuration configuration, Function<Object, Object> jsonTransformer) {
super(path, configuration, jsonTransformer);
}

/**
* Creates JsonUnitResultMatchers to be used for JSON assertions.
*/
public static JsonUnitResultMatchers json() {
return new JsonUnitResultMatchers(Path.root(), Configuration.empty());
return new JsonUnitResultMatchers(Path.root(), Configuration.empty(), Function.identity());
}

@Override
@NotNull
ResultMatcher matcher(@NotNull BiConsumer<Object, InternalMatcher> matcher) {
return new JsonResultMatcher(path, configuration, matcher);
ResultMatcher matcher(@NotNull Consumer<InternalMatcher> matcher) {
return new JsonResultMatcher(path, configuration, matcher, jsonTransformer);
}

@Override
@NotNull
JsonUnitResultMatchers matchers(@NotNull Path path, @NotNull Configuration configuration) {
return new JsonUnitResultMatchers(path, configuration);
JsonUnitResultMatchers matchers(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Function<Object, Object> jsonTransformer) {
return new JsonUnitResultMatchers(path, configuration, jsonTransformer);
}

private static class JsonResultMatcher extends AbstractSpringMatcher implements ResultMatcher {
private JsonResultMatcher(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull BiConsumer<Object, InternalMatcher> matcher) {
super(path, configuration, matcher);
@NotNull Consumer<InternalMatcher> matcher,
@NotNull Function<Object, Object> jsonTransformer) {
super(path, configuration, matcher, jsonTransformer);
}

@Override
Expand Down
Loading

0 comments on commit 2645ca7

Please sign in to comment.