[hibernate-commits] Hibernate SVN: r14020 - in search/trunk: src/java/org/hibernate/search/annotations and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Fri Sep 21 12:34:06 EDT 2007


Author: epbernard
Date: 2007-09-21 12:34:06 -0400 (Fri, 21 Sep 2007)
New Revision: 14020

Added:
   search/trunk/src/java/org/hibernate/search/annotations/ClassBridges.java
   search/trunk/src/test/org/hibernate/search/test/bridge/CatDeptsFieldsClassBridge.java
   search/trunk/src/test/org/hibernate/search/test/bridge/Departments.java
   search/trunk/src/test/org/hibernate/search/test/bridge/EquipmentType.java
Modified:
   search/trunk/build.xml
   search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java
   search/trunk/src/test/org/hibernate/search/test/bridge/ClassBridgeTest.java
Log:
HSEARCH-118 @ClassBridges

Modified: search/trunk/build.xml
===================================================================
--- search/trunk/build.xml	2007-09-21 16:26:29 UTC (rev 14019)
+++ search/trunk/build.xml	2007-09-21 16:34:06 UTC (rev 14020)
@@ -17,7 +17,7 @@
 	<!-- Name of project and version, used to create filenames -->
 	<property name="Name" value="Hibernate Search"/>
 	<property name="name" value="hibernate-search"/>
-	<property name="version" value="3.0.0.CR1"/>
+	<property name="version" value="3.0.0.CR1.HSEARCH-116"/>
 	<property name="javadoc.packagenames" value="org.hibernate.search.*"/>
 	<property name="copy.test" value="true"/>
 	<property name="javac.source" value="1.5"/>

Added: search/trunk/src/java/org/hibernate/search/annotations/ClassBridges.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/annotations/ClassBridges.java	                        (rev 0)
+++ search/trunk/src/java/org/hibernate/search/annotations/ClassBridges.java	2007-09-21 16:34:06 UTC (rev 14020)
@@ -0,0 +1,22 @@
+package org.hibernate.search.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author John Griffin
+ */
+ at Retention( RetentionPolicy.RUNTIME )
+ at Target( ElementType.TYPE )
+ at Documented
+public @interface ClassBridges {
+	/**
+	 * An array of ClassBridge annotations each of
+	 * which is to be applied to the class containing
+	 * this annotation.
+	 */
+	ClassBridge[] value() default {};
+}
\ No newline at end of file

Modified: search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java	2007-09-21 16:26:29 UTC (rev 14019)
+++ search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java	2007-09-21 16:34:06 UTC (rev 14020)
@@ -34,6 +34,7 @@
 import org.hibernate.search.annotations.IndexedEmbedded;
 import org.hibernate.search.annotations.Store;
 import org.hibernate.search.annotations.ClassBridge;
+import org.hibernate.search.annotations.ClassBridges;
 import org.hibernate.search.backend.AddLuceneWork;
 import org.hibernate.search.backend.DeleteLuceneWork;
 import org.hibernate.search.backend.LuceneWork;
@@ -140,11 +141,21 @@
 			if ( analyzer != null ) {
 				propertiesMetadata.analyzer = analyzer;
 			}
+			// Check for any ClassBridges annotation.
+			ClassBridges classBridgesAnn = currClass.getAnnotation( ClassBridges.class);
+			if (classBridgesAnn != null) {
+				ClassBridge[] cbs = classBridgesAnn.value();
+				for (ClassBridge cb : cbs) {
+					bindClassAnnotation(prefix, propertiesMetadata, cb);
+				}
+ 			}
+
 			// Check for any ClassBridge style of annotations.
 			ClassBridge classBridgeAnn = currClass.getAnnotation(ClassBridge.class);
 			if (classBridgeAnn != null) {
 				bindClassAnnotation(prefix, propertiesMetadata, classBridgeAnn);
 			}
