Browse Source
Added a Degraph based tests to identify package cycles and violations in layering. Moved Collation to the core.query package, fixing dependency cycles. Moved IndexOperations and IndexOperationsProvider to the core.index package. fixing dependency cycles. Moved GeoJsonConfiguration to config package. Replaced the original version of these interfaces/classes with a deprecated version extending the new one, in order to not break the existing API. Removed all references to Part.Type, except for those to maintain the existing API. API using Part.Type is marked as deprecated. It violates the layering, because nothing but "config" should access "repository". Tests added to MongoRegexCreator in order to facilitate the removal of Part.Type dependencies. Using the moved/new ExampleMatcherAccessor. Related Tickets: DATACMNS-1097. Original pull request: #470.pull/483/merge
49 changed files with 501 additions and 123 deletions
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
/* |
||||
* Copyright 2015-2017 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.data.mongodb.config; |
||||
|
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.data.mongodb.core.geo.GeoJsonModule; |
||||
import org.springframework.data.web.config.SpringDataJacksonModules; |
||||
|
||||
/** |
||||
* Configuration class to expose {@link GeoJsonModule} as a Spring bean. |
||||
* |
||||
* @author Oliver Gierke |
||||
* @author Jens Schauder |
||||
*/ |
||||
public class GeoJsonConfiguration implements SpringDataJacksonModules { |
||||
|
||||
@Bean |
||||
public GeoJsonModule geoJsonModule() { |
||||
return new GeoJsonModule(); |
||||
} |
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
/* |
||||
* Copyright 2011-2017 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.data.mongodb.core.index; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* Index operations on a collection. |
||||
* |
||||
* @author Mark Pollack |
||||
* @author Oliver Gierke |
||||
* @author Christoph Strobl |
||||
* @author Jens Schauder |
||||
*/ |
||||
public interface IndexOperations { |
||||
|
||||
/** |
||||
* Ensure that an index for the provided {@link IndexDefinition} exists for the collection indicated by the entity |
||||
* class. If not it will be created. |
||||
* |
||||
* @param indexDefinition must not be {@literal null}. |
||||
*/ |
||||
String ensureIndex(IndexDefinition indexDefinition); |
||||
|
||||
/** |
||||
* Drops an index from this collection. |
||||
* |
||||
* @param name name of index to drop |
||||
*/ |
||||
void dropIndex(String name); |
||||
|
||||
/** |
||||
* Drops all indices from this collection. |
||||
*/ |
||||
void dropAllIndexes(); |
||||
|
||||
/** |
||||
* Returns the index information on the collection. |
||||
* |
||||
* @return index information on the collection |
||||
*/ |
||||
List<IndexInfo> getIndexInfo(); |
||||
} |
||||
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
/* |
||||
* Copyright 2016-2017 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.data.mongodb.core.index; |
||||
|
||||
/** |
||||
* TODO: Revisit for a better pattern. |
||||
* |
||||
* @author Mark Paluch |
||||
* @author Jens Schauder |
||||
* @since 2.0 |
||||
*/ |
||||
public interface IndexOperationsProvider { |
||||
|
||||
/** |
||||
* Returns the operations that can be performed on indexes |
||||
* |
||||
* @return index operations on the named collection |
||||
*/ |
||||
IndexOperations indexOps(String collectionName); |
||||
} |
||||
@ -1,2 +1,2 @@
@@ -1,2 +1,2 @@
|
||||
org.springframework.data.web.config.SpringDataJacksonModules=org.springframework.data.mongodb.core.GeoJsonConfiguration |
||||
org.springframework.data.web.config.SpringDataJacksonModules=org.springframework.data.mongodb.config.GeoJsonConfiguration |
||||
org.springframework.data.repository.core.support.RepositoryFactorySupport=org.springframework.data.mongodb.repository.support.MongoRepositoryFactory |
||||
|
||||
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
/* |
||||
* Copyright 2017 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.data.mongodb; |
||||
|
||||
import static de.schauderhaft.degraph.check.JCheck.*; |
||||
import static org.junit.Assert.*; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.data.mongodb.core.GeoJsonConfiguration; |
||||
import org.springframework.data.mongodb.core.query.MongoRegexCreator; |
||||
|
||||
import de.schauderhaft.degraph.configuration.NamedPattern; |
||||
|
||||
/** |
||||
* Tests package dependency constraints. |
||||
* |
||||
* @author Jens Schauder |
||||
*/ |
||||
public class DependencyTests { |
||||
|
||||
@Test |
||||
public void noInternalPackageCycles() { |
||||
|
||||
assertThat( |
||||
classpath() //
|
||||
.noJars() //
|
||||
.including("org.springframework.data.mongodb.**") //
|
||||
// ignoring deprecated class that will be removed soon
|
||||
.excluding(org.springframework.data.mongodb.core.IndexOperations.class.getCanonicalName()) |
||||
.excluding(org.springframework.data.mongodb.core.IndexOperationsProvider.class.getCanonicalName()) |
||||
.excluding(GeoJsonConfiguration.class.getCanonicalName()) |
||||
.filterClasspath("*target/classes") //
|
||||
.printOnFailure("degraph.graphml"), //
|
||||
violationFree() //
|
||||
); |
||||
} |
||||
|
||||
@Test |
||||
public void onlyConfigMayUseRepository() { |
||||
|
||||
assertThat( |
||||
classpath() //
|
||||
.including("org.springframework.data.**") //
|
||||
// ignoring the MongoRegexCreator for now, since it still
|
||||
// needs the reference to Part.Type to maintain the old API
|
||||
.excluding(MongoRegexCreator.class.getCanonicalName() + "*") |
||||
// ignoring deprecated class that will be removed soon
|
||||
.excluding(org.springframework.data.mongodb.core.IndexOperations.class.getCanonicalName()) |
||||
.excluding(org.springframework.data.mongodb.core.IndexOperationsProvider.class.getCanonicalName()) |
||||
.excluding(GeoJsonConfiguration.class.getCanonicalName()) |
||||
.filterClasspath("*target/classes") //
|
||||
.printOnFailure("onlyConfigMayUseRepository.graphml") //
|
||||
.withSlicing("slices", //
|
||||
"**.(config).**", //
|
||||
new NamedPattern("**.cdi.**", "config"), //
|
||||
"**.(repository).**", //
|
||||
new NamedPattern("**", "other")) |
||||
.allow("config", "repository", "other"), //
|
||||
violationFree() //
|
||||
); |
||||
} |
||||
|
||||
@Test |
||||
public void commonsInternaly() { |
||||
|
||||
assertThat( |
||||
classpath() //
|
||||
.noJars() //
|
||||
.including("org.springframework.data.**") //
|
||||
.excluding("org.springframework.data.mongodb.**") //
|
||||
.filterClasspath("*target/classes") //
|
||||
.printTo("commons.graphml"), //
|
||||
violationFree() //
|
||||
); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,116 @@
@@ -0,0 +1,116 @@
|
||||
package org.springframework.data.mongodb.core.query; |
||||
|
||||
import static java.util.Arrays.*; |
||||
import static org.springframework.data.mongodb.core.query.MongoRegexCreatorUnitTests.TestParameter.*; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.assertj.core.api.SoftAssertions; |
||||
import org.assertj.core.api.StringAssert; |
||||
import org.junit.Test; |
||||
import org.springframework.data.repository.query.parser.Part.Type; |
||||
|
||||
/** |
||||
* Tests the creation of Regex's in {@link MongoRegexCreator} |
||||
* |
||||
* @author Jens Schauder |
||||
*/ |
||||
public class MongoRegexCreatorUnitTests { |
||||
|
||||
List<TestParameter> testParameters = asList(TestParameter.test("anystring", null, "anystring", "type=null -> input"), |
||||
test(null, Type.AFTER, null, "source=null -> null"), //
|
||||
test("anystring", Type.REGEX, "anystring", "REGEX -> input"), //
|
||||
test("one.two?three", Type.AFTER, "\\Qone.two?three\\E", |
||||
"not(REGEX, LIKE, NOT_LIKE, PunctuationPattern -> quoted punctuation"), //
|
||||
test("*", Type.LIKE, ".*", "LIKE * -> .*"), test("*", Type.NOT_LIKE, ".*", "LIKE * -> .*"), //
|
||||
test("*.*", Type.LIKE, ".*\\Q.\\E.*", "Wildcards & Punctuation"), //
|
||||
test("*.", Type.LIKE, ".*\\Q.\\E", "Leading Wildcard & Punctuation"), //
|
||||
test(".*", Type.LIKE, "\\Q.\\E.*", "Trailing Wildcard & Punctuation"), //
|
||||
test("other", Type.LIKE, "other", "No Wildcard & Other"), //
|
||||
test("other*", Type.LIKE, "other.*", "Trailing Wildcard & Other"), //
|
||||
test("*other", Type.LIKE, ".*other", "Leading Wildcard & Other"), //
|
||||
test("o*t.*h.er", Type.LIKE, "\\Qo*t.*h.er\\E", "Dots & Stars"), //
|
||||
test("other", Type.STARTING_WITH, "^other", "Dots & Stars"), //
|
||||
test("other", Type.ENDING_WITH, "other$", "Dots & Stars"), //
|
||||
test("other", Type.CONTAINING, ".*other.*", "Dots & Stars"), //
|
||||
test("other", Type.NOT_CONTAINING, ".*other.*", "Dots & Stars"), //
|
||||
test("other", Type.SIMPLE_PROPERTY, "^other$", "Dots & Stars"), //
|
||||
test("other", Type.NEGATING_SIMPLE_PROPERTY, "^other$", "Dots & Stars")); |
||||
|
||||
Map<Type, String> expectedResultsForAllTypes = new HashMap<>(); |
||||
{ |
||||
expectedResultsForAllTypes.put(Type.BETWEEN, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.IS_NOT_NULL, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.IS_NULL, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.LESS_THAN, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.LESS_THAN_EQUAL, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.GREATER_THAN, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.GREATER_THAN_EQUAL, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.BEFORE, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.AFTER, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.NOT_LIKE, "\\Qo*t.*h.er\\E.*"); |
||||
expectedResultsForAllTypes.put(Type.LIKE, "\\Qo*t.*h.er\\E.*"); |
||||
expectedResultsForAllTypes.put(Type.STARTING_WITH, "^\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.ENDING_WITH, "\\Qo*t.*h.er*\\E$"); |
||||
expectedResultsForAllTypes.put(Type.IS_NOT_EMPTY, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.IS_EMPTY, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.NOT_CONTAINING, ".*\\Qo*t.*h.er*\\E.*"); |
||||
expectedResultsForAllTypes.put(Type.CONTAINING, ".*\\Qo*t.*h.er*\\E.*"); |
||||
expectedResultsForAllTypes.put(Type.NOT_IN, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.IN, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.NEAR, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.WITHIN, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.REGEX, "o*t.*h.er*"); |
||||
expectedResultsForAllTypes.put(Type.EXISTS, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.TRUE, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.FALSE, "\\Qo*t.*h.er*\\E"); |
||||
expectedResultsForAllTypes.put(Type.NEGATING_SIMPLE_PROPERTY, "^\\Qo*t.*h.er*\\E$"); |
||||
expectedResultsForAllTypes.put(Type.SIMPLE_PROPERTY, "^\\Qo*t.*h.er*\\E$"); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testSpecialCases() { |
||||
SoftAssertions.assertSoftly(sa -> testParameters.forEach(tp -> tp.check(sa))); |
||||
} |
||||
|
||||
@Test |
||||
public void testAllTypes() { |
||||
SoftAssertions.assertSoftly( |
||||
sa -> Arrays.stream(Type.values()).forEach(t -> //
|
||||
test("o*t.*h.er*", t, expectedResultsForAllTypes.getOrDefault(t,"missed one"), t.toString())//
|
||||
.check(sa))); |
||||
} |
||||
|
||||
static class TestParameter { |
||||
|
||||
TestParameter(String source, Type type, String expectedResult, String comment) { |
||||
this.source = source; |
||||
this.type = type; |
||||
this.expectedResult = expectedResult; |
||||
this.comment = comment; |
||||
} |
||||
|
||||
static TestParameter test(String source, Type type, String expectedResult, String comment) { |
||||
return new TestParameter(source, type, expectedResult, comment); |
||||
} |
||||
|
||||
private final String source; |
||||
private final Type type; |
||||
private final String expectedResult; |
||||
private final String comment; |
||||
|
||||
private StringAssert check(SoftAssertions sa) { |
||||
|
||||
return sa |
||||
.assertThat( //
|
||||
MongoRegexCreator.INSTANCE.toRegularExpression(source, type)) //
|
||||
.describedAs(comment) //
|
||||
.isEqualTo(expectedResult); |
||||
} |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue