From 9d4fff6029a67efeeb1aeaad980fc2c5f8a9fcef Mon Sep 17 00:00:00 2001 From: hoswey Date: Fri, 27 Nov 2015 11:22:33 +0800 Subject: [PATCH] Fix #216 Repository vs DAO --- pom.xml | 12 ++ repository/etc/repository.png | Bin 9683 -> 55254 bytes repository/etc/repository.ucls | 40 ++++++- repository/index.md | 6 + repository/pom.xml | 73 ++++++------ .../java/com/iluwatar/repository/App.java | 34 ++++-- .../java/com/iluwatar/repository/Person.java | 58 +++++++++- .../iluwatar/repository/PersonRepository.java | 8 +- .../repository/PersonSpecifications.java | 50 ++++++++ .../src/main/resources/applicationContext.xml | 6 +- .../java/com/iluwatar/repository/AppTest.java | 19 --- .../iluwatar/repository/RepositoryTest.java | 109 ++++++++++++++++++ 12 files changed, 343 insertions(+), 72 deletions(-) create mode 100644 repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java delete mode 100644 repository/src/test/java/com/iluwatar/repository/AppTest.java create mode 100644 repository/src/test/java/com/iluwatar/repository/RepositoryTest.java diff --git a/pom.xml b/pom.xml index bcdf9aff..e6603b06 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ UTF-8 5.0.1.Final + 4.1.7.RELEASE 1.9.0.RELEASE 1.4.188 4.12 @@ -20,6 +21,7 @@ 1.4 2.15.3 1.2.17 + 18.0 abstract-factory @@ -101,6 +103,11 @@ ${hibernate.version} + org.springframework + spring-test + ${spring.version} + + org.springframework.data spring-data-jpa ${spring-data.version} @@ -142,6 +149,11 @@ log4j ${log4j.version} + + com.google.guava + guava + ${guava.version} + diff --git a/repository/etc/repository.png b/repository/etc/repository.png index 1e031f3ae327d8dd20c46ea0b0fa69a0333efc27..08d5d571d0a82607a3c714686c6f58e0999f81b1 100644 GIT binary patch literal 55254 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%0Db#Ymqoa9Uf5(TB(u>Gdf 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 literal 9683 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 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repository/index.md b/repository/index.md index a65044d2..8ecd1652 100644 --- a/repository/index.md +++ b/repository/index.md @@ -25,3 +25,9 @@ querying is utilized. **Real world examples:** * [Spring Data](http://projects.spring.io/spring-data/) + +**Credits:** + +* [Don’t use DAO, use Repository](http://thinkinginobjects.com/2012/08/26/dont-use-dao-use-repository/) +* [Advanced Spring Data JPA - Specifications and Querydsl](https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/) + diff --git a/repository/pom.xml b/repository/pom.xml index 60b51568..c3adc7a9 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -1,35 +1,42 @@ - - 4.0.0 - - com.iluwatar - java-design-patterns - 1.8.0-SNAPSHOT - - repository - - - org.springframework.data - spring-data-jpa - - - org.hibernate - hibernate-entitymanager - - - commons-dbcp - commons-dbcp - - - com.h2database - h2 - - - junit - junit - test - - + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.8.0-SNAPSHOT + + repository + + + org.springframework + spring-test + + + org.springframework.data + spring-data-jpa + + + org.hibernate + hibernate-entitymanager + + + commons-dbcp + commons-dbcp + + + com.h2database + h2 + + + junit + junit + test + + + com.google.guava + guava + + diff --git a/repository/src/main/java/com/iluwatar/repository/App.java b/repository/src/main/java/com/iluwatar/repository/App.java index fb9680cb..2442c854 100644 --- a/repository/src/main/java/com/iluwatar/repository/App.java +++ b/repository/src/main/java/com/iluwatar/repository/App.java @@ -5,7 +5,6 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; /** - * * Repository pattern mediates between the domain and data mapping layers using a collection-like * interface for accessing domain objects. A system with complex domain model often benefits from a * layer that isolates domain objects from the details of the database access code and in such @@ -16,9 +15,9 @@ *