+
 			//rejecting non properties because the object is loaded from Hibernate, so indexing a non property does not make sense
 			List<XProperty> methods = currClass.getDeclaredProperties( XClass.ACCESS_PROPERTY );
 			for (XProperty method : methods) {

Added: search/trunk/src/test/org/hibernate/search/test/bridge/CatDeptsFieldsClassBridge.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/bridge/CatDeptsFieldsClassBridge.java	                        (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/bridge/CatDeptsFieldsClassBridge.java	2007-09-21 16:34:06 UTC (rev 14020)
@@ -0,0 +1,40 @@
+package org.hibernate.search.test.bridge;
+
+import java.util.Map;
+
+import org.hibernate.search.bridge.FieldBridge;
+import org.hibernate.search.bridge.ParameterizedBridge;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+
+/**
+ * @author John Griffin
+ */
+public class CatDeptsFieldsClassBridge implements FieldBridge, ParameterizedBridge {
+
+	private String sepChar;
+
+	public void setParameterValues(Map parameters) {
+		this.sepChar = (String) parameters.get( "sepChar" );
+	}
+
+	public void set(String name, Object value, Document document, Field.Store store, Field.Index index, Float boost) {
+		// In this particular class the name of the new field was passed
+		// from the name field of the ClassBridge Annotation. This is not
+		// a requirement. It just works that way in this instance. The
+		// actual name could be supplied by hard coding it below.
+		Departments dep = (Departments) value;
+		String fieldValue1 = dep.getBranch();
+		if ( fieldValue1 == null ) {
+			fieldValue1 = "";
+		}
+		String fieldValue2 = dep.getNetwork();
+		if ( fieldValue2 == null ) {
+			fieldValue2 = "";
+		}
+		String fieldValue = fieldValue1 + sepChar + fieldValue2;
+		Field field = new Field( name, fieldValue, store, index );
+		if ( boost != null ) field.setBoost( boost );
+		document.add( field );
+	}
+}

Modified: search/trunk/src/test/org/hibernate/search/test/bridge/ClassBridgeTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/bridge/ClassBridgeTest.java	2007-09-21 16:26:29 UTC (rev 14019)
+++ search/trunk/src/test/org/hibernate/search/test/bridge/ClassBridgeTest.java	2007-09-21 16:34:06 UTC (rev 14020)
@@ -1,22 +1,162 @@
 package org.hibernate.search.test.bridge;
 
 import java.util.List;
+import java.io.Serializable;
 
 import org.apache.lucene.analysis.SimpleAnalyzer;
 import org.apache.lucene.queryParser.QueryParser;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.document.Document;
 import org.hibernate.Transaction;
+import org.hibernate.ScrollableResults;
 import org.hibernate.cfg.Configuration;
 import org.hibernate.search.Environment;
 import org.hibernate.search.FullTextSession;
 import org.hibernate.search.Search;
+import org.hibernate.search.FullTextQuery;
 import org.hibernate.search.test.SearchTestCase;
+import org.hibernate.search.test.query.Employee;
 
 /**
  * @author John Griffin
  */
 public class ClassBridgeTest extends SearchTestCase {
 	/**
+	 * 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
+	 */
+	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.createFullTextSession( 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.
+		QueryParser parser = new QueryParser( "equipment", new SimpleAnalyzer() );
+
+		// Check the second ClassBridge annotation
+		Query query = parser.parse( "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 = parser.parse( "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.
+		parser = new QueryParser( "branchHead", new SimpleAnalyzer() );
+		query = parser.parse( "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.
+		parser = new QueryParser( "branchnetwork", new SimpleAnalyzer() );
+		query = parser.parse( "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
+	 */
+	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.createFullTextSession( 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.
+		QueryParser parser = new QueryParser( "equipment", new SimpleAnalyzer() );
+
+		// Check the second ClassBridge annotation
+		Query query = parser.parse( "equiptype:Cisco" );
+		org.hibernate.search.FullTextQuery hibQuery = session.createFullTextQuery( query, Departments.class );
+
+		hibQuery.setProjection( FullTextQuery.THIS, FullTextQuery.DOCUMENT );
+
+		ScrollableResults projections = hibQuery.scroll();
+		assertNotNull( projections );
+
+		projections.beforeFirst();
+		projections.next();
+		Object[] projection = projections.get();
+
+		assertTrue( "DOCUMENT incorrect", projection[0] instanceof Departments );
+		assertEquals( "id incorrect", 1, ((Departments)projection[0]).getId() );
+		assertTrue( "DOCUMENT incorrect", projection[1] instanceof Document );
+		assertEquals( "DOCUMENT size incorrect", 8, ( (Document) projection[1] ).getFields().size() );
+		assertNotNull( "equiptype is null", ( (Document) projection[1] ).getField("equiptype") );
+		assertEquals( "equiptype incorrect", "Cisco", ( (Document) projection[1] ).getField("equiptype" ).stringValue() );
+		assertNotNull( "branchnetwork is null", ( (Document) projection[1] ).getField("branchnetwork") );
+		assertEquals( "branchnetwork incorrect", "Salt Lake City 1A", ( (Document) projection[1] ).getField("branchnetwork" ).stringValue() );
+
+		projections.next();
+		projection = projections.get();
+
+		assertTrue( "DOCUMENT incorrect", projection[0] instanceof Departments );
+		assertEquals( "id incorrect", 4, ((Departments)projection[0]).getId() );
+		assertTrue( "DOCUMENT incorrect", projection[1] instanceof Document );
+		assertEquals( "DOCUMENT size incorrect", 8, ( (Document) projection[1] ).getFields().size() );
+		assertNotNull( "equiptype is null", ( (Document) projection[1] ).getField("equiptype") );
+		assertEquals( "equiptype incorrect", "Cisco", ( (Document) projection[1] ).getField("equiptype" ).stringValue() );
+		assertNotNull( "branchnetwork is null", ( (Document) projection[1] ).getField("branchnetwork") );
+		assertEquals( "branchnetwork incorrect", "St. George 1D", ( (Document) projection[1] ).getField("branchnetwork" ).stringValue() );
+
+		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();
+	}
+
+	/**
 	 * 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.
@@ -83,19 +223,16 @@
 	private Department getDept1() {
 		Department dept = new Department();
 
-//		dept.setId( 1000 );
 		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.setId( 1001 );
 		dept.setBranch( "Layton" );
 		dept.setBranchHead( "Terry Poperszky" );
 		dept.setMaxEmployees( 20 );
@@ -107,7 +244,6 @@
 	private Department getDept3() {
 		Department dept = new Department();
 
-//		dept.setId( 1002 );
 		dept.setBranch( "West Valley" );
 		dept.setBranchHead( "Pat Kelley" );
 		dept.setMaxEmployees( 15 );
@@ -116,9 +252,57 @@
 		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;
+	}
+
 	protected Class[] getMappings() {
 		return new Class[] {
-				Department.class
+				Department.class,
+				Departments.class
 		};
 	}
 

Added: search/trunk/src/test/org/hibernate/search/test/bridge/Departments.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/bridge/Departments.java	                        (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/bridge/Departments.java	2007-09-21 16:34:06 UTC (rev 14020)
@@ -0,0 +1,102 @@
+package org.hibernate.search.test.bridge;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.ClassBridge;
+import org.hibernate.search.annotations.Index;
+import org.hibernate.search.annotations.Store;
+import org.hibernate.search.annotations.Parameter;
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.ClassBridges;
+
+/**
+ * This is just a simple copy of the Department entity to allow
+ * separation of the tests for ClassBridge and ClassBridges.
+ *
+ * @author John Griffin
+ */
+ at Entity
+ at Indexed
+ at ClassBridges ( {
+	@ClassBridge(name="branchnetwork",
+				 index= Index.TOKENIZED,
+				 store= Store.YES,
+				 impl = CatDeptsFieldsClassBridge.class,
+				 params = @Parameter( name="sepChar", value=" " ) ),
+	@ClassBridge(name="equiptype",
+				 index= Index.TOKENIZED,
+				 store= Store.YES,
+				 impl = EquipmentType.class,
+				 params = {@Parameter( name="C", value="Cisco" ),
+						   @Parameter( name="D", value="D-Link" ),
+						   @Parameter( name="K", value="Kingston" ),
+						   @Parameter( name="3", value="3Com" )
+				 })
+})
+public class Departments {
+	private int id;
+	private String network;
+	private String manufacturer;
+	private String branchHead;
+	private String branch;
+	private Integer maxEmployees;
+
+	@Id
+	@GeneratedValue
+	@DocumentId
+	public int getId() {
+		return id;
+	}
+
+	public void setId(int id) {
+		this.id = id;
+	}
+
+	@Field(index=Index.TOKENIZED, store=Store.YES)
+	public String getBranchHead() {
+		return branchHead;
+	}
+
+	public void setBranchHead(String branchHead) {
+		this.branchHead = branchHead;
+	}
+
+	@Field(index=Index.TOKENIZED, store=Store.YES)
+	public String getNetwork() {
+		return network;
+	}
+
+	public void setNetwork(String network) {
+		this.network = network;
+	}
+
+	@Field(index=Index.TOKENIZED, store=Store.YES)
+	public String getBranch() {
+		return branch;
+	}
+
+	public void setBranch(String branch) {
+		this.branch = branch;
+	}
+
+	@Field(index=Index.UN_TOKENIZED, store=Store.YES)
+	public Integer getMaxEmployees() {
+		return maxEmployees;
+	}
+
+	public void setMaxEmployees(Integer maxEmployees) {
+		this.maxEmployees = maxEmployees;
+	}
+
+	public String getManufacturer() {
+		return manufacturer;
+	}
+
+	public void setManufacturer(String manufacturer) {
+		this.manufacturer = manufacturer;
+	}
+}

Added: search/trunk/src/test/org/hibernate/search/test/bridge/EquipmentType.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/bridge/EquipmentType.java	                        (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/bridge/EquipmentType.java	2007-09-21 16:34:06 UTC (rev 14020)
@@ -0,0 +1,40 @@
+package org.hibernate.search.test.bridge;
+
+import java.util.Map;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.hibernate.search.bridge.FieldBridge;
+import org.hibernate.search.bridge.ParameterizedBridge;
+
+/**
+ * @author John Griffin
+ */
+public class EquipmentType  implements FieldBridge, ParameterizedBridge {
+	private Map equips;
+
+	public void setParameterValues(Map parameters) {
+		// This map was defined by the parameters of the ClassBridge annotation.
+		this.equips = parameters;
+	}
+
+	public void set(String name, Object value, Document document, Field.Store store, Field.Index index, Float boost) {
+		// In this particular class the name of the new field was passed
+		// from the name field of the ClassBridge Annotation. This is not
+		// a requirement. It just works that way in this instance. The
+		// actual name could be supplied by hard coding it below.
+		Departments deps = (Departments) value;
+		Field field = null;
+		String fieldValue1 = deps.getManufacturer();
+
+		if ( fieldValue1 == null ) {
+			fieldValue1 = "";
+		}
+		else {
+			String fieldValue = (String)equips.get( fieldValue1);
+			field = new Field( name, fieldValue, store, index );
+			if ( boost != null ) field.setBoost( boost );
+		}
+		document.add( field );
+	}
+}




More information about the hibernate-commits mailing list