diff --git a/pom.xml b/pom.xml index 6c28d06495..3173b1bcbf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 4.4.0-SNAPSHOT + 4.4.0-GH-4818-SNAPSHOT pom Spring Data MongoDB @@ -26,10 +26,10 @@ multi spring-data-mongodb - 3.4.0-SNAPSHOT + 3.4.0-GH-3185-SNAPSHOT 5.2.0 ${mongo} - 1.19 + 1.37 @@ -125,12 +125,13 @@ - benchmarks - - spring-data-mongodb - spring-data-mongodb-distribution - spring-data-mongodb-benchmarks - + jmh + + + jitpack.io + https://jitpack.io + + mongo-4.x diff --git a/spring-data-mongodb-benchmarks/README.md b/spring-data-mongodb-benchmarks/README.md deleted file mode 100644 index ca14cc11a9..0000000000 --- a/spring-data-mongodb-benchmarks/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# Benchmarks - -Benchmarks are based on [JMH](https://openjdk.java.net/projects/code-tools/jmh/). - -# Running Benchmarks - -Running benchmarks is disabled by default and can be activated via the `benchmarks` profile. -To run the benchmarks with default settings use. - -```bash -mvn -P benchmarks clean test -``` - -A basic report will be printed to the CLI. - -```bash -# Run complete. Total time: 00:00:15 - -Benchmark Mode Cnt Score Error Units -MappingMongoConverterBenchmark.readObject thrpt 10 1920157,631 ± 64310,809 ops/s -MappingMongoConverterBenchmark.writeObject thrpt 10 782732,857 ± 53804,130 ops/s -``` - -## Running all Benchmarks of a specific class - -To run all Benchmarks of a specific class, just provide its simple class name via the `benchmark` command line argument. - -```bash -mvn -P benchmarks clean test -D benchmark=MappingMongoConverterBenchmark -``` - -## Running a single Benchmark - -To run a single Benchmark provide its containing class simple name followed by `#` and the method name via the `benchmark` command line argument. - -```bash -mvn -P benchmarks clean test -D benchmark=MappingMongoConverterBenchmark#readObjectWith2Properties -``` - -# Saving Benchmark Results - -A detailed benchmark report is stored in JSON format in the `/target/reports/performance` directory. -To store the report in a different location use the `benchmarkReportDir` command line argument. - -## MongoDB - -Results can be directly piped to MongoDB by providing a valid [Connection String](https://docs.mongodb.com/manual/reference/connection-string/) via the `publishTo` command line argument. - -```bash -mvn -P benchmarks clean test -D publishTo=mongodb://127.0.0.1:27017 -``` - -NOTE: If the uri does not explicitly define a database the default `spring-data-mongodb-benchmarks` is used. - -## HTTP Endpoint - -The benchmark report can also be posted as `application/json` to an HTTP Endpoint by providing a valid URl via the `publishTo` command line argument. - -```bash -mvn -P benchmarks clean test -D publishTo=http://127.0.0.1:8080/capture-benchmarks -``` - -# Customizing Benchmarks - -Following options can be set via command line. - -Option | Default Value ---- | --- -warmupIterations | 10 -warmupTime | 1 (seconds) -measurementIterations | 10 -measurementTime | 1 (seconds) -forks | 1 -benchmarkReportDir | /target/reports/performance (always relative to project root dir) -benchmark | .* (single benchmark via `classname#benchmark`) -publishTo | \[not set\] (mongodb-uri or http-endpoint) \ No newline at end of file diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml deleted file mode 100644 index a3dc49f892..0000000000 --- a/spring-data-mongodb-benchmarks/pom.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - 4.0.0 - - - org.springframework.data - spring-data-mongodb-parent - 4.4.0-SNAPSHOT - ../pom.xml - - - spring-data-mongodb-benchmarks - jar - - Spring Data MongoDB - Microbenchmarks - - - - true - - - - - - ${project.groupId} - spring-data-mongodb - ${project.version} - - - - junit - junit - ${junit} - compile - - - - org.openjdk.jmh - jmh-core - ${jmh.version} - - - - org.openjdk.jmh - jmh-generator-annprocess - ${jmh.version} - provided - - - - - - - - benchmarks - - false - - - - - - - - pl.project13.maven - git-commit-id-plugin - 2.2.2 - - - - revision - - - - - - maven-jar-plugin - - - default-jar - never - - - - - maven-surefire-plugin - - false - ${project.build.sourceDirectory} - ${project.build.outputDirectory} - - **/AbstractMicrobenchmark.java - **/*$*.class - **/generated/*.class - - - **/*Benchmark* - - - ${project.build.directory}/reports/performance - ${project.version} - ${git.dirty} - ${git.commit.id} - ${git.branch} - - - - - - diff --git a/spring-data-mongodb-benchmarks/src/main/resources/logback.xml b/spring-data-mongodb-benchmarks/src/main/resources/logback.xml deleted file mode 100644 index bccb2dc4fa..0000000000 --- a/spring-data-mongodb-benchmarks/src/main/resources/logback.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - %d %5p %40.40c:%4L - %m%n - - - - - - - - \ No newline at end of file diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index acdc13437d..18e81d15f6 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -15,7 +15,7 @@ org.springframework.data spring-data-mongodb-parent - 4.4.0-SNAPSHOT + 4.4.0-GH-4818-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 066f463015..6ed3645da5 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -13,7 +13,7 @@ org.springframework.data spring-data-mongodb-parent - 4.4.0-SNAPSHOT + 4.4.0-GH-4818-SNAPSHOT ../pom.xml @@ -343,6 +343,21 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh} + + + + + + com.mysema.maven apt-maven-plugin diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java similarity index 96% rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java index 0d3039a05c..fb4597977f 100644 --- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java +++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java @@ -19,6 +19,7 @@ import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.TearDown; + import org.springframework.beans.factory.annotation.Value; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithQuery; @@ -27,8 +28,8 @@ import org.springframework.data.mongodb.core.query.BasicQuery; import org.springframework.data.mongodb.microbenchmark.AbstractMicrobenchmark; -import com.mongodb.MongoClient; -import com.mongodb.ServerAddress; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; /** @@ -56,7 +57,7 @@ public class ProjectionsBenchmark extends AbstractMicrobenchmark { @Setup public void setUp() { - client = new MongoClient(new ServerAddress()); + client = MongoClients.create(); template = new MongoTemplate(client, DB_NAME); source = new Person(); @@ -83,7 +84,7 @@ public void setUp() { @TearDown public void tearDown() { - client.dropDatabase(DB_NAME); + client.getDatabase(DB_NAME).drop(); client.close(); } diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java similarity index 79% rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java index 0b14b7a517..ac09ee9146 100644 --- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java +++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java @@ -18,8 +18,6 @@ import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; -import lombok.Data; - import java.util.ArrayList; import java.util.List; @@ -29,14 +27,15 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; + import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.microbenchmark.AbstractMicrobenchmark; -import com.mongodb.MongoClient; -import com.mongodb.ServerAddress; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; /** * @author Christoph Strobl @@ -55,7 +54,7 @@ public class DbRefMappingBenchmark extends AbstractMicrobenchmark { @Setup public void setUp() throws Exception { - client = new MongoClient(new ServerAddress()); + client = MongoClients.create(); template = new MongoTemplate(client, DB_NAME); List refObjects = new ArrayList<>(); @@ -80,7 +79,7 @@ public void setUp() throws Exception { @TearDown public void tearDown() { - client.dropDatabase(DB_NAME); + client.getDatabase(DB_NAME).drop(); client.close(); } @@ -94,18 +93,56 @@ public ObjectWithDBRef readMultipleDbRefs() { return template.findOne(queryObjectWithDBRefList, ObjectWithDBRef.class); } - @Data static class ObjectWithDBRef { private @Id ObjectId id; private @DBRef RefObject ref; private @DBRef List refList; + + public ObjectId getId() { + return id; + } + + public void setId(ObjectId id) { + this.id = id; + } + + public RefObject getRef() { + return ref; + } + + public void setRef(RefObject ref) { + this.ref = ref; + } + + public List getRefList() { + return refList; + } + + public void setRefList(List refList) { + this.refList = refList; + } } - @Data static class RefObject { private @Id String id; private String someValue; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getSomeValue() { + return someValue; + } + + public void setSomeValue(String someValue) { + this.someValue = someValue; + } } } diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java similarity index 75% rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java index e3a0666e5d..e0f739d2a8 100644 --- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java +++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java @@ -15,11 +15,6 @@ */ package org.springframework.data.mongodb.core.convert; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; @@ -29,25 +24,29 @@ import org.bson.Document; import org.bson.types.ObjectId; +import org.junit.platform.commons.annotation.Testable; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; + import org.springframework.data.annotation.Id; import org.springframework.data.geo.Point; -import org.springframework.data.mongodb.core.SimpleMongoDbFactory; +import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory; import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.microbenchmark.AbstractMicrobenchmark; +import org.springframework.util.ObjectUtils; -import com.mongodb.MongoClient; -import com.mongodb.ServerAddress; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; /** * @author Christoph Strobl */ @State(Scope.Benchmark) +@Testable public class MappingMongoConverterBenchmark extends AbstractMicrobenchmark { private static final String DB_NAME = "mapping-mongo-converter-benchmark"; @@ -64,13 +63,13 @@ public class MappingMongoConverterBenchmark extends AbstractMicrobenchmark { @Setup public void setUp() throws Exception { - client = new MongoClient(new ServerAddress()); + client = MongoClients.create(); this.mappingContext = new MongoMappingContext(); this.mappingContext.setInitialEntitySet(Collections.singleton(Customer.class)); this.mappingContext.afterPropertiesSet(); - DbRefResolver dbRefResolver = new DefaultDbRefResolver(new SimpleMongoDbFactory(client, DB_NAME)); + DbRefResolver dbRefResolver = new DefaultDbRefResolver(new SimpleMongoClientDatabaseFactory(client, DB_NAME)); this.converter = new MappingMongoConverter(dbRefResolver, mappingContext); this.converter.setCustomConversions(new MongoCustomConversions(Collections.emptyList())); @@ -116,7 +115,7 @@ public void setUp() throws Exception { @TearDown public void tearDown() { - client.dropDatabase(DB_NAME); + client.getDatabase(DB_NAME).drop(); client.close(); } @@ -151,22 +150,36 @@ public Object writeObjectWithListAndMapsOfComplexType() { return sink; } - @Getter - @RequiredArgsConstructor static class Customer { private @Id ObjectId id; private final String firstname, lastname; private final Address address; + + public Customer(String firstname, String lastname, Address address) { + this.firstname = firstname; + this.lastname = lastname; + this.address = address; + } } - @Getter - @AllArgsConstructor static class Address { private String zipCode, city; + + public Address(String zipCode, String city) { + this.zipCode = zipCode; + this.city = city; + } + + public String getZipCode() { + return zipCode; + } + + public String getCity() { + return city; + } } - @Data static class SlightlyMoreComplexObject { @Id String id; @@ -177,5 +190,59 @@ static class SlightlyMoreComplexObject { Customer customer; List
addressList; Map customerMap; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SlightlyMoreComplexObject)) { + return false; + } + SlightlyMoreComplexObject that = (SlightlyMoreComplexObject) o; + if (intOne != that.intOne) { + return false; + } + if (intTwo != that.intTwo) { + return false; + } + if (!ObjectUtils.nullSafeEquals(id, that.id)) { + return false; + } + if (!ObjectUtils.nullSafeEquals(stringOne, that.stringOne)) { + return false; + } + if (!ObjectUtils.nullSafeEquals(stringTwo, that.stringTwo)) { + return false; + } + if (!ObjectUtils.nullSafeEquals(renamedField, that.renamedField)) { + return false; + } + if (!ObjectUtils.nullSafeEquals(location, that.location)) { + return false; + } + if (!ObjectUtils.nullSafeEquals(customer, that.customer)) { + return false; + } + if (!ObjectUtils.nullSafeEquals(addressList, that.addressList)) { + return false; + } + return ObjectUtils.nullSafeEquals(customerMap, that.customerMap); + } + + @Override + public int hashCode() { + int result = ObjectUtils.nullSafeHashCode(id); + result = 31 * result + intOne; + result = 31 * result + intTwo; + result = 31 * result + ObjectUtils.nullSafeHashCode(stringOne); + result = 31 * result + ObjectUtils.nullSafeHashCode(stringTwo); + result = 31 * result + ObjectUtils.nullSafeHashCode(renamedField); + result = 31 * result + ObjectUtils.nullSafeHashCode(location); + result = 31 * result + ObjectUtils.nullSafeHashCode(customer); + result = 31 * result + ObjectUtils.nullSafeHashCode(addressList); + result = 31 * result + ObjectUtils.nullSafeHashCode(customerMap); + return result; + } } } diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java similarity index 98% rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java index f69feac660..1f912a4e6b 100644 --- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java +++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java @@ -21,7 +21,6 @@ import java.util.Collection; import java.util.Date; -import org.junit.Test; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Scope; @@ -33,6 +32,7 @@ import org.openjdk.jmh.runner.options.ChainedOptionsBuilder; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; + import org.springframework.core.env.StandardEnvironment; import org.springframework.util.CollectionUtils; import org.springframework.util.ResourceUtils; @@ -41,8 +41,8 @@ /** * @author Christoph Strobl */ -@Warmup(iterations = AbstractMicrobenchmark.WARMUP_ITERATIONS) -@Measurement(iterations = AbstractMicrobenchmark.MEASUREMENT_ITERATIONS) +@Warmup(iterations = AbstractMicrobenchmark.WARMUP_ITERATIONS, time = 2) +@Measurement(iterations = AbstractMicrobenchmark.MEASUREMENT_ITERATIONS, time = 2) @Fork(AbstractMicrobenchmark.FORKS) @State(Scope.Thread) public class AbstractMicrobenchmark { @@ -62,7 +62,6 @@ public class AbstractMicrobenchmark { * @throws Exception * @see #options(String) */ - @Test public void run() throws Exception { String includes = includes(); diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java similarity index 93% rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java index 7fb72f6ee6..0e7b611c6e 100644 --- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java +++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java @@ -15,8 +15,8 @@ */ package org.springframework.data.mongodb.microbenchmark; -import lombok.SneakyThrows; +import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; @@ -43,13 +43,20 @@ class HttpResultsWriter implements ResultsWriter { } @Override - @SneakyThrows public void write(Collection results) { if (CollectionUtils.isEmpty(results)) { return; } + try { + doWrite(results); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void doWrite(Collection results) throws IOException { StandardEnvironment env = new StandardEnvironment(); String projectVersion = env.getProperty("project.version", "unknown"); diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java similarity index 80% rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java index 498fb25451..af7d4e5e97 100644 --- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java +++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java @@ -21,15 +21,16 @@ import org.bson.Document; import org.openjdk.jmh.results.RunResult; + import org.springframework.core.env.StandardEnvironment; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import com.mongodb.BasicDBObject; -import com.mongodb.MongoClient; -import com.mongodb.MongoClientURI; +import com.mongodb.ConnectionString; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoDatabase; -import com.mongodb.util.JSON; /** * MongoDB specific {@link ResultsWriter} implementation. @@ -56,13 +57,14 @@ public void write(Collection results) { String gitDirty = env.getProperty("git.dirty", "no"); String gitCommitId = env.getProperty("git.commit.id", "unknown"); - MongoClientURI uri = new MongoClientURI(this.uri); - MongoClient client = new MongoClient(uri); + ConnectionString connectionString = new ConnectionString(this.uri); + MongoClient client = MongoClients.create(this.uri); - String dbName = StringUtils.hasText(uri.getDatabase()) ? uri.getDatabase() : "spring-data-mongodb-benchmarks"; + String dbName = StringUtils.hasText(connectionString.getDatabase()) ? connectionString.getDatabase() + : "spring-data-mongodb-benchmarks"; MongoDatabase db = client.getDatabase(dbName); - for (BasicDBObject dbo : (List) JSON.parse(ResultsWriter.jsonifyResults(results))) { + for (Document dbo : (List) Document.parse(ResultsWriter.jsonifyResults(results))) { String collectionName = extractClass(dbo.get("benchmark").toString()); @@ -96,14 +98,15 @@ private Document fixDocumentKeys(Document doc) { for (Object key : doc.keySet()) { Object value = doc.get(key); - if (value instanceof Document document) { - value = fixDocumentKeys(document); - } else if (value instanceof BasicDBObject basicDBObject) { - value = fixDocumentKeys(new Document(basicDBObject)); + if (value instanceof Document) { + value = fixDocumentKeys((Document) value); + } else if (value instanceof BasicDBObject) { + value = fixDocumentKeys(new Document((BasicDBObject) value)); } - if (key instanceof String newKey) { + if (key instanceof String) { + String newKey = (String) key; if (newKey.contains(".")) { newKey = newKey.replace('.', ','); } diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java similarity index 92% rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java index 3326c3b4bd..c8baf2f396 100644 --- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java +++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java @@ -15,8 +15,6 @@ */ package org.springframework.data.mongodb.microbenchmark; -import lombok.SneakyThrows; - import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.nio.charset.StandardCharsets; @@ -54,13 +52,12 @@ static ResultsWriter forUri(String uri) { * * @param results * @return json string representation of results. - * @see org.openjdk.jmh.results.format.JSONResultFormat */ - @SneakyThrows static String jsonifyResults(Collection results) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ResultFormatFactory.getInstance(ResultFormatType.JSON, new PrintStream(baos, true, "UTF-8")).writeOut(results); + ResultFormatFactory.getInstance(ResultFormatType.JSON, new PrintStream(baos, true, StandardCharsets.UTF_8)) + .writeOut(results); return new String(baos.toByteArray(), StandardCharsets.UTF_8); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java index f0153a1b2c..183c1b9639 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java @@ -171,6 +171,7 @@ public DocumentTypeAliasAccessor(@Nullable String typeKey) { this.typeKey = typeKey; } + @Override public Alias readAliasFrom(Bson source) { if (source instanceof List) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index 0c4d396cd4..2135a76858 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.BiPredicate; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -130,6 +131,23 @@ public class MappingMongoConverter extends AbstractMongoConverter private static final String INCOMPATIBLE_TYPES = "Cannot convert %1$s of type %2$s into an instance of %3$s; Implement a custom Converter<%2$s, %3$s> and register it with the CustomConversions; Parent object was: %4$s"; private static final String INVALID_TYPE_TO_READ = "Expected to read Document %s into type %s but didn't find a PersistentEntity for the latter"; + private static final BiPredicate, MongoPersistentProperty> PROPERTY_FILTER = (e, + property) -> { + + if (property.isIdProperty()) { + return false; + } + + if (e.isCreatorArgument(property)) { + return false; + } + + if (!property.isReadable()) { + return false; + } + return true; + }; + public static final TypeInformation BSON = TypeInformation.of(Bson.class); protected static final Log LOGGER = LogFactory.getLog(MappingMongoConverter.class); @@ -368,7 +386,7 @@ private R doReadProjection(ConversionContext context, Bson bson, EntityProje evaluator, spELContext); readProperties(context, entity, convertingAccessor, documentAccessor, valueProvider, evaluator, - Predicates.isTrue()); + (mongoPersistentProperties, mongoPersistentProperty) -> true); return (R) projectionFactory.createProjection(mappedType.getType(), accessor.getBean()); } @@ -518,6 +536,23 @@ private ParameterValueProvider getParameterProvider(Con parameterProvider); } + class EvaluatingDocumentAccessor extends DocumentAccessor implements ValueExpressionEvaluator { + + /** + * Creates a new {@link DocumentAccessor} for the given {@link Document}. + * + * @param document must be a {@link Document} effectively, must not be {@literal null}. + */ + public EvaluatingDocumentAccessor(Bson document) { + super(document); + } + + @Override + public T evaluate(String expression) { + return expressionEvaluatorFactory.create(getDocument()).evaluate(expression); + } + } + private S read(ConversionContext context, MongoPersistentEntity entity, Document bson) { S existing = context.findContextualEntity(entity, bson); @@ -525,19 +560,18 @@ private S read(ConversionContext context, MongoPersistentEntity entity, D return existing; } - ValueExpressionEvaluator evaluator = expressionEvaluatorFactory.create(bson); - DocumentAccessor documentAccessor = new DocumentAccessor(bson); - + EvaluatingDocumentAccessor documentAccessor = new EvaluatingDocumentAccessor(bson); InstanceCreatorMetadata instanceCreatorMetadata = entity.getInstanceCreatorMetadata(); ParameterValueProvider provider = instanceCreatorMetadata != null - && instanceCreatorMetadata.hasParameters() ? getParameterProvider(context, entity, documentAccessor, evaluator) + && instanceCreatorMetadata.hasParameters() + ? getParameterProvider(context, entity, documentAccessor, documentAccessor) : NoOpParameterValueProvider.INSTANCE; EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity); S instance = instantiator.createInstance(entity, provider); - return populateProperties(context, entity, documentAccessor, evaluator, instance); + return populateProperties(context, entity, documentAccessor, documentAccessor, instance); } private S populateProperties(ConversionContext context, MongoPersistentEntity entity, @@ -559,9 +593,7 @@ private S populateProperties(ConversionContext context, MongoPersistentEntit MongoDbPropertyValueProvider valueProvider = new MongoDbPropertyValueProvider(contextToUse, documentAccessor, evaluator, spELContext); - Predicate propertyFilter = isIdentifier(entity).or(isConstructorArgument(entity)) - .or(Predicates.negate(PersistentProperty::isReadable)).negate(); - readProperties(contextToUse, entity, accessor, documentAccessor, valueProvider, evaluator, propertyFilter); + readProperties(contextToUse, entity, accessor, documentAccessor, valueProvider, evaluator, PROPERTY_FILTER); return accessor.getBean(); } @@ -606,13 +638,13 @@ private Object readIdValue(ConversionContext context, ValueExpressionEvaluator e private void readProperties(ConversionContext context, MongoPersistentEntity entity, PersistentPropertyAccessor accessor, DocumentAccessor documentAccessor, MongoDbPropertyValueProvider valueProvider, ValueExpressionEvaluator evaluator, - Predicate propertyFilter) { + BiPredicate, MongoPersistentProperty> propertyFilter) { DbRefResolverCallback callback = null; for (MongoPersistentProperty prop : entity) { - if (!propertyFilter.test(prop)) { + if (!propertyFilter.test(entity, prop)) { continue; } @@ -1943,10 +1975,6 @@ static class MongoDbPropertyValueProvider implements PropertyValueProvider S convert(Object source, TypeInformation typeHint, ConversionContext context) { - Assert.notNull(source, "Source must not be null"); - Assert.notNull(typeHint, "TypeInformation must not be null"); - if (conversions.hasCustomReadTarget(source.getClass(), typeHint.getType())) { return (S) elementConverter.convert(source, typeHint); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/CachingMongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/CachingMongoPersistentProperty.java index fce1fbfb86..4eaae53715 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/CachingMongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/CachingMongoPersistentProperty.java @@ -30,6 +30,8 @@ */ public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty { + private final Lazy isEntity = Lazy.of(super::isEntity); + private final Lazy isUnwrapped = Lazy.of(super::isUnwrapped); private final Lazy isIdProperty = Lazy.of(super::isIdProperty); private final Lazy isAssociation = Lazy.of(super::isAssociation); private final Lazy dbref = Lazy.of(super::getDBRef); @@ -58,6 +60,16 @@ public CachingMongoPersistentProperty(Property property, MongoPersistentEntity