* In this example we utilize Spring Data to automatically generate a repository for us from the * {@link Person} domain object. Using the {@link PersonRepository} we perform CRUD operations on - * the entity. Underneath we have configured in-memory H2 database for which schema is created and - * dropped on each run. - * + * the entity, moreover, the query by {@link org.springframework.data.jpa.domain.Specification} are + * also performed. Underneath we have configured in-memory H2 database for which schema is created + * and dropped on each run. */ public class App { @@ -28,16 +27,21 @@ public class App { * @param args command line args */ public static void main(String[] args) { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); PersonRepository repository = context.getBean(PersonRepository.class); - Person peter = new Person("Peter", "Sagan"); - Person nasta = new Person("Nasta", "Kuzminova"); + Person peter = new Person("Peter", "Sagan", 17); + Person nasta = new Person("Nasta", "Kuzminova", 25); + Person john = new Person("John", "lawrence", 35); + Person terry = new Person("Terry", "Law", 36); // Add new Person records repository.save(peter); repository.save(nasta); + repository.save(john); + repository.save(terry); // Count Person records System.out.println("Count Person records: " + repository.count()); @@ -48,9 +52,6 @@ public static void main(String[] args) { System.out.println(person); } - // Find Person by surname - System.out.println("Find by surname 'Sagan': " + repository.findBySurname("Sagan")); - // Update Person nasta.setName("Barbora"); nasta.setSurname("Spotakova"); @@ -61,9 +62,22 @@ public static void main(String[] args) { // Remove record from Person repository.delete(2L); - // And finally count records + // count records System.out.println("Count Person records: " + repository.count()); + // find by name + Person p = repository.findOne(new PersonSpecifications.NameEqualSpec("John")); + System.out.println("Find by John is " + p); + + // find by age + persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40)); + + System.out.println("Find Person with age between 20,40: "); + for (Person person : persons) { + System.out.println(person); + } + context.close(); + } } diff --git a/repository/src/main/java/com/iluwatar/repository/Person.java b/repository/src/main/java/com/iluwatar/repository/Person.java index 97d5e712..57439b8c 100644 --- a/repository/src/main/java/com/iluwatar/repository/Person.java +++ b/repository/src/main/java/com/iluwatar/repository/Person.java @@ -18,11 +18,14 @@ public class Person { private String name; private String surname; + private int age; + public Person() {} - public Person(String name, String surname) { + public Person(String name, String surname, int age) { this.name = name; this.surname = surname; + this.age = age; } public Long getId() { @@ -49,8 +52,59 @@ public void setSurname(String surname) { this.surname = surname; } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + @Override public String toString() { - return "Person [id=" + id + ", name=" + name + ", surname=" + surname + "]"; + return "Person [id=" + id + ", name=" + name + ", surname=" + surname + ", age=" + age + "]"; + } + + @Override + public int hashCode() { + + final int prime = 31; + int result = 1; + result = prime * result + age; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((surname == null) ? 0 : surname.hashCode()); + return result; } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Person other = (Person) obj; + if (age != other.age) + return false; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (surname == null) { + if (other.surname != null) + return false; + } else if (!surname.equals(other.surname)) + return false; + return true; + } + } diff --git a/repository/src/main/java/com/iluwatar/repository/PersonRepository.java b/repository/src/main/java/com/iluwatar/repository/PersonRepository.java index 167b40d1..98bb7abc 100644 --- a/repository/src/main/java/com/iluwatar/repository/PersonRepository.java +++ b/repository/src/main/java/com/iluwatar/repository/PersonRepository.java @@ -1,7 +1,6 @@ package com.iluwatar.repository; -import java.util.List; - +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @@ -11,7 +10,8 @@ * */ @Repository -public interface PersonRepository extends CrudRepository { +public interface PersonRepository + extends CrudRepository, JpaSpecificationExecutor { - public List findBySurname(String surname); + public Person findByName(String name); } diff --git a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java new file mode 100644 index 00000000..dadaae36 --- /dev/null +++ b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java @@ -0,0 +1,50 @@ +package com.iluwatar.repository; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.springframework.data.jpa.domain.Specification; + +/** + * Helper class, includes vary Specification as the abstraction of sql query criteria + */ +public class PersonSpecifications { + + public static class AgeBetweenSpec implements Specification { + + private int from; + + private int to; + + public AgeBetweenSpec(int from, int to) { + this.from = from; + this.to = to; + } + + @Override + public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) { + + return cb.between(root.get("age"), from, to); + + } + + } + public static class NameEqualSpec implements Specification { + + public String name; + + public NameEqualSpec(String name) { + this.name = name; + } + + public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) { + + return cb.equal(root.get("name"), this.name); + + } + } + +} + diff --git a/repository/src/main/resources/applicationContext.xml b/repository/src/main/resources/applicationContext.xml index 3fe15b2f..9322c9f6 100644 --- a/repository/src/main/resources/applicationContext.xml +++ b/repository/src/main/resources/applicationContext.xml @@ -6,10 +6,10 @@ xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd - http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd"> - - + http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> + + diff --git a/repository/src/test/java/com/iluwatar/repository/AppTest.java b/repository/src/test/java/com/iluwatar/repository/AppTest.java deleted file mode 100644 index 929f6194..00000000 --- a/repository/src/test/java/com/iluwatar/repository/AppTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.iluwatar.repository; - -import org.junit.Test; - -import com.iluwatar.repository.App; - -/** - * - * Application test - * - */ -public class AppTest { - - @Test - public void test() { - String[] args = {}; - App.main(args); - } -} diff --git a/repository/src/test/java/com/iluwatar/repository/RepositoryTest.java b/repository/src/test/java/com/iluwatar/repository/RepositoryTest.java new file mode 100644 index 00000000..26689321 --- /dev/null +++ b/repository/src/test/java/com/iluwatar/repository/RepositoryTest.java @@ -0,0 +1,109 @@ +package com.iluwatar.repository; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Resource; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.common.collect.Lists; + +/** + * Test case to test the functions of {@link PersonRepository}, beside the CRUD functions, the query + * by {@link org.springframework.data.jpa.domain.Specification} are also test. + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"classpath:applicationContext.xml"}) +public class RepositoryTest { + + @Resource + private PersonRepository repository; + + Person peter = new Person("Peter", "Sagan", 17); + Person nasta = new Person("Nasta", "Kuzminova", 25); + Person john = new Person("John", "lawrence", 35); + Person terry = new Person("Terry", "Law", 36); + + List persons = Arrays.asList(peter, nasta, john, terry); + + /** + * Prepare data for test + */ + @Before + public void setup() { + + repository.save(persons); + } + + @Test + public void testFindAll() { + + List actuals = Lists.newArrayList(repository.findAll()); + assertTrue(actuals.containsAll(persons) && persons.containsAll(actuals)); + } + + @Test + public void testSave() { + + Person terry = repository.findByName("Terry"); + terry.setSurname("Lee"); + terry.setAge(47); + repository.save(terry); + + terry = repository.findByName("Terry"); + assertEquals(terry.getSurname(), "Lee"); + assertEquals(47, terry.getAge()); + } + + @Test + public void testDelete() { + + Person terry = repository.findByName("Terry"); + repository.delete(terry); + + assertEquals(3, repository.count()); + assertNull(repository.findByName("Terry")); + } + + @Test + public void testCount() { + + assertEquals(4, repository.count()); + } + + @Test + public void testFindAllByAgeBetweenSpec() { + + List persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40)); + + assertEquals(3, persons.size()); + assertTrue(persons.stream().allMatch((item) -> { + return item.getAge() > 20 && item.getAge() < 40; + })); + } + + @Test + public void testFindOneByNameEqualSpec() { + + Person actual = repository.findOne(new PersonSpecifications.NameEqualSpec("Terry")); + assertEquals(terry, actual); + } + + @After + public void cleanup() { + + repository.deleteAll(); + } + +} +