Compare commits

..

10 Commits

Author SHA1 Message Date
Jens Schauder
171f6641c7 archunit-dependency-tests - Prepare branch 2023-03-03 13:02:05 +01:00
Jens Schauder
4f8c29f48a Migrates DependencyTests to ArchUnit.
The tests are currently failing due to various undesired dependencies.

The tests start with something like:

		JavaClasses importedClasses = new ClassFileImporter()
		        ...
				.that(onlySpringData())

By adding

				.that(ignorePackage(org.springframework.data.aot.hint))

or

				.that(ignore(SomeClass.class));

the given classes or packages can be ignored for the analysis.
Of course the goal should be to fix the cycles.
2023-03-03 13:01:24 +01:00
Christoph Strobl
e3ef84a56c Fix regression in findAndReplace when using native MongoDB types as domain value.
This commit fixes a regression that prevented native org.bson.Document to serve as source for a findAndReplaceOperation.

Closes: #4300
Original Pull Request: #4310
2023-03-02 09:55:42 +01:00
Mark Paluch
3ab78fc1ed Upgrade to Maven Wrapper 3.9.0.
See #4297
2023-02-20 11:58:01 +01:00
Christoph Strobl
fa0f026410 After release cleanups.
See #4294
2023-02-17 14:25:48 +01:00
Christoph Strobl
9c96a2b2c3 Prepare next development iteration.
See #4294
2023-02-17 14:25:46 +01:00
Christoph Strobl
0986210221 Release version 4.1 M2 (2023.0.0).
See #4294
2023-02-17 14:22:30 +01:00
Christoph Strobl
7d5372f049 Prepare 4.1 M2 (2023.0.0).
See #4294
2023-02-17 14:22:15 +01:00
Christoph Strobl
a5022e9bc4 After release cleanups.
See #4235
2023-02-17 13:31:54 +01:00
Christoph Strobl
aff8fbd62a Prepare next development iteration.
See #4235
2023-02-17 13:31:52 +01:00
11 changed files with 207 additions and 51 deletions

View File

@@ -1,2 +1,2 @@
#Mon Jan 30 10:48:12 CET 2023
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
#Mon Feb 20 11:58:01 CET 2023
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-bin.zip

10
pom.xml
View File

@@ -5,7 +5,7 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-M1</version>
<version>4.1.0-archunit-dependency-tests-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Spring Data MongoDB</name>
@@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>3.1.0-M1</version>
<version>3.1.0-SNAPSHOT</version>
</parent>
<modules>
@@ -26,7 +26,7 @@
<properties>
<project.type>multi</project.type>
<dist.id>spring-data-mongodb</dist.id>
<springdata.commons>3.1.0-M1</springdata.commons>
<springdata.commons>3.1.0-SNAPSHOT</springdata.commons>
<mongo>4.9.0</mongo>
<mongo.reactivestreams>${mongo}</mongo.reactivestreams>
<jmh.version>1.19</jmh.version>
@@ -145,8 +145,8 @@
<repositories>
<repository>
<id>spring-libs-milestone</id>
<url>https://repo.spring.io/libs-milestone</url>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-M1</version>
<version>4.1.0-archunit-dependency-tests-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-M1</version>
<version>4.1.0-archunit-dependency-tests-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-M1</version>
<version>4.1.0-archunit-dependency-tests-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -23,6 +23,7 @@
<java-module-name>spring.data.mongodb</java-module-name>
<project.root>${basedir}/..</project.root>
<multithreadedtc>1.01</multithreadedtc>
<archunit.version>1.0.1</archunit.version>
</properties>
<dependencies>
@@ -250,9 +251,9 @@
</dependency>
<dependency>
<groupId>de.schauderhaft.degraph</groupId>
<artifactId>degraph-check</artifactId>
<version>0.1.4</version>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit</artifactId>
<version>${archunit.version}</version>
<scope>test</scope>
</dependency>

View File

