From c85ab0ed2cfc6f1e00804372953a528f981367b7 Mon Sep 17 00:00:00 2001 From: Filip Nguyen Date: Mon, 17 Aug 2015 13:31:31 +0200 Subject: [PATCH] Seminar 01 materials --- .../{README-app.md => README-seminar-01.md} | 17 +- .../{README-cont.md => README-seminar-02.md} | 9 +- .../{README-main.md => README.md} | 0 .../{answ-q1.md => answ-s1.md} | 0 .../java/cz/fi/muni/pa165/MainJavaSe.java | 175 +++++++++++++++--- .../cz/fi/muni/pa165/entity/Category.java | 13 +- .../java/cz/fi/muni/pa165/entity/Product.java | 16 +- .../dao/AppManagedEntityManagerTest.java | 98 ++++++++++ .../ContainerManagedEntityManagerTest.java | 98 ++++++++++ 9 files changed, 378 insertions(+), 48 deletions(-) rename eshop-persistence/seminar-persistence/{README-app.md => README-seminar-01.md} (50%) rename eshop-persistence/seminar-persistence/{README-cont.md => README-seminar-02.md} (92%) rename eshop-persistence/seminar-persistence/{README-main.md => README.md} (100%) rename eshop-persistence/seminar-persistence/{answ-q1.md => answ-s1.md} (100%) create mode 100644 eshop-persistence/src/test/java/cz/fi/muni/pa165/dao/AppManagedEntityManagerTest.java create mode 100644 eshop-persistence/src/test/java/cz/fi/muni/pa165/dao/ContainerManagedEntityManagerTest.java diff --git a/eshop-persistence/seminar-persistence/README-app.md b/eshop-persistence/seminar-persistence/README-seminar-01.md similarity index 50% rename from eshop-persistence/seminar-persistence/README-app.md rename to eshop-persistence/seminar-persistence/README-seminar-01.md index 6c32891d..bd9c1901 100755 --- a/eshop-persistence/seminar-persistence/README-app.md +++ b/eshop-persistence/seminar-persistence/README-seminar-01.md @@ -1,5 +1,12 @@ ## Persistence Seminar 01 -Your first tasks will be related to module persistence-app. It will teach you basic work with application managed EntityManager and it's configuration. +This first seminar tries to be as minimalistic as possible. You will work with in-memory database and just one Main Class (MainJavaSe.java). You will be asked to implement parts of methods. Then you will run the method by modifying the Main method. For example if I want to try method corresponding to task07(), then I will modify the main method this way: + ```java + emf = Persistence.createEntityManagerFactory("javaSeUnit"); + // BEGIN YOUR CODE + task06(); + // END YOUR CODE + emf.close(); + ``` **Task 01** Your first task is to locate and download JPA 2.1 specification (JSR 338). It is a PDF file. @@ -15,13 +22,13 @@ https://docs.jboss.org/hibernate/orm/4.3/devguide/en-US/html_single/ . Rerun **T **Task06** This task requires you to work with a detached entity. To start working on a task, just add call to task06() method into your main method. Then implement the task06() according the comments in there. +**Task07** This task is associated with method task07. Parts of the method are commented out, because the implementation of entity Product is not complete yet. Look into comments in task07 and then uncomment the "testing code" in the task07. +**Task08** This task requires you to correctly implement equals and hashcode methods of Product entity. Note that you should use business equivalence. Look into the method comments for more instructions. -**Task 18** Quiz. You can check your answers after you take the quiz in file answ-q1.md +**Task 09** Quiz. You can check your answers after you take the quiz in file answ-s1.md 1. What is the main configuration file for JPA in your application? 2. Where is the following text used and what is the effect of it (use Hibernate dev guide to find answer)? "hibernate.format_sql" 3. What is hibernate.hbm2ddl.auto property in persistence.xml file? - - - +**Task 10** This task requires more investigation from you and work with Hibernate documentation. For the rest of the seminar you can try to configure your persistence unit to use database in your Netbeans. First you will have to create new database in netbeans (Derby) then reconfigure the persistence unit to connect to this database on localhost and set username and password. \ No newline at end of file diff --git a/eshop-persistence/seminar-persistence/README-cont.md b/eshop-persistence/seminar-persistence/README-seminar-02.md similarity index 92% rename from eshop-persistence/seminar-persistence/README-cont.md rename to eshop-persistence/seminar-persistence/README-seminar-02.md index 4ca8ce71..2511c791 100755 --- a/eshop-persistence/seminar-persistence/README-cont.md +++ b/eshop-persistence/seminar-persistence/README-seminar-02.md @@ -1,9 +1,8 @@ ## Seminar 02 30.9.2014 -In this seminar you will reuse your knowledge of mapping and you will extend it a bit. -Most of the seminar is dedicated to gain more confidence with JPQL and Entity States. -Everything that you will do in the second seminar is related container managed EntityManager. +In this seminar you will mostly work with unit tests. These three tests are the most importatnt for you: +AppManagedEntityManagerTest, ContainerManagedEntityManagerTest, ProductDaoTest. The tests are documented, read through the comments before you begin your tasks. -**Task 01** All the assignements of this seminar will require you to work with unit tests. You need to know how to run a unit test from IDE and also from the command line. First run the following single test method from the IDE: JpqlTest.findPets() +**Task 01** First run the following single test method from the IDE: AppManagedEntityManagerTest.persistAndFindProduct() It should pass ``` @@ -13,7 +12,7 @@ Total tests run: 1, Failures: 0, Skips: 0 **Task 02** Try to run the test from **Task 01** through Maven from command line. To do this you should use "mvn test" command with a correct parameter. Find the parameter in maven documentation http://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html -Obviously you should get the same result as in **Task 01** +Obviously you should get the same result as in **Task 01** . **Task 03** There is a new entity in the project PetStore. Map it as an entity and check that it can be stored in the database by running test PetStoreMappingTest.testSimplePersist diff --git a/eshop-persistence/seminar-persistence/README-main.md b/eshop-persistence/seminar-persistence/README.md similarity index 100% rename from eshop-persistence/seminar-persistence/README-main.md rename to eshop-persistence/seminar-persistence/README.md diff --git a/eshop-persistence/seminar-persistence/answ-q1.md b/eshop-persistence/seminar-persistence/answ-s1.md similarity index 100% rename from eshop-persistence/seminar-persistence/answ-q1.md rename to eshop-persistence/seminar-persistence/answ-s1.md diff --git a/eshop-persistence/src/main/java/cz/fi/muni/pa165/MainJavaSe.java b/eshop-persistence/src/main/java/cz/fi/muni/pa165/MainJavaSe.java index 57966810..93477c09 100644 --- a/eshop-persistence/src/main/java/cz/fi/muni/pa165/MainJavaSe.java +++ b/eshop-persistence/src/main/java/cz/fi/muni/pa165/MainJavaSe.java @@ -1,33 +1,55 @@ package cz.fi.muni.pa165; import java.sql.SQLException; +import java.util.Calendar; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; +import javax.persistence.PersistenceException; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import cz.fi.muni.pa165.entity.Category; import cz.fi.muni.pa165.entity.Product; +import cz.fi.muni.pa165.entity.Product.Color; public class MainJavaSe { private static EntityManagerFactory emf; - + public static void main(String[] args) throws SQLException { - //The following line is here just to start up a in-memory database + // The following line is here just to start up a in-memory database new AnnotationConfigApplicationContext(InMemoryDatabaseSpring.class); - + System.out.println(" ****** STARTING PET STORE APPLICATOIN ****** "); emf = Persistence.createEntityManagerFactory("javaSeUnit"); - + // BEGIN YOUR CODE - task06(); + task08(); // END YOUR CODE emf.close(); } - + + private static void task05() { + // TODO under this line, persist two categories, one with name + // Electronics and second with name Musical + + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + List categories = em.createQuery( + "select c from Category c order by c.name", Category.class) + .getResultList(); + + assertEq(categories.get(0).getName(), "Electronics"); + assertEq(categories.get(1).getName(), "Musical"); + + em.getTransaction().commit(); + em.close(); + + System.out.println("Succesfully found Electronics and Musical!"); + } + private static void task06() { EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); @@ -36,18 +58,19 @@ private static void task06() { em.persist(category); em.getTransaction().commit(); em.close(); - - //TODO under this line. create new EM and start new transaction. Merge the detached category - //into the context and change the name to "Electro" + + // TODO under this line. create new EM and start new transaction. Merge + // the detached category + // into the context and change the name to "Electro" + EntityManager em2 = emf.createEntityManager(); em2.getTransaction().begin(); category = em2.merge(category); category.setName("Electro"); em2.getTransaction().commit(); em2.close(); - - - EntityManager checkingEm= emf.createEntityManager(); + + EntityManager checkingEm = emf.createEntityManager(); checkingEm.getTransaction().begin(); Category cat = checkingEm.find(Category.class, category.getId()); assertEq(cat.getName(), "Electro"); @@ -56,27 +79,133 @@ private static void task06() { checkingEm.close(); } - private static void task05() { - //TODO under this line, persist two categories, one with name Electronics and second with name Musical + private static void task07() { + // TODO Map class Product to be an entity with the following attributes: + // * id - autogenerated @Id using IDENTITY column + // * name - nonnullable, unique + // * color - you will have to create new ENUM for this + // * java.util.Date addedDate - this will be only date field, use + // @Temporal annotation + // Then persist exactly one Product with the following values: + // * name='Guitar' + // * color=Color.BLACK + // * dateAdded = 20-01-2011 - to fill java.util.Date, use java.util.Calendar.getTime(). On the Calendar, set only these three fields: YEAR=11, MONTH=0, DAY_OF_MONTH=20 + // + // Additional task: Change the underlying table of Product entity to be + // ESHOP_PRODUCTS. After you do this, check this by + // inspecting console output (the CREATE TABLE statement) + + Product prod = new Product(); + prod.setName("Guitar"); + prod.setColor(Color.BLACK); + Calendar cal1 = Calendar.getInstance(); + cal1.set(Calendar.YEAR, 2011); + cal1.set(Calendar.MONTH, 0); + cal1.set(Calendar.DAY_OF_MONTH, 20); + prod.setAddedDate(cal1.getTime()); + EntityManager e = emf.createEntityManager(); + e.getTransaction().begin(); + e.persist(prod); + e.getTransaction().commit(); + e.close(); + EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); - List categories = em.createQuery("select c from Category c order by c.name", Category.class).getResultList(); + Product p = em.createQuery("select p from Product p", Product.class) + .getSingleResult(); + em.getTransaction().commit(); + em.close(); + + assertEq(p.getName(), "Guitar"); + Calendar cal = Calendar.getInstance(); + cal.setTime(p.getAddedDate()); + assertEq(cal.get(Calendar.YEAR), 2011); + assertEq(cal.get(Calendar.MONTH), 0); + assertEq(cal.get(Calendar.DAY_OF_MONTH), 11); + assertEq(cal.get(Calendar.MINUTE), 0); + assertEq(p.getColor(), Color.BLACK); + System.out + .println("Found Guitar with correct values. Starting uniqueness test."); + + em = emf.createEntityManager(); + em.getTransaction().begin(); + Product p2 = new Product(); + p2.setName("Guitar"); + Product p3 = new Product(); + p3.setName("Violin"); + em.persist(p3); + System.out.println("Successfully persited Violin"); + try { + em.persist(p2); + + throw new RuntimeException( + "Successfully saved new Product with the same name (Guitar) it should be unique!"); + } catch (PersistenceException ex) { + System.out + .println("Unsuccessfully saved second object with name Guitar -> OK"); + } + em.close(); + + + System.out.println("Task7 ok!"); + } + + private static void task08() { + System.out.println("Running TASK 08"); + //Implement business equivalence on Product (equals and hashcode method). Tip: Product.name is nonullable and should have unique values + //This is very important concept and you should understand it beyond just "making this method work" + // see https://developer.jboss.org/wiki/EqualsandHashCode + + //TODO after you implement equals nad hashCode, you can uncomment the code below. It will try + // to check whether you are doing everything correctly. + + class MockProduct extends Product { + private boolean getNameCalled = false; + @Override + public String getName() { + getNameCalled = true; + return super.getName(); + } + } + + Product p = new Product(); + p.setName("X"); + p.setId(2l); + Product p2 = new Product(); + p2.setName("X"); + p2.setId(4l); + MockProduct mp = new MockProduct(); + mp.setName("X"); + p.setId(3l); - assertEq(categories.get(0).getName(),"Electronics"); - assertEq(categories.get(1).getName(),"Musical"); + System.out.println("Your equals and hashcode should work on unique 'name' attribute"); + if (p.equals(p2) && p.hashCode()==p2.hashCode()){ + System.out.println("CORRECT"); + } else System.out.println("INCORRECT!"); + + System.out.println("Your equals should use instanceof and not getClass()=="); + if (p.equals(mp)){ + System.out.println("CORRECT"); + } else + System.out.println("INCORRECT!"); - em.getTransaction().commit(); - em.close(); + System.out.println("Your equals should call getter to get 'name' value on the other object, because other object may be a proxy class instance"); + if (mp.getNameCalled){ + System.out.println("CORRECT"); + } else System.out.println("INCORRECT!"); - System.out.println("Succesfully found Electronics and Musical!"); + } - private static void assertEq(String str1, String str2) { - if (!str1.equals(str2)){ - throw new RuntimeException("Expected these two strings to be identical: "+ str1+", "+ str2); + private static void assertEq(Object obj1, Object obj2) { + if (!obj1.equals(obj2)) { + throw new RuntimeException( + "Expected these two objects to be identical: " + obj1 + + ", " + obj2); } } + } diff --git a/eshop-persistence/src/main/java/cz/fi/muni/pa165/entity/Category.java b/eshop-persistence/src/main/java/cz/fi/muni/pa165/entity/Category.java index 02a9b8b5..7a6c8ab8 100644 --- a/eshop-persistence/src/main/java/cz/fi/muni/pa165/entity/Category.java +++ b/eshop-persistence/src/main/java/cz/fi/muni/pa165/entity/Category.java @@ -24,13 +24,12 @@ public class Category { @Column(nullable=false,unique=true) private String name; -// @ManyToMany(mappedBy="categories") -// private Set products = new HashSet(); - - @OneToMany(mappedBy="category") + @ManyToMany(mappedBy="categories") private Set products = new HashSet(); - + public void addProduct(Product product) { + this.products.add(product); + } public Category(Long categoryId) { this.id = categoryId; @@ -42,9 +41,6 @@ public String getName() { return name; } - protected void addProduct(Product p){ - products.add(p); - } public void setName(String name) { this.name = name; } @@ -83,4 +79,5 @@ public boolean equals(Object obj) { } + } diff --git a/eshop-persistence/src/main/java/cz/fi/muni/pa165/entity/Product.java b/eshop-persistence/src/main/java/cz/fi/muni/pa165/entity/Product.java index f4b34a13..7c63adf7 100644 --- a/eshop-persistence/src/main/java/cz/fi/muni/pa165/entity/Product.java +++ b/eshop-persistence/src/main/java/cz/fi/muni/pa165/entity/Product.java @@ -21,6 +21,8 @@ import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.OrderBy; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; import javax.validation.constraints.NotNull; import cz.fi.muni.pa165.validation.AllOrNothing; @@ -46,15 +48,13 @@ public class Product { /* * The day this item has been added to the eshop */ + @Temporal(TemporalType.DATE) private java.util.Date addedDate; @ManyToMany private Set categories = new HashSet(); - - - @ManyToOne private Category category = null; @@ -71,7 +71,9 @@ public class Product { private Color color; - + public void setId(Long id){ + this.id = id; + } public void removeCategory(Category category) { @@ -97,8 +99,6 @@ public void setCategory(Category category) { public enum Color{ BLACK, WHITE, RED} - - public java.util.Date getAddedDate() { return addedDate; } @@ -189,12 +189,14 @@ public boolean equals(Object obj) { return false; Product other = (Product) obj; if (name == null) { - if (other.getName() != null) + if (other.name != null) return false; } else if (!name.equals(other.getName())) return false; return true; } + + diff --git a/eshop-persistence/src/test/java/cz/fi/muni/pa165/dao/AppManagedEntityManagerTest.java b/eshop-persistence/src/test/java/cz/fi/muni/pa165/dao/AppManagedEntityManagerTest.java new file mode 100644 index 00000000..66a46361 --- /dev/null +++ b/eshop-persistence/src/test/java/cz/fi/muni/pa165/dao/AppManagedEntityManagerTest.java @@ -0,0 +1,98 @@ +package cz.fi.muni.pa165.dao; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceException; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import javax.validation.ConstraintViolationException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests; +import org.testng.Assert; +import org.testng.annotations.Test; + +import cz.fi.muni.pa165.PersistenceSampleApplicationContext; +import cz.fi.muni.pa165.entity.Category; +import cz.fi.muni.pa165.entity.Product; + +@ContextConfiguration(classes=PersistenceSampleApplicationContext.class) +@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD) +public class AppManagedEntityManagerTest extends AbstractTransactionalTestNGSpringContextTests { + + @Autowired + private CategoryDao categoryDao; + + @Autowired + private ProductDao productDao; + + @PersistenceContext + private EntityManager em; + + + @Test(expectedExceptions=ConstraintViolationException.class) + public void nameNotNull(){ + Category cat = new Category(); + cat.setName(null); + categoryDao.create(cat); + } + + @Test(expectedExceptions=PersistenceException.class) + public void nameUnique(){ + Category cat = new Category(); + cat.setName("Electronics"); + categoryDao.create(cat); + cat = new Category(); + cat.setName("Electronics"); + categoryDao.create(cat); + + } + + + @Test + public void createCategory(){ + Category cat = new Category(); + cat.setName("Electronics"); + categoryDao.create(cat); + + em.flush(); + em.clear(); + + Category created = categoryDao.findById(cat.getId()); + + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(Product.class); + Root p = cq.from(Product.class); + cq.select(p).where(cb.equal(p.get("name"),"Guitar")); + TypedQuery tq= em.createQuery(cq); + tq.getResultList(); + + + Assert.assertEquals(created, cat); + } + + @Test + public void productsInCategory(){ + Category categoryElectro = new Category(); + categoryElectro.setName("Electronics"); + categoryDao.create(categoryElectro); + + Product p = new Product(); + p.setName("TV"); + + productDao.create(p); + p.addCategory(categoryElectro); + + em.flush(); + em.clear(); + + Category found = categoryDao.findById(categoryElectro.getId()); + Assert.assertEquals(found.getProducts().size(), 1); + Assert.assertEquals(found.getProducts().iterator().next().getName(), "TV"); + } +} diff --git a/eshop-persistence/src/test/java/cz/fi/muni/pa165/dao/ContainerManagedEntityManagerTest.java b/eshop-persistence/src/test/java/cz/fi/muni/pa165/dao/ContainerManagedEntityManagerTest.java new file mode 100644 index 00000000..7ffd1a4b --- /dev/null +++ b/eshop-persistence/src/test/java/cz/fi/muni/pa165/dao/ContainerManagedEntityManagerTest.java @@ -0,0 +1,98 @@ +package cz.fi.muni.pa165.dao; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceException; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import javax.validation.ConstraintViolationException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests; +import org.testng.Assert; +import org.testng.annotations.Test; + +import cz.fi.muni.pa165.PersistenceSampleApplicationContext; +import cz.fi.muni.pa165.entity.Category; +import cz.fi.muni.pa165.entity.Product; + +@ContextConfiguration(classes=PersistenceSampleApplicationContext.class) +@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD) +public class ContainerManagedEntityManagerTest extends AbstractTransactionalTestNGSpringContextTests { + + @Autowired + private CategoryDao categoryDao; + + @Autowired + private ProductDao productDao; + + @PersistenceContext + private EntityManager em; + + + @Test(expectedExceptions=ConstraintViolationException.class) + public void nameNotNull(){ + Category cat = new Category(); + cat.setName(null); + categoryDao.create(cat); + } + + @Test(expectedExceptions=PersistenceException.class) + public void nameUnique(){ + Category cat = new Category(); + cat.setName("Electronics"); + categoryDao.create(cat); + cat = new Category(); + cat.setName("Electronics"); + categoryDao.create(cat); + + } + + + @Test + public void createCategory(){ + Category cat = new Category(); + cat.setName("Electronics"); + categoryDao.create(cat); + + em.flush(); + em.clear(); + + Category created = categoryDao.findById(cat.getId()); + + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(Product.class); + Root p = cq.from(Product.class); + cq.select(p).where(cb.equal(p.get("name"),"Guitar")); + TypedQuery tq= em.createQuery(cq); + tq.getResultList(); + + + Assert.assertEquals(created, cat); + } + + @Test + public void productsInCategory(){ + Category categoryElectro = new Category(); + categoryElectro.setName("Electronics"); + categoryDao.create(categoryElectro); + + Product p = new Product(); + p.setName("TV"); + + productDao.create(p); + p.addCategory(categoryElectro); + + em.flush(); + em.clear(); + + Category found = categoryDao.findById(categoryElectro.getId()); + Assert.assertEquals(found.getProducts().size(), 1); + Assert.assertEquals(found.getProducts().iterator().next().getName(), "TV"); + } +}