diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy index 3e91271b64..e80b01e4be 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy @@ -122,7 +122,8 @@ class JsonToJsonPathsConverter { String pathWithoutAnyArray = matcher.path().substring(0, matcher.path().lastIndexOf(ANY_ARRAY_NOTATION_IN_JSONPATH)) def object = context.read(pathWithoutAnyArray) if (object instanceof Iterable && containsOnlyEmptyElements(object)) { - context.delete(pathWithoutAnyArray) + String pathToDelete = pathToDelete(pathWithoutAnyArray) + context.delete(pathToDelete) } else { String lastParent = matcher.path().substring(0, matcher.path().lastIndexOf(".")) def lastParentObject = context.read(lastParent) @@ -133,6 +134,11 @@ class JsonToJsonPathsConverter { } } + private static String pathToDelete(String pathWithoutAnyArray) { + // we can't remove root + return pathWithoutAnyArray == '$' ? '$[*]' : pathWithoutAnyArray + } + private static boolean containsOnlyEmptyElements(Object object) { return object.every { if (it instanceof Map) { diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy index 04ed2b1282..78abf50bae 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy @@ -1079,4 +1079,55 @@ DocumentContext parsedJson = JsonPath.parse(json); "JaxRsClientJUnitMethodBodyBuilder" | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } } + @Issue("#844") + def "should not leave unnecessary isEmpty when using matchers [#methodBuilderName]"() { + given: + Contract contractDsl = Contract.make { + request { + method 'GET' + url('/test') + headers { + accept(applicationJson()) + header("X-Authorization", "eyJhbGciOiJIUzI1NiJ9.eyJtZW1iZXJObyI6IjEyMzQ1In0.VdYumw6QkfxaBgFUZNyza1VfNKiZ2WW4JaxIKe-G8HA") + } + } + response { + status OK() + body([ + [test: 'testJson'], + [test: 'testJson'] + ]) + headers { + contentType(applicationJson()) + } + bodyMatchers { + jsonPath('$', byType { + minOccurrence(2) + maxOccurrence(2) + }) + jsonPath('$[*].test', byType { + minOccurrence(2) + maxOccurrence(2) + }) + } + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + String test = blockBuilder.toString() + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) + !test.contains('''assertThatJson(parsedJson).array().isEmpty()''') + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + "MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) } + "MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } + "JaxRsClientJUnitMethodBodyBuilder" | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + } + }