spring-cloud-contract: bodyMatchers - minOccurrences failing with SimpleObjects List.

We are trying to implement contracts for list of objects which contains a list of basic objects (Integer) we just saw that having something like

body([
            [
               listNumbers: [
                   50, 100, 150, 200, 300, 1000
              ],
           ]
       ])
       bodyMatchers {
            jsonPath('$[*].listNumbers[*]', byRegex(positiveInt()))
            jsonPath('$[*].listNumbers', byType {
                minOccurrence(0)
            })
        }

is generating

assertThat((java.lang.Iterable) parsedJson.read("$[*].listNumbers[*]", java.util.Collection.class)).as("$[*].listNumbers[*]").allElementsMatch("([1-9]\\d*)");
assertThat((Object) parsedJson.read("$[*].listNumbers")).isInstanceOf(java.util.List.class);
assertThat((java.lang.Iterable) parsedJson.read("$[*].listNumbers", java.util.Collection.class)).as("$[*].listNumbers").hasFlattenedSizeGreaterThanOrEqualTo(0);

which fail for whatever minOcurrence greater than 0 since counter in the implementation is never update if we have an simple list of objects…

private int flattenedSize(int counter, Object object) {
		if (object instanceof Map) {
			return counter + ((Map) object).size();
		}
		else if (object instanceof Iterator) {
			Iterator iterator = ((Iterator) object);
			while (iterator.hasNext()) {
				Object next = iterator.next();
				counter = flattenedSize(counter, next);
			}
			return counter;
		}
		else if (object instanceof Collection) {
			return flattenedSize(counter, ((Collection) object).iterator());
		}
		return counter;
}

May be I miss a call to the size(Iterable iterable) function.

But if we just have

 body(
         [
              listNumbers: [
                  50, 100, 150, 200, 300, 1000
               ],
                ]
        )
        bodyMatchers {
            jsonPath('$.listNumbers[*]', byRegex(positiveInt()))
            jsonPath('$.listNumbers', byType {
                minOccurrence(0)
            })
        }

we got

assertThat((java.lang.Iterable) parsedJson.read("$.listNumbers[*]", java.util.Collection.class)).as("$.listNumbers[*]").allElementsMatch("([1-9]\\d*)");
assertThat((Object) parsedJson.read("$.listNumbers")).isInstanceOf(java.util.List.class);
assertThat((java.lang.Iterable) parsedJson.read("$.listNumbers", java.util.Collection.class)).as("$.listNumbers").hasSizeGreaterThanOrEqualTo(0);

which works more better with values greater than 1, in fact it works.

So we are a bit lost about if the actual behaviour is the expected one or there is a bug but it’s like a bit frustrating trying to understand why this behaviour.

Nowadays we found this is happening with Spring Cloud Versions 2.0.4.RELEASE and 2.1.1.RELEASE, so looks like is the expected way to be? is this is true, how we can achieve to get a contract as we want, have the same validation expresion for a return object and a list of objects of the same type. Kind Regards.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 28 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Ok I’ll need a sample to replicate this. Could you create a small one please?

Great, that will be extremely helpful, thank you.