Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#859 Support for JsonPath in Spring #860

Merged
merged 1 commit into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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