From e2b9de4fbbd2b2bbb9522ae23f30ba1f43abda46 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Tue, 16 Mar 2021 18:04:41 +0100 Subject: [PATCH] Add Spring Data JDBC example for jMolecules. --- jdbc/jmolecules/pom.xml | 69 +++++++++++++++++ .../jdbc/jmolecules/Application.java | 30 ++++++++ .../jdbc/jmolecules/customer/Address.java | 26 +++++++ .../jdbc/jmolecules/customer/Customer.java | 64 ++++++++++++++++ .../jdbc/jmolecules/customer/Customers.java | 28 +++++++ .../jdbc/jmolecules/order/LineItem.java | 26 +++++++ .../jdbc/jmolecules/order/Order.java | 73 ++++++++++++++++++ .../jdbc/jmolecules/order/Orders.java | 28 +++++++ jdbc/jmolecules/src/main/resources/schema.sql | 28 +++++++ .../ApplicationIntegrationTests.java | 74 +++++++++++++++++++ jdbc/pom.xml | 1 + 11 files changed, 447 insertions(+) create mode 100644 jdbc/jmolecules/pom.xml create mode 100644 jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/Application.java create mode 100644 jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Address.java create mode 100644 jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Customer.java create mode 100644 jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Customers.java create mode 100644 jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/LineItem.java create mode 100644 jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/Order.java create mode 100644 jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/Orders.java create mode 100644 jdbc/jmolecules/src/main/resources/schema.sql create mode 100644 jdbc/jmolecules/src/test/java/example/springdata/jdbc/jmolecules/ApplicationIntegrationTests.java diff --git a/jdbc/jmolecules/pom.xml b/jdbc/jmolecules/pom.xml new file mode 100644 index 00000000..b2262476 --- /dev/null +++ b/jdbc/jmolecules/pom.xml @@ -0,0 +1,69 @@ + + 4.0.0 + + + org.springframework.data.examples + spring-data-jdbc-examples + 2.0.0.BUILD-SNAPSHOT + + + Spring Data JDBC - jMolecules Example + spring-data-jdbc-jmolecules + + + 2021.0.0-SNAPSHOT + 1.2.0 + 0.2.0 + + + + + + com.h2database + h2 + runtime + + + + + + 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/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/Application.java b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/Application.java new file mode 100644 index 00000000..ce4703ee --- /dev/null +++ b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/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.jdbc.jmolecules; + +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/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Address.java b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Address.java new file mode 100644 index 00000000..5e2fce82 --- /dev/null +++ b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/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.jdbc.jmolecules.customer; + +import lombok.Value; + +import org.jmolecules.ddd.annotation.ValueObject; + +@Value +@ValueObject +public class Address { + private final String street, city, zipCode; +} diff --git a/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Customer.java b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Customer.java new file mode 100644 index 00000000..ad3312d6 --- /dev/null +++ b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Customer.java @@ -0,0 +1,64 @@ +/* + * 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.jdbc.jmolecules.customer; + +import example.springdata.jdbc.jmolecules.customer.Customer.CustomerId; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +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 @Setter 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().toString()); + + 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 String id; + } +} diff --git a/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Customers.java b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Customers.java new file mode 100644 index 00000000..d7ae0563 --- /dev/null +++ b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/customer/Customers.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.jdbc.jmolecules.customer; + +import example.springdata.jdbc.jmolecules.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/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/LineItem.java b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/LineItem.java new file mode 100644 index 00000000..85fd2e6f --- /dev/null +++ b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/LineItem.java @@ -0,0 +1,26 @@ +/* + * 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.jdbc.jmolecules.order; + +import lombok.Value; + +import org.jmolecules.ddd.annotation.ValueObject; + +@Value +@ValueObject +public class LineItem { + String description; +} diff --git a/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/Order.java b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/Order.java new file mode 100644 index 00000000..fba4db25 --- /dev/null +++ b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/Order.java @@ -0,0 +1,73 @@ +/* + * 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.jdbc.jmolecules.order; + +import example.springdata.jdbc.jmolecules.customer.Customer; +import example.springdata.jdbc.jmolecules.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; +import org.springframework.data.relational.core.mapping.Column; +import org.springframework.data.relational.core.mapping.Table; + +/** + * @author Oliver Drotbohm + */ +@Table("MY_ORDER") +@Getter +@ToString +@RequiredArgsConstructor +public class Order implements AggregateRoot { + + private final OrderId id; + private @Column("FOO") 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/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/Orders.java b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/order/Orders.java new file mode 100644 index 00000000..0f178d63 --- /dev/null +++ b/jdbc/jmolecules/src/main/java/example/springdata/jdbc/jmolecules/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.jdbc.jmolecules.order; + +import example.springdata.jdbc.jmolecules.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/jdbc/jmolecules/src/main/resources/schema.sql b/jdbc/jmolecules/src/main/resources/schema.sql new file mode 100644 index 00000000..4a75e4b7 --- /dev/null +++ b/jdbc/jmolecules/src/main/resources/schema.sql @@ -0,0 +1,28 @@ +CREATE TABLE IF NOT EXISTS customer ( + id VARCHAR(100) PRIMARY KEY, + firstname VARCHAR(100), + lastname VARCHAR(100) +); + +CREATE TABLE IF NOT EXISTS address ( + street VARCHAR(100), + city VARCHAR(100), + zip_code VARCHAR(100), + customer VARCHAR(100), + customer_key VARCHAR(100) +); + +CREATE TABLE IF NOT EXISTS my_order ( + id VARCHAR(100), + customer VARCHAR(100) +); + +CREATE TABLE IF NOT EXISTS line_item ( + my_order_key VARCHAR(100), + description VARCHAR(100), + foo VARCHAR(100) +); + +// CREATE TABLE IF NOT EXISTS Lego_Set (id INTEGER, name VARCHAR(100), min_Age INTEGER, max_Age INTEGER); +// CREATE TABLE IF NOT EXISTS Handbuch (handbuch_id INTEGER, author VARCHAR(100), text CLOB); +// CREATE TABLE IF NOT EXISTS Model (name VARCHAR(100), description CLOB, lego_set INTEGER); diff --git a/jdbc/jmolecules/src/test/java/example/springdata/jdbc/jmolecules/ApplicationIntegrationTests.java b/jdbc/jmolecules/src/test/java/example/springdata/jdbc/jmolecules/ApplicationIntegrationTests.java new file mode 100644 index 00000000..cdaf6fd1 --- /dev/null +++ b/jdbc/jmolecules/src/test/java/example/springdata/jdbc/jmolecules/ApplicationIntegrationTests.java @@ -0,0 +1,74 @@ +/* + * 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.jdbc.jmolecules; + +import static org.assertj.core.api.Assertions.*; + +import example.springdata.jdbc.jmolecules.customer.Address; +import example.springdata.jdbc.jmolecules.customer.Customer; +import example.springdata.jdbc.jmolecules.customer.Customers; +import example.springdata.jdbc.jmolecules.order.Order; +import example.springdata.jdbc.jmolecules.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.jdbc.core.mapping.JdbcMappingContext; +import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; +import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; + +/** + * @author Oliver Drotbohm + */ +@SpringBootTest +@RequiredArgsConstructor +class ApplicationIntegrationTests { + + private final ConfigurableApplicationContext context; + + @Test + void exposesAssociationInMetamodel() { + + JdbcMappingContext mapping = context.getBean(JdbcMappingContext.class); + RelationalPersistentEntity entity = mapping.getRequiredPersistentEntity(Order.class); + RelationalPersistentProperty 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)); + + customer.setFirstname("Carter"); + customer = customers.save(customer); + + 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/jdbc/pom.xml b/jdbc/pom.xml index 398da725..f7a9dada 100644 --- a/jdbc/pom.xml +++ b/jdbc/pom.xml @@ -19,6 +19,7 @@ basics mybatis + jmolecules jooq