- 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();
+ }
+
+}
+