diff --git a/accurest-converters/src/test/groovy/io/codearte/accurest/wiremock/DslToWireMockClientConverterSpec.groovy b/accurest-converters/src/test/groovy/io/codearte/accurest/wiremock/DslToWireMockClientConverterSpec.groovy index 79632e7eb1..0d0eee7c03 100755 --- a/accurest-converters/src/test/groovy/io/codearte/accurest/wiremock/DslToWireMockClientConverterSpec.groovy +++ b/accurest-converters/src/test/groovy/io/codearte/accurest/wiremock/DslToWireMockClientConverterSpec.groovy @@ -117,48 +117,40 @@ class DslToWireMockClientConverterSpec extends Specification { { "request" : { "url" : "/api/12", - "method" : "PUT", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == 38.995548)]" - }, { - "matchesJsonPath" : "$[*].place[?(@.country == 'United States')]" - }, { - "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == -77.119759)]" - }, { - "matchesJsonPath" : "$[*].place[?(@.name == 'Washington')]" - }, { - "matchesJsonPath" : "$[*].place.bounding_box[?(@.type == 'Polygon')]" - }, { - "matchesJsonPath" : "$[*][?(@.id_str == '492967299297845248')]" - }, { - "matchesJsonPath" : "$[*].place[?(@.country_code == 'US')]" - }, { - "matchesJsonPath" : "$[*][?(@.id == 492967299297845248)]" - }, { - "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == -76.909393)]" - }, { - "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == 38.791645)]" - }, { - "matchesJsonPath" : "$[*].place[?(@.id == '01fbe706f872cb32')]" - }, { - "matchesJsonPath" : "$[*].place[?(@.url == 'http://api.twitter.com/1/geo/id/01fbe706f872cb32.json')]" - }, { - "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == -77.119759)]" - }, { - "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == -76.909393)]" - }, { - "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == 38.995548)]" - }, { - "matchesJsonPath" : "$[*][?(@.text == 'Gonna see you at Warsaw')]" - }, { - "matchesJsonPath" : "$[*].place[?(@.place_type == 'city')]" - }, { - "matchesJsonPath" : "$[*][?(@.created_at == 'Sat Jul 26 09:38:57 +0000 2014')]" - }, { - "matchesJsonPath" : "$[*].place[?(@.full_name == 'Washington, DC')]" - }, { - "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == 38.791645)]" - } ], + "method" : "PUT", + "bodyPatterns" : [ { + "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == -77.119759)]" + }, { + "matchesJsonPath" : "$[*][?(@.text == 'Gonna see you at Warsaw')]" + }, { + "matchesJsonPath" : "$[*].place[?(@.place_type == 'city')]" + }, { + "matchesJsonPath" : "$[*][?(@.id == 492967299297845248)]" + }, { + "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == 38.791645)]" + }, { + "matchesJsonPath" : "$[*].place[?(@.country == 'United States')]" + }, { + "matchesJsonPath" : "$[*][?(@.id_str == '492967299297845248')]" + }, { + "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == -76.909393)]" + }, { + "matchesJsonPath" : "$[*].place[?(@.name == 'Washington')]" + }, { + "matchesJsonPath" : "$[*].place.bounding_box[?(@.type == 'Polygon')]" + }, { + "matchesJsonPath" : "$[*].place[?(@.url == 'http://api.twitter.com/1/geo/id/01fbe706f872cb32.json')]" + }, { + "matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == 38.995548)]" + }, { + "matchesJsonPath" : "$[*].place[?(@.country_code == 'US')]" + }, { + "matchesJsonPath" : "$[*].place[?(@.full_name == 'Washington, DC')]" + }, { + "matchesJsonPath" : "$[*][?(@.created_at == 'Sat Jul 26 09:38:57 +0000 2014')]" + }, { + "matchesJsonPath" : "$[*].place[?(@.id == '01fbe706f872cb32')]" + } ], "headers" : { "Content-Type" : { "equalTo" : "application/vnd.com.ofg.twitter-places-analyzer.v1+json" @@ -207,7 +199,7 @@ class DslToWireMockClientConverterSpec extends Specification { {"request":{"urlPath":"/foos","method":"GET"},"response":{"body":"[{\\"id\\":\\"123\\"},{\\"id\\":\\"567\\"}]"}} ''', json, false) } - + def 'should convert dsl to wiremock to show it in the docs'() { given: def converter = new DslToWireMockClientConverter() @@ -272,5 +264,5 @@ class DslToWireMockClientConverterSpec extends Specification { // end::wiremock[] , json, false) } - + } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/DelegatingJsonVerifiable.java b/accurest-core/src/main/groovy/io/codearte/accurest/util/DelegatingJsonVerifiable.java index 3067c79049..cf96e2822d 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/util/DelegatingJsonVerifiable.java +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/DelegatingJsonVerifiable.java @@ -2,6 +2,8 @@ package io.codearte.accurest.util; import com.toomuchcoding.jsonassert.JsonVerifiable; +import java.util.LinkedList; + import static org.apache.commons.lang3.StringEscapeUtils.escapeJava; /** @@ -10,17 +12,17 @@ import static org.apache.commons.lang3.StringEscapeUtils.escapeJava; class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { private final JsonVerifiable delegate; - private final StringBuffer methodsBuffer; + private final LinkedList methodsBuffer; DelegatingJsonVerifiable(JsonVerifiable delegate, - StringBuffer methodsBuffer) { + LinkedList methodsBuffer) { this.delegate = delegate; - this.methodsBuffer = new StringBuffer(methodsBuffer.toString()); + this.methodsBuffer = new LinkedList(methodsBuffer); } DelegatingJsonVerifiable(JsonVerifiable delegate) { this.delegate = delegate; - this.methodsBuffer = new StringBuffer(); + this.methodsBuffer = new LinkedList(); } private static String stringWithEscapedQuotes(Object object) { @@ -35,8 +37,7 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { } private void appendMethodWithValue(String methodName, Object value) { - methodsBuffer.append(".").append(methodName).append("(").append(value) - .append(")"); + methodsBuffer.offer("." + methodName + "(" + value + ")"); } private void appendMethodWithQuotedValue(String methodName, Object value) { @@ -48,7 +49,7 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { DelegatingJsonVerifiable verifiable = new FinishedDelegatingJsonVerifiable(delegate.contains(value), methodsBuffer); verifiable.appendMethodWithQuotedValue("contains", value); if (isAssertingAValueInArray()) { - verifiable.methodsBuffer.append(".value()"); + verifiable.methodsBuffer.offer(".value()"); } return verifiable; } @@ -91,14 +92,14 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { @Override public MethodBufferingJsonVerifiable arrayField() { DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(delegate.arrayField(), methodsBuffer); - verifiable.methodsBuffer.append(".arrayField()"); + verifiable.methodsBuffer.offer(".arrayField()"); return verifiable; } @Override public MethodBufferingJsonVerifiable array() { DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(delegate.array(), methodsBuffer); - verifiable.methodsBuffer.append(".array()"); + verifiable.methodsBuffer.offer(".array()"); return verifiable; } @@ -110,8 +111,11 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { @Override public MethodBufferingJsonVerifiable isEqualTo(String value) { DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.isEqualTo(value), methodsBuffer); - if (delegate.isAssertingAValueInArray()) { - readyToCheck.methodsBuffer.append(".value()"); + if (delegate.isAssertingAValueInArray() && readyToCheck.methodsBuffer.peekLast().equals(".arrayField()")) { + readyToCheck.appendMethodWithQuotedValue("isEqualTo", escapeJava(value)); + readyToCheck.methodsBuffer.offer(".value()"); + } else if (delegate.isAssertingAValueInArray() && !readyToCheck.methodsBuffer.peekLast().contains("array")) { + readyToCheck.methodsBuffer.offer(".value()"); } else { readyToCheck.appendMethodWithQuotedValue("isEqualTo", escapeJava(value)); } @@ -129,18 +133,25 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { @Override public MethodBufferingJsonVerifiable isEqualTo(Number value) { DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.isEqualTo(value), methodsBuffer); - if (delegate.isAssertingAValueInArray()) { - readyToCheck.methodsBuffer.append(".value()"); + // related to #271 - the problem is with asserting arrays of maps vs arrays of primitives + String last = readyToCheck.methodsBuffer.peekLast(); + boolean containsAMatcher = containsAnyMatcher(last); + if (delegate.isAssertingAValueInArray() && containsAMatcher) { + readyToCheck.methodsBuffer.offer(".value()"); } else { readyToCheck.appendMethodWithValue("isEqualTo", String.valueOf(value)); } return readyToCheck; } + private boolean containsAnyMatcher(String string) { + return string.contains("isEqualTo") || string.contains("matches") || string.contains("isNull"); + } + @Override public MethodBufferingJsonVerifiable isNull() { DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.isNull(), methodsBuffer); - readyToCheck.methodsBuffer.append(".isNull()"); + readyToCheck.methodsBuffer.offer(".isNull()"); return readyToCheck; } @@ -149,7 +160,7 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.matches(value), methodsBuffer); if (delegate.isAssertingAValueInArray()) { readyToCheck.appendMethodWithQuotedValue("matches", escapeJava(value)); - readyToCheck.methodsBuffer.append(".value()"); + readyToCheck.methodsBuffer.offer(".value()"); } else { readyToCheck.appendMethodWithQuotedValue("matches", escapeJava(value)); } @@ -160,7 +171,7 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { public MethodBufferingJsonVerifiable isEqualTo(Boolean value) { DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.isEqualTo(value), methodsBuffer); if (delegate.isAssertingAValueInArray()) { - readyToCheck.methodsBuffer.append(".value()"); + readyToCheck.methodsBuffer.offer(".value()"); } else { readyToCheck.appendMethodWithValue("isEqualTo", String.valueOf(value)); } @@ -204,7 +215,16 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { @Override public String method() { - return methodsBuffer.toString(); + return createMethodString(); + } + + private String createMethodString() { + LinkedList queue = new LinkedList(methodsBuffer); + StringBuilder stringBuffer = new StringBuilder(); + while (!queue.isEmpty()) { + stringBuffer.append(queue.remove()); + } + return stringBuffer.toString(); } @Override diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/FinishedDelegatingJsonVerifiable.java b/accurest-core/src/main/groovy/io/codearte/accurest/util/FinishedDelegatingJsonVerifiable.java index eb65cd73f4..abf0678d07 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/util/FinishedDelegatingJsonVerifiable.java +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/FinishedDelegatingJsonVerifiable.java @@ -2,18 +2,20 @@ package io.codearte.accurest.util; import com.toomuchcoding.jsonassert.JsonVerifiable; +import java.util.LinkedList; + /** * @author Marcin Grzejszczak */ class FinishedDelegatingJsonVerifiable extends DelegatingJsonVerifiable { FinishedDelegatingJsonVerifiable(JsonVerifiable delegate, - StringBuffer methodsBuffer) { + LinkedList methodsBuffer) { super(delegate, methodsBuffer); } FinishedDelegatingJsonVerifiable(JsonVerifiable delegate) { - super(delegate, new StringBuffer()); + super(delegate, new LinkedList()); } } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonToJsonPathsConverter.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonToJsonPathsConverter.groovy index 21fd6ac1e1..ae7558b952 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonToJsonPathsConverter.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonToJsonPathsConverter.groovy @@ -62,17 +62,25 @@ class JsonToJsonPathsConverter { // JSON with a list of primitives ["a", "b", "c"] in root issue #266 } else if (key.isIteratingOverNamelessArray() && value instanceof List && listContainsOnlyPrimitives(value)) { value.each { - traverseRecursively(Object, key.arrayField().contains(it), it, closure) + traverseRecursively(Object, key.arrayField().contains(ContentUtils.returnParsedObject(it)), + ContentUtils.returnParsedObject(it), closure) + } + // JSON containing list of primitives { "partners":[ { "role":"AGENT", "payment_methods":[ "BANK", "CASH" ] } ] + } else if (value instanceof List && listContainsOnlyPrimitives(value)) { + value.each { + traverseRecursively(Object, valueToAsserter(key.arrayField(), ContentUtils.returnParsedObject(it)), + ContentUtils.returnParsedObject(it), closure) } } else if (value instanceof List) { MethodBufferingJsonVerifiable jsonPathVerifiable = createAsserterFromList(key, value) value.each { def element -> - traverseRecursively(List, createAsserterFromListElement(jsonPathVerifiable, element), - element, closure) + traverseRecursively(List, createAsserterFromListElement(jsonPathVerifiable, ContentUtils.returnParsedObject(element)), + ContentUtils.returnParsedObject(element), closure) } return value } else if (key.isIteratingOverArray()) { - traverseRecursively(Object, key.arrayField().contains(value), value, closure) + traverseRecursively(Object, key.arrayField().contains(ContentUtils.returnParsedObject(value)), + ContentUtils.returnParsedObject(value), closure) } try { return runClosure(closure, key, value) @@ -108,7 +116,7 @@ class JsonToJsonPathsConverter { } private static def runClosure(Closure closure, MethodBufferingJsonVerifiable key, def value) { - if (key.isAssertingAValueInArray()) { + if (key.isAssertingAValueInArray() && !(value instanceof List || value instanceof Map)) { return closure(valueToAsserter(key, value), value) } return closure(key, value) @@ -172,19 +180,20 @@ class JsonToJsonPathsConverter { } protected static MethodBufferingJsonVerifiable valueToAsserter(MethodBufferingJsonVerifiable key, Object value) { + def convertedValue = ContentUtils.returnParsedObject(value) if (key instanceof FinishedDelegatingJsonVerifiable) { return key } - if (value instanceof Pattern) { - return key.matches((value as Pattern).pattern()) - } else if (value instanceof OptionalProperty) { - return key.matches((value as OptionalProperty).optionalPattern()) - } else if (value instanceof GString) { - return key.matches(RegexpBuilders.buildGStringRegexpForTestSide(value)) - } else if (ContentUtils.returnParsedObject(value) instanceof ExecutionProperty) { + if (convertedValue instanceof Pattern) { + return key.matches((convertedValue as Pattern).pattern()) + } else if (convertedValue instanceof OptionalProperty) { + return key.matches((convertedValue as OptionalProperty).optionalPattern()) + } else if (convertedValue instanceof GString) { + return key.matches(RegexpBuilders.buildGStringRegexpForTestSide(convertedValue)) + } else if (convertedValue instanceof ExecutionProperty) { return key } - return key.isEqualTo(value) + return key.isEqualTo(convertedValue) } } diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcMethodBodyBuilderSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcMethodBodyBuilderSpec.groovy index 9193e11a55..5c54cae143 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcMethodBodyBuilderSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcMethodBodyBuilderSpec.groovy @@ -1131,7 +1131,7 @@ World.'''""" builder.appendTo(blockBuilder) def test = blockBuilder.toString() then: - test.contains('''assertThatJson(parsedJson).array("authorities").matches("^[a-zA-Z0-9_\\\\- ]+\\$").value()''') + test.contains('''assertThatJson(parsedJson).array("authorities").arrayField().matches("^[a-zA-Z0-9_\\\\- ]+\\$").value()''') where: methodBuilderName | methodBuilder "MockMvcSpockMethodBuilder" | { GroovyDsl dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl) } @@ -1232,6 +1232,39 @@ World.'''""" "MockMvcJUnitMethodBuilder" | { GroovyDsl dsl -> new MockMvcJUnitMethodBodyBuilder(dsl) } } + def "should generate proper test code with array of primitives using #methodBuilderName"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method 'GET' + urlPath '/api/tags' + } + response { + status 200 + body('''{ + "partners":[ + { + "payment_methods":[ "BANK", "CASH" ] + } + ] + } + ''') + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.then(blockBuilder) + def test = blockBuilder.toString() + then: + test.contains('assertThatJson(parsedJson).array("partners").array("payment_methods").arrayField().isEqualTo("BANK").value()') + test.contains('assertThatJson(parsedJson).array("partners").array("payment_methods").arrayField().isEqualTo("CASH").value()') + where: + methodBuilderName | methodBuilder + "MockMvcSpockMethodBuilder" | { GroovyDsl dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl) } + "MockMvcJUnitMethodBuilder" | { GroovyDsl dsl -> new MockMvcJUnitMethodBodyBuilder(dsl) } + } + GroovyDsl dslForDocs = // tag::dsl_example[] @@ -1278,4 +1311,4 @@ World.'''""" } } // end::dsl_example[] - } \ No newline at end of file +} \ No newline at end of file diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WireMockGroovyDslSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WireMockGroovyDslSpec.groovy index 269d1c3b6f..2b5157a3f7 100755 --- a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WireMockGroovyDslSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WireMockGroovyDslSpec.groovy @@ -1015,19 +1015,15 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie "matchesJsonPath" : "$.errors[*][?(@.propertyName =~ /[0-9]{2}/)]" }, { "matchesJsonPath" : "$.errors[*][?(@.providerValue == 'Test')]" - }, { - "matchesJsonPath" : "$.errors[*][?(@.providerValue == 'Test')]" }, { "matchesJsonPath" : "$[?(@.lastName =~ /.*/)]" }, { - "matchesJsonPath" : "$.errors[*][?(@.propertyName =~ /[0-9]{2}/)]" + "matchesJsonPath" : "$[?(@.firstName =~ /.*/)]" }, { "matchesJsonPath" : "$[?(@.birthDate =~ /[0-9]{4}-[0-9]{2}-[0-9]{2}/)]" }, { "matchesJsonPath" : "$[?(@.personalId =~ /[0-9]{11}/)]" - }, { - "matchesJsonPath" : "$[?(@.firstName =~ /.*/)]" - } ] + }] }, "response" : { "status" : 200, diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/util/JsonToJsonPathsConverterSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/util/JsonToJsonPathsConverterSpec.groovy index a4d8a06a5c..1645aa7475 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/util/JsonToJsonPathsConverterSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/util/JsonToJsonPathsConverterSpec.groovy @@ -142,7 +142,7 @@ class JsonToJsonPathsConverterSpec extends Specification { JsonPaths pathAndValues = JsonToJsonPathsConverter.transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) then: pathAndValues.find { - it.method() == """.array("items").contains("HOP").value()""" && + it.method() == """.array("items").arrayField().isEqualTo("HOP").value()""" && it.jsonPath() == '''$.items[?(@ == 'HOP')]''' } and: @@ -534,19 +534,19 @@ class JsonToJsonPathsConverterSpec extends Specification { JsonPaths pathAndValues = JsonToJsonPathsConverter.transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) then: pathAndValues.find { - it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().contains(38.995548).value()""" && + it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().isEqualTo(38.995548)""" && it.jsonPath() == """\$[*].place.bounding_box.coordinates[*][*][?(@ == 38.995548)]""" } pathAndValues.find { - it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().contains(-77.119759).value()""" && + it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().isEqualTo(-77.119759)""" && it.jsonPath() == """\$[*].place.bounding_box.coordinates[*][*][?(@ == -77.119759)]""" } pathAndValues.find { - it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().contains(-76.909393).value()""" && + it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().isEqualTo(-76.909393)""" && it.jsonPath() == """\$[*].place.bounding_box.coordinates[*][*][?(@ == -76.909393)]""" } pathAndValues.find { - it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().contains(38.791645).value()""" && + it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().isEqualTo(38.791645)""" && it.jsonPath() == """\$[*].place.bounding_box.coordinates[*][*][?(@ == 38.791645)]""" } and: diff --git a/gradle.properties b/gradle.properties index bc634783d3..c186a2a3ed 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ nexusUsername = nexusPassword = wiremockVersion = 2.0.10-beta -jsonassertVersion = 0.4.2 +jsonassertVersion = 0.4.3 BOM_VERSION=Brixton-1.0.0.RC1 springBootVersion=1.3.3.RELEASE