diff --git a/README.md b/README.md
index ab63a1a2..6eb37776 100644
--- a/README.md
+++ b/README.md
@@ -59,6 +59,7 @@ We have separate folders for the samples of individual modules:
* `geo-json` - Example project showing usage of [GeoJSON](http://geojson.org) with MongoDB.
* `gridfs` - Example project showing usage of gridFS with MongoDB.
* `java8` - Example of how to use Spring Data MongoDB with Java 8 date time types as well as the usage of `Optional` as return type for repository methods. Note, this project requires to be build with JDK 8.
+* `jmolecules` - Example of Spring Data MongoDB working with a jMolecules based domain model.
* `kotlin` - Example for using [Kotlin](https://kotlinlang.org/) with MongoDB.
* `query-by-example` - Example project showing usage of Query by Example with MongoDB.
* `querydsl` - Example project showing imperative and reactive [Querydsl](https://github.com/querydsl/querydsl) support for MongoDB.
@@ -113,5 +114,5 @@ We have separate folders for the samples of individual modules:
## Note
-* The example projects make use of the [Lombok](https://projectlombok.org/) plugin. To get proper code navigation in your IDE, you must install it separately.
+* The example projects make use of the [Lombok](https://projectlombok.org/) plugin. To get proper code navigation in your IDE, you must install it separately.
Lombok is available in the IntelliJ plugins repository and as a [download](https://projectlombok.org/download) for Eclipse-based IDEs.
\ No newline at end of file
diff --git a/mongodb/jmolecules/pom.xml b/mongodb/jmolecules/pom.xml
new file mode 100644
index 00000000..fb4ae9fb
--- /dev/null
+++ b/mongodb/jmolecules/pom.xml
@@ -0,0 +1,63 @@
+
+ 4.0.0
+
+
+ org.springframework.data.examples
+ spring-data-mongodb-examples
+ 2.0.0.BUILD-SNAPSHOT
+
+
+ Spring Data MongoDB - jMolecules Example
+ spring-data-mongodb-jmolecules
+
+
+ 2021.0.0-SNAPSHOT
+ 1.2.0
+ 0.2.0
+
+
+
+
+
+
+
+ org.jmolecules.integrations
+ jmolecules-spring
+ ${jmolecules-integration.version}
+
+
+
+ org.jmolecules
+ jmolecules-events
+ ${jmolecules.version}
+
+
+
+
+
+
+
+ net.bytebuddy
+ byte-buddy-maven-plugin
+ ${byte-buddy.version}
+
+
+
+ transform
+
+
+
+
+
+ org.jmolecules.integrations
+ jmolecules-bytebuddy
+ ${jmolecules-integration.version}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mongodb/jmolecules/src/main/java/example/springdata/mongodb/Application.java b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/Application.java
new file mode 100644
index 00000000..bb6cb0fd
--- /dev/null
+++ b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/Application.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 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
+ *
+ * https://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 example.springdata.mongodb;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author Oliver Drotbohm
+ */
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/mongodb/jmolecules/src/main/java/example/springdata/mongodb/customer/Address.java b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/customer/Address.java
new file mode 100644
index 00000000..ba7be86c
--- /dev/null
+++ b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/customer/Address.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2021 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
+ *
+ * https://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 example.springdata.mongodb.customer;
+
+import lombok.Value;
+
+import org.jmolecules.ddd.annotation.ValueObject;
+
+@Value
+@ValueObject
+public class Address {
+ private final String street, city, zipCode;
+}
diff --git a/mongodb/jmolecules/src/main/java/example/springdata/mongodb/customer/Customer.java b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/customer/Customer.java
new file mode 100644
index 00000000..b0621268
--- /dev/null
+++ b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/customer/Customer.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2020 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
+ *
+ * https://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 example.springdata.mongodb.customer;
+
+import example.springdata.mongodb.customer.Customer.CustomerId;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.ToString;
+import lombok.Value;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.jmolecules.ddd.types.AggregateRoot;
+import org.jmolecules.ddd.types.Identifier;
+import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.util.Assert;
+
+/**
+ * @author Oliver Drotbohm
+ */
+@Getter
+@ToString
+@AllArgsConstructor(access = AccessLevel.PRIVATE, onConstructor = @__(@PersistenceConstructor))
+public class Customer implements AggregateRoot {
+
+ private final CustomerId id;
+ private String firstname, lastname;
+ private List addresses;
+
+ public Customer(String firstname, String lastname, Address address) {
+
+ Assert.notNull(address, "Address must not be null!");
+
+ this.id = CustomerId.of(UUID.randomUUID());
+
+ this.firstname = firstname;
+ this.lastname = lastname;
+
+ this.addresses = new ArrayList<>();
+ this.addresses.add(address);
+ }
+
+ @Value(staticConstructor = "of")
+ public static class CustomerId implements Identifier {
+ private final UUID id;
+ }
+}
diff --git a/mongodb/jmolecules/src/main/java/example/springdata/mongodb/customer/Customers.java b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/customer/Customers.java
new file mode 100644
index 00000000..1c1139d3
--- /dev/null
+++ b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/customer/Customers.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 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
+ *
+ * https://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 example.springdata.mongodb.customer;
+
+import example.springdata.mongodb.customer.Customer.CustomerId;
+
+import org.jmolecules.ddd.types.Repository;
+import org.jmolecules.spring.AssociationResolver;
+
+/**
+ * @author Oliver Drotbohm
+ */
+public interface Customers extends Repository, AssociationResolver {
+ Customer save(Customer customer);
+}
diff --git a/mongodb/jmolecules/src/main/java/example/springdata/mongodb/order/LineItem.java b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/order/LineItem.java
new file mode 100644
index 00000000..ca36c610
--- /dev/null
+++ b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/order/LineItem.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2020 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
+ *
+ * https://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 example.springdata.mongodb.order;
+
+import lombok.Value;
+
+import org.jmolecules.ddd.annotation.ValueObject;
+
+@Value
+@ValueObject
+public class LineItem {
+ String description;
+}
diff --git a/mongodb/jmolecules/src/main/java/example/springdata/mongodb/order/Order.java b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/order/Order.java
new file mode 100644
index 00000000..94cbc673
--- /dev/null
+++ b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/order/Order.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 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
+ *
+ * https://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 example.springdata.mongodb.order;
+
+import example.springdata.mongodb.customer.Customer;
+import example.springdata.mongodb.customer.Customer.CustomerId;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
+import lombok.Value;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.jmolecules.ddd.types.AggregateRoot;
+import org.jmolecules.ddd.types.Association;
+import org.jmolecules.ddd.types.Identifier;
+
+/**
+ * @author Oliver Drotbohm
+ */
+@Getter
+@ToString
+@RequiredArgsConstructor
+public class Order implements AggregateRoot {
+
+ private final OrderId id;
+ private List lineItems;
+ private Association customer;
+
+ public Order(Customer customer) {
+
+ this.id = OrderId.of(UUID.randomUUID());
+ this.customer = Association.forAggregate(customer);
+ this.lineItems = new ArrayList<>();
+ }
+
+ public Order addLineItem(String description) {
+
+ LineItem item = new LineItem(description);
+
+ this.lineItems.add(item);
+
+ return this;
+ }
+
+ @Value(staticConstructor = "of")
+ public static class OrderId implements Identifier {
+
+ private final UUID orderId;
+
+ public static OrderId create() {
+ return OrderId.of(UUID.randomUUID());
+ }
+ }
+}
diff --git a/mongodb/jmolecules/src/main/java/example/springdata/mongodb/order/Orders.java b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/order/Orders.java
new file mode 100644
index 00000000..28862aa5
--- /dev/null
+++ b/mongodb/jmolecules/src/main/java/example/springdata/mongodb/order/Orders.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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 example.springdata.mongodb.order;
+
+import example.springdata.mongodb.order.Order.OrderId;
+
+import org.jmolecules.ddd.types.Repository;
+import org.jmolecules.spring.AssociationResolver;
+
+/**
+ * @author Oliver Drotbohm
+ */
+public interface Orders extends Repository, AssociationResolver {
+ Order save(Order order);
+}
diff --git a/mongodb/jmolecules/src/main/resources/application.properties b/mongodb/jmolecules/src/main/resources/application.properties
new file mode 100644
index 00000000..e69de29b
diff --git a/mongodb/jmolecules/src/test/java/example/springdata/mongodb/ApplicationIntegrationTests.java b/mongodb/jmolecules/src/test/java/example/springdata/mongodb/ApplicationIntegrationTests.java
new file mode 100644
index 00000000..d0652106
--- /dev/null
+++ b/mongodb/jmolecules/src/test/java/example/springdata/mongodb/ApplicationIntegrationTests.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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 example.springdata.mongodb;
+
+import static org.assertj.core.api.Assertions.*;
+
+import example.springdata.mongodb.customer.Address;
+import example.springdata.mongodb.customer.Customer;
+import example.springdata.mongodb.customer.Customers;
+import example.springdata.mongodb.order.Order;
+import example.springdata.mongodb.order.Orders;
+import lombok.RequiredArgsConstructor;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
+import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
+import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
+
+/**
+ * @author Oliver Drotbohm
+ */
+@SpringBootTest
+@RequiredArgsConstructor
+class ApplicationIntegrationTests {
+
+ private final ConfigurableApplicationContext context;
+
+ @Test
+ void exposesAssociationInMetamodel() {
+
+ MongoMappingContext mapping = context.getBean(MongoMappingContext.class);
+ MongoPersistentEntity> entity = mapping.getRequiredPersistentEntity(Order.class);
+ MongoPersistentProperty customer = entity.getRequiredPersistentProperty("customer");
+
+ assertThat(customer.isAssociation()).isTrue();
+ }
+
+ @Test
+ void persistsDomainModel() {
+
+ Address address = new Address("41 Greystreet", "Dreaming Tree", "2731");
+
+ Customers customers = context.getBean(Customers.class);
+ Customer customer = customers.save(new Customer("Dave", "Matthews", address));
+
+ Orders orders = context.getBean(Orders.class);
+
+ Order order = new Order(customer)
+ .addLineItem("Foo")
+ .addLineItem("Bar");
+
+ Order result = orders.save(order);
+
+ assertThat(customers.resolveRequired(result.getCustomer()));
+ }
+}
diff --git a/mongodb/pom.xml b/mongodb/pom.xml
index 68926a26..965744e8 100644
--- a/mongodb/pom.xml
+++ b/mongodb/pom.xml
@@ -24,6 +24,7 @@
geo-json
gridfs
java8
+ jmolecules
kotlin
query-by-example
reactive