/* * 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.bridge; import java.util.List; import java.util.Map; import org.apache.lucene.analysis.core.SimpleAnalyzer; import org.apache.lucene.search.Query; import org.hibernate.ScrollableResults; import org.hibernate.Transaction; import org.hibernate.search.FullTextQuery; import org.hibernate.search.FullTextSession; import org.hibernate.search.Search; import org.hibernate.search.cfg.Environment; import org.hibernate.search.query.dsl.QueryBuilder; import org.hibernate.search.test.SearchTestBase; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; /** * @author John Griffin */ public class ClassBridgeTest extends SearchTestBase { /** * This tests that a field created by a user-supplied * EquipmentType class has been created and is a translation * from an identifier to a manufacturer name. * * @throws Exception */ @Test public void testClassBridges() throws Exception { org.hibernate.Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( getDepts1() ); s.persist( getDepts2() ); s.persist( getDepts3() ); s.persist( getDepts4() ); s.flush(); tx.commit(); tx = s.beginTransaction(); FullTextSession session = Search.getFullTextSession( s ); // The equipment field is the manufacturer field in the // Departments entity after being massaged by passing it // through the EquipmentType class. This field is in // the Lucene document but not in the Department entity itself. QueryBuilder queryBuilder = session.getSearchFactory().buildQueryBuilder().forEntity( Departments.class ).get(); // Check the second ClassBridge annotation Query query = createQuery(queryBuilder, "equiptype", "Cisco" ); org.hibernate.search.FullTextQuery hibQuery = session.createFullTextQuery( query, Departments.class ); List<Departments> result = hibQuery.list(); assertNotNull( result ); assertEquals( "incorrect number of results returned", 2, result.size() ); for ( Departments d : result ) { assertEquals( "incorrect manufacturer", "C", d.getManufacturer() ); } // No data cross-ups. query = createQuery(queryBuilder, "branchnetwork", "Kent Lewin" ); hibQuery = session.createFullTextQuery( query, Departments.class ); result = hibQuery.list(); assertNotNull( result ); assertTrue( "problem with field cross-ups", result.size() == 0 ); // Non-ClassBridge field. query = createQuery(queryBuilder, "branchHead", "Kent Lewin" ); hibQuery = session.createFullTextQuery( query, Departments.class ); result = hibQuery.list(); assertNotNull( result ); assertTrue( "incorrect entity returned, wrong branch head", result.size() == 1 ); assertEquals( "incorrect entity returned", "Kent Lewin", ( result.get( 0 ) ).getBranchHead() ); // Check other ClassBridge annotation. query = createQuery(queryBuilder, "branchnetwork", "st. george 1D" ); hibQuery = session.createFullTextQuery( query, Departments.class ); result = hibQuery.list(); assertNotNull( result ); assertEquals( "incorrect entity returned, wrong network", "1D", ( result.get( 0 ) ).getNetwork() ); assertEquals( "incorrect entity returned, wrong branch", "St. George", ( result.get( 0 ) ).getBranch() ); assertEquals( "incorrect number of results returned", 1, result.size() ); // cleanup for ( Object element : s.createQuery( "from " + Departments.class.getName() ).list() ) { s.delete( element ); } tx.commit(); s.close(); } /** * This is the same test as above with a projection query * to show the presence of the ClassBridge impl built fields * just in case you don't believe us. * * @throws Exception */ @Test public void testClassBridgesWithProjection() throws Exception { org.hibernate.Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( getDepts1() ); s.persist( getDepts2() ); s.persist( getDepts3() ); s.persist( getDepts4() ); s.flush(); tx.commit(); tx = s.beginTransaction(); FullTextSession session = Search.getFullTextSession( s ); // The equipment field is the manufacturer field in the // Departments entity after being massaged by passing it // through the EquipmentType class. This field is in // the Lucene document but not in the Department entity itself. QueryBuilder queryBuilder = session.getSearchFactory().buildQueryBuilder().forEntity( Departments.class ).get(); // Check the second ClassBridge annotation Query query = createQuery(queryBuilder, "equiptype", "Cisco" ); org.hibernate.search.FullTextQuery hibQuery = session.createFullTextQuery( query, Departments.class ); hibQuery.setProjection( FullTextQuery.THIS, "equiptype", "branchnetwork" ); hibQuery.setSort( queryBuilder.sort().byField( "idSort" ).createSort() ); ScrollableResults projections = hibQuery.scroll(); assertNotNull( projections ); projections.beforeFirst(); projections.next(); Object[] projection = projections.get(); assertTrue( "Result type incorrect", projection[0] instanceof Departments ); assertEquals( "Result id incorrect", 1, ( (Departments) projection[0] ).getId() ); assertEquals( "equiptype incorrect", "Cisco", projection[1] ); assertEquals( "branchnetwork incorrect", "Salt Lake City 1A", projection[2] ); projections.next(); projection = projections.get(); assertTrue( "Result type incorrect", projection[0] instanceof Departments ); assertEquals( "Result id incorrect", 4, ( (Departments) projection[0] ).getId() ); assertEquals( "equiptype incorrect", "Cisco", projection[1] ); assertEquals( "branchnetwork incorrect", "St. George 1D", projection[2] ); assertTrue( "incorrect result count returned", projections.isLast() ); //cleanup for ( Object element : s.createQuery( "from " + Departments.class.getName() ).list() ) { s.delete( element ); } tx.commit(); s.close(); } private Query createQuery(QueryBuilder queryBuilder, String fieldName, String term) { return queryBuilder .keyword() .onField( fieldName ) .ignoreFieldBridge() .matching( term ) .createQuery(); } /** * This test checks for two fields being concatentated by the user-supplied * CatFieldsClassBridge class which is specified as the implementation class * in the ClassBridge annotation of the Department class. * * @throws Exception */ @Test public void testClassBridge() throws Exception { org.hibernate.Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( getDept1() ); s.persist( getDept2() ); s.persist( getDept3() ); s.flush(); tx.commit(); tx = s.beginTransaction(); FullTextSession session = Search.getFullTextSession( s ); // The branchnetwork field is the concatenation of both // the branch field and the network field of the Department // class. This is in the Lucene document but not in the // Department entity itself. QueryBuilder queryBuilder = session.getSearchFactory().buildQueryBuilder().forEntity( Department.class ).get(); Query query = createQuery( queryBuilder, "branchnetwork", "layton 2B" ); org.hibernate.search.FullTextQuery hibQuery = session.createFullTextQuery( query, Department.class ); List result = hibQuery.list(); assertNotNull( result ); assertEquals( "incorrect entity returned, wrong network", "2B", ( (Department) result.get( 0 ) ).getNetwork() ); assertEquals( "incorrect entity returned, wrong branch", "Layton", ( (Department) result.get( 0 ) ).getBranch() ); assertEquals( "incorrect number of results returned", 1, result.size() ); // Partial match. query = createQuery( queryBuilder, "branchnetwork", "3c" ); hibQuery = session.createFullTextQuery( query, Department.class ); result = hibQuery.list(); assertNotNull( result ); assertEquals( "incorrect entity returned, wrong network", "3C", ( (Department) result.get( 0 ) ).getNetwork() ); assertEquals( "incorrect entity returned, wrong branch", "West Valley", ( (Department) result.get( 0 ) ).getBranch() ); assertEquals( "incorrect number of results returned", 1, result.size() ); // No data cross-ups . query = createQuery( queryBuilder, "branchnetwork", "Kent Lewin" ); hibQuery = session.createFullTextQuery( query, Department.class ); result = hibQuery.list(); assertNotNull( result ); assertTrue( "problem with field cross-ups", result.size() == 0 ); // Non-ClassBridge field. query = createQuery( queryBuilder, "branchHead", "Kent Lewin" ); hibQuery = session.createFullTextQuery( query, Department.class ); result = hibQuery.list(); assertNotNull( result ); assertTrue( "incorrect entity returned, wrong branch head", result.size() == 1 ); assertEquals( "incorrect entity returned", "Kent Lewin", ( (Department) result.get( 0 ) ).getBranchHead() ); //cleanup for ( Object element : s.createQuery( "from " + Department.class.getName() ).list() ) { s.delete( element ); } tx.commit(); s.close(); } private Department getDept1() { Department dept = new Department(); dept.setBranch( "Salt Lake City" ); dept.setBranchHead( "Kent Lewin" ); dept.setMaxEmployees( 100 ); dept.setNetwork( "1A" ); return dept; } private Department getDept2() { Department dept = new Department(); dept.setBranch( "Layton" ); dept.setBranchHead( "Terry Poperszky" ); dept.setMaxEmployees( 20 ); dept.setNetwork( "2B" ); return dept; } private Department getDept3() { Department dept = new Department(); dept.setBranch( "West Valley" ); dept.setBranchHead( "Pat Kelley" ); dept.setMaxEmployees( 15 ); dept.setNetwork( "3C" ); return dept; } private Departments getDepts1() { Departments depts = new Departments(); depts.setBranch( "Salt Lake City" ); depts.setBranchHead( "Kent Lewin" ); depts.setMaxEmployees( 100 ); depts.setNetwork( "1A" ); depts.setManufacturer( "C" ); return depts; } private Departments getDepts2() { Departments depts = new Departments(); depts.setBranch( "Layton" ); depts.setBranchHead( "Terry Poperszky" ); depts.setMaxEmployees( 20 ); depts.setNetwork( "2B" ); depts.setManufacturer( "3" ); return depts; } private Departments getDepts3() { Departments depts = new Departments(); depts.setBranch( "West Valley" ); depts.setBranchHead( "Pat Kelley" ); depts.setMaxEmployees( 15 ); depts.setNetwork( "3C" ); depts.setManufacturer( "D" ); return depts; } private Departments getDepts4() { Departments depts = new Departments(); depts.setBranch( "St. George" ); depts.setBranchHead( "Spencer Stajskal" ); depts.setMaxEmployees( 10 ); depts.setNetwork( "1D" ); depts.setManufacturer( "C" ); return depts; } @Override public Class<?>[] getAnnotatedClasses() { return new Class[] { Department.class, Departments.class }; } @Override public void configure(Map<String,Object> cfg) { cfg.put( Environment.ANALYZER_CLASS, SimpleAnalyzer.class.getName() ); } }