@@ -283,6 +283,10 @@ class EntityOperations {
* @see EntityProjectionIntrospector#introspect(Class, Class)
*/
public <M, D> EntityProjection<M, D> introspectProjection(Class<M> resultType, Class<D> entityType) {
if (!queryMapper.getMappingContext().hasPersistentEntityFor(entityType)) {
return (EntityProjection) EntityProjection.nonProjecting(resultType);
}
return introspector.introspect(resultType, entityType);
}

View File

@@ -15,12 +15,16 @@
*/
package org.springframework.data.mongodb;
import static de.schauderhaft.degraph.check.JCheck.*;
import static org.hamcrest.MatcherAssert.*;
import de.schauderhaft.degraph.configuration.NamedPattern;
import org.junit.jupiter.api.Disabled;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.library.dependencies.SliceAssignment;
import com.tngtech.archunit.library.dependencies.SliceIdentifier;
import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Test;
/**
@@ -29,49 +33,138 @@ import org.junit.jupiter.api.Test;
* @author Jens Schauder
* @author Oliver Gierke
*/
@Disabled("Needs to be tansitioned to ArchUnit")
class DependencyTests {
@Test
void noInternalPackageCycles() {
void cycleFree() {
assertThat(classpath() //
.noJars() //
.including("org.springframework.data.mongodb.**") //
.filterClasspath("*target/classes") //
.printOnFailure("degraph.graphml"), //
violationFree() //
);
JavaClasses importedClasses = new ClassFileImporter() //
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) //
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS) // we just analyze the code of this module.
.importPackages("org.springframework.data.mongodb").that( //
onlySpringData() //
);
ArchRule rule = SlicesRuleDefinition.slices() //
.matching("org.springframework.data.mongodb.(**)") //
.should() //
.beFreeOfCycles();
rule.check(importedClasses);
}
@Test
void onlyConfigMayUseRepository() {
void acrossModules() {
assertThat(classpath() //
.including("org.springframework.data.**") //
.filterClasspath("*target/classes") //
.printOnFailure("onlyConfigMayUseRepository.graphml") //
.withSlicing("slices", //
"**.(config).**", //
new NamedPattern("**.cdi.**", "config"), //
"**.(repository).**", //
new NamedPattern("**", "other"))
.allow("config", "repository", "other"), //
violationFree() //
);
JavaClasses importedClasses = new ClassFileImporter().withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages( //
"org.springframework.data.mongodb", // Spring Data Relational
"org.springframework.data" // Spring Data Commons
).that(onlySpringData());
ArchRule rule = SlicesRuleDefinition.slices() //
.assignedFrom(subModuleSlicing()) //
.should().beFreeOfCycles();
rule.check(importedClasses);
}
@Test
void commonsInternaly() {
// GH-1058
void testGetFirstPackagePart() {
assertThat(classpath() //
.noJars() //
.including("org.springframework.data.**") //
.excluding("org.springframework.data.mongodb.**") //
.filterClasspath("*target/classes") //
.printTo("commons.graphml"), //
violationFree() //
);
SoftAssertions.assertSoftly(softly -> {
softly.assertThat(getFirstPackagePart("a.b.c")).isEqualTo("a");
softly.assertThat(getFirstPackagePart("a")).isEqualTo("a");
});
}
@Test
// GH-1058
void testSubModule() {
SoftAssertions.assertSoftly(softly -> {
softly.assertThat(subModule("a.b", "a.b.c.d")).isEqualTo("c");
softly.assertThat(subModule("a.b", "a.b.c")).isEqualTo("c");
softly.assertThat(subModule("a.b", "a.b")).isEqualTo("");
});
}
private DescribedPredicate<JavaClass> onlySpringData() {
return new DescribedPredicate<>("Spring Data Classes") {
@Override
public boolean test(JavaClass input) {
return input.getPackageName().startsWith("org.springframework.data");
}
};
}
private DescribedPredicate<JavaClass> ignore(Class<?> type) {
return new DescribedPredicate<>("ignored class " + type.getName()) {
@Override
public boolean test(JavaClass input) {
return !input.getFullName().startsWith(type.getName());
}
};
}
private DescribedPredicate<JavaClass> ignorePackage(String type) {
return new DescribedPredicate<>("ignored class " + type) {
@Override
public boolean test(JavaClass input) {
return !input.getPackageName().equals(type);
}
};
}
private String getFirstPackagePart(String subpackage) {
int index = subpackage.indexOf(".");
if (index < 0) {
return subpackage;
}
return subpackage.substring(0, index);
}
private String subModule(String basePackage, String packageName) {
if (packageName.startsWith(basePackage) && packageName.length() > basePackage.length()) {
final int index = basePackage.length() + 1;
String subpackage = packageName.substring(index);
return getFirstPackagePart(subpackage);
}
return "";
}
private SliceAssignment subModuleSlicing() {
return new SliceAssignment() {
@Override
public SliceIdentifier getIdentifierOf(JavaClass javaClass) {
String packageName = javaClass.getPackageName();
String subModule = subModule("org.springframework.data.mongodb", packageName);
if (!subModule.isEmpty()) {
return SliceIdentifier.of(subModule);
}
subModule = subModule("org.springframework.data", packageName);
if (!subModule.isEmpty()) {
return SliceIdentifier.of(subModule);
}
return SliceIdentifier.ignore();
}
@Override
public String getDescription() {
return "Submodule";
}
};
}
}

View File

@@ -2526,6 +2526,26 @@ public class MongoTemplateTests {
assertThat(projection.getName()).isEqualTo("Walter");
}
@Test // GH-4300
public void findAndReplaceShouldAllowNativeDomainTypesAndReturnAProjection() {
MyPerson person = new MyPerson("Walter");
person.address = new Address("TX", "Austin");
template.save(person);
MyPerson previous = template.findAndReplace(query(where("name").is("Walter")),
new org.bson.Document("name", "Heisenberg"), FindAndReplaceOptions.options(), org.bson.Document.class,
"myPerson", MyPerson.class);
assertThat(previous).isNotNull();
assertThat(previous.getAddress()).isEqualTo(person.address);
org.bson.Document loaded = template.execute(MyPerson.class, collection -> {
return collection.find(new org.bson.Document("name", "Heisenberg")).first();
});
assertThat(loaded.get("_id")).isEqualTo(new ObjectId(person.id));
}
@Test // DATAMONGO-407
public void updatesShouldRetainTypeInformationEvenForCollections() {

View File

@@ -2392,6 +2392,17 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
.isEqualTo(new com.mongodb.client.model.TimeSeriesOptions("time_stamp").toString());
}
@Test // GH-4300
void findAndReplaceAllowsDocumentSourceType() {
template.findAndReplace(new Query(), new Document("spring", "data"), FindAndReplaceOptions.options().upsert(),
Document.class, "coll-1", Person.class);
verify(db).getCollection(eq("coll-1"), eq(Document.class));
verify(collection).findOneAndReplace((Bson) any(Bson.class), eq(new Document("spring", "data")),
any(FindOneAndReplaceOptions.class));
}
class AutogenerateableId {
@Id BigInteger id;

View File

@@ -729,6 +729,32 @@ public class ReactiveMongoTemplateTests {
}).verifyComplete();
}
@Test // GH-4300
public void findAndReplaceShouldAllowNativeDomainTypesAndReturnAProjection() {
MongoTemplateTests.MyPerson person = new MongoTemplateTests.MyPerson("Walter");
person.address = new Address("TX", "Austin");
template.save(person) //
.as(StepVerifier::create) //
.expectNextCount(1) //
.verifyComplete();
template
.findAndReplace(query(where("name").is("Walter")), new org.bson.Document("name", "Heisenberg"),
FindAndReplaceOptions.options(), org.bson.Document.class, "myPerson", MongoTemplateTests.MyPerson.class)
.as(StepVerifier::create) //
.consumeNextWith(actual -> {
assertThat(actual.getAddress()).isEqualTo(person.address);
}).verifyComplete();
template.execute(MongoTemplateTests.MyPerson.class, collection -> {
return collection.find(new org.bson.Document("name", "Heisenberg")).first();
}).as(StepVerifier::create) //
.consumeNextWith(loaded -> {
assertThat(loaded.get("_id")).isEqualTo(new ObjectId(person.id));
}).verifyComplete();
}
@Test // DATAMONGO-1827
void findAndReplaceShouldReplaceObjectReturingNew() {

View File

@@ -1,4 +1,4 @@
Spring Data MongoDB 4.1 M1 (2023.0.0)
Spring Data MongoDB 4.1 M2 (2023.0.0)
Copyright (c) [2010-2019] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -41,5 +41,6 @@ conditions of the subcomponent's license, as noted in the LICENSE file.