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