/* * Hibernate Search, full-text search for your domain model * * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.search.test.embedded.update; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import org.apache.lucene.index.Term; import org.apache.lucene.search.TermQuery; import org.hibernate.Transaction; import org.hibernate.search.FullTextQuery; import org.hibernate.search.FullTextSession; import org.hibernate.search.Search; import org.hibernate.search.annotations.DocumentId; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.Indexed; import org.hibernate.search.annotations.IndexedEmbedded; import org.hibernate.search.test.SearchTestBase; import org.hibernate.search.testsupport.TestForIssue; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; /** * Unit test about updating an entity with collection marked with @IndexedEmbedded annotation * * @author Davide Di Somma <davide.disomma@gmail.com> */ public class UpdateIndexedEmbeddedCollectionTest extends SearchTestBase { @TestForIssue(jiraKey = "HSEARCH-734") @Test public void testUpdateIndexedEmbeddedCollectionWithNull() throws Exception { // load the truck with number plate "LVN 746 XD" guided by driver Mark Smith Driver driverSmith = new Driver( "Mark", "Smith" ); Truck truckLVN746XD = new Truck( "LVN 746 XD" ); driverSmith.setTruck( truckLVN746XD ); Item item1 = new Item( "Sofa", 1 ); Item item2 = new Item( "Table", 3 ); Item item3 = new Item( "Chair", 24 ); Set<Item> itemsTruckLVN746XD = new HashSet<Item>(); itemsTruckLVN746XD.add( item1 ); itemsTruckLVN746XD.add( item2 ); itemsTruckLVN746XD.add( item3 ); truckLVN746XD.setItems( itemsTruckLVN746XD ); // load the truck with number plate "MLN 666 DJ" guided by driver John Doe Driver driverDoe = new Driver( "John", "Doe" ); Truck truckMLN666DJ = new Truck( "MLN 666 DJ" ); driverDoe.setTruck( truckMLN666DJ ); Item item4 = new Item( "Armchair", 8 ); Item item5 = new Item( "Chair", 19 ); Set<Item> itemsTruckMLN666DJ = new HashSet<Item>(); itemsTruckMLN666DJ.add( item4 ); itemsTruckMLN666DJ.add( item5 ); truckMLN666DJ.setItems( itemsTruckMLN666DJ ); // first operation -> save FullTextSession session = Search.getFullTextSession( openSession() ); Transaction tx = session.beginTransaction(); session.save( driverSmith ); session.save( driverDoe ); tx.commit(); session.close(); // assert that everything got saved and indexed correctly final Long truckLVN746XDId = truckLVN746XD.getId(); final Long truckMLN666DJId = truckMLN666DJ.getId(); session = Search.getFullTextSession( openSession() ); tx = session.beginTransaction(); assertEquals( truckMLN666DJId, findTruckIdFromIndex( session, "armchair" ) ); assertEquals( truckLVN746XDId, findTruckIdFromIndex( session, "table" ) ); tx.commit(); session.close(); // now unload the truck "LVN 746 XD" because his driver, Mark Smith, arrived at his destination. truckLVN746XD.setItems( null ); // let's update session = Search.getFullTextSession( openSession() ); tx = session.beginTransaction(); session.update( driverSmith ); // if the Hibernate-Search release is 3.4.0.CR2, it throws NullPointerException described in HSEARCH-734 during // commit phase tx.commit(); session.close(); // let's assert that indexes got updated correctly session = Search.getFullTextSession( openSession() ); tx = session.beginTransaction(); assertNull( findTruckIdFromIndex( session, "table" ) ); tx.commit(); session.close(); // Now let's clean up everything session = Search.getFullTextSession( openSession() ); tx = session.beginTransaction(); session.delete( driverSmith ); session.delete( driverDoe ); tx.commit(); session.close(); } private Long findTruckIdFromIndex(FullTextSession session, String itemDescription) { FullTextQuery q = session.createFullTextQuery( new TermQuery( new Term( "truck.items.description", itemDescription ) ), Driver.class ); q.setProjection( "truck.id" ); @SuppressWarnings("unchecked") List<Object[]> results = q.list(); if ( results.isEmpty() ) { return null; } return (Long) results.get( 0 )[0]; } @Override public Class<?>[] getAnnotatedClasses() { return new Class[] { Driver.class, Truck.class, Item.class }; } @Entity(name = "Driver") @Indexed public static class Driver { public Driver(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public Driver() { } @Id @GeneratedValue @DocumentId public Long getId() { return id; } public void setId(Long id) { this.id = id; } private Long id; @Field public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } private String firstName; @Field public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } private String lastName; @IndexedEmbedded(includeEmbeddedObjectId = true) @OneToOne(cascade = CascadeType.ALL) public Truck getTruck() { return truck; } public void setTruck(Truck truck) { this.truck = truck; } private Truck truck; } @Entity(name = "Truck") @Indexed public static class Truck { public Truck(String numberPlate) { super(); this.numberPlate = numberPlate; } public Truck() { } @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } private Long id; @Field public String getNumberPlate() { return numberPlate; } public void setNumberPlate(String numberPlate) { this.numberPlate = numberPlate; } private String numberPlate; @IndexedEmbedded @OneToMany(cascade = CascadeType.ALL) public Set<Item> getItems() { return items; } public void setItems(Set<Item> items) { this.items = items; } private Set<Item> items; } @Entity(name = "Item") @Indexed public static class Item { public Item(String description, Integer quantity) { super(); this.description = description; this.quantity = quantity; } public Item() { } @Id @GeneratedValue @DocumentId public Long getId() { return id; } public void setId(Long id) { this.id = id; } private Long id; @Field public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } private String description; @Field public Integer getQuantity() { return quantity; } public void setQuantity(Integer quantity) { this.quantity = quantity; } private Integer quantity; } }