[hibernate-commits] Hibernate SVN: r11260 - in branches/Branch_3_2/HibernateExt/search/src: java/org/hibernate/search/engine and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Mar 7 18:02:51 EST 2007


Author: epbernard
Date: 2007-03-07 18:02:51 -0500 (Wed, 07 Mar 2007)
New Revision: 11260

Added:
   branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/annotations/IndexedEmbedded.java
   branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/
   branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Address.java
   branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java
   branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Owner.java
   branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Tower.java
Modified:
   branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentBuilder.java
Log:
HSEARCH-27

Added: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/annotations/IndexedEmbedded.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/annotations/IndexedEmbedded.java	                        (rev 0)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/annotations/IndexedEmbedded.java	2007-03-07 23:02:51 UTC (rev 11260)
@@ -0,0 +1,31 @@
+//$Id: $
+package org.hibernate.search.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Documented;
+
+ at Retention( RetentionPolicy.RUNTIME )
+ at Target( { ElementType.FIELD, ElementType.METHOD } )
+ at Documented
+/**
+ * Specifies that an association (@*ToOne or @Embedded) is to be indexed
+ * in the root entity index
+ * It allows queries involving associated objects restrictions
+ */
+public @interface IndexedEmbedded {
+	/**
+	 * Field name prefix
+	 * Default to 'propertyname.'
+	 */
+	String prefix() default ".";
+
+	/**
+	 * Stop indexing embedded elements when depth is reached
+	 * depth=1 means the associated element is index, but not its embedded elements
+	 * Default: infinite (an exception will be raised in case of class circular reference when infinite is chosen)
+	 */
+	int depth() default Integer.MAX_VALUE;
+}

Modified: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentBuilder.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentBuilder.java	2007-03-07 22:55:12 UTC (rev 11259)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentBuilder.java	2007-03-07 23:02:51 UTC (rev 11260)
@@ -8,11 +8,16 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.HashMap;
 
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.index.Term;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.hibernate.annotations.common.reflection.ReflectionManager;
 import org.hibernate.annotations.common.reflection.XAnnotatedElement;
 import org.hibernate.annotations.common.reflection.XClass;
@@ -28,12 +33,14 @@
 import org.hibernate.search.annotations.Store;
 import org.hibernate.search.annotations.Text;
 import org.hibernate.search.annotations.Unstored;
+import org.hibernate.search.annotations.IndexedEmbedded;
 import org.hibernate.search.bridge.BridgeFactory;
 import org.hibernate.search.bridge.FieldBridge;
 import org.hibernate.search.bridge.TwoWayFieldBridge;
 import org.hibernate.search.store.DirectoryProvider;
 import org.hibernate.search.util.BinderHelper;
 import org.hibernate.util.ReflectHelper;
+import org.hibernate.Hibernate;
 
 /**
  * Set up and provide a manager for indexes classes
@@ -44,21 +51,9 @@
  * @author Richard Hallier
  */
 public class DocumentBuilder<T> {
-	private final List<XMember> keywordGetters = new ArrayList<XMember>();
-	private final List<String> keywordNames = new ArrayList<String>();
-	private final List<FieldBridge> keywordBridges = new ArrayList<FieldBridge>();
-	private final List<XMember> unstoredGetters = new ArrayList<XMember>();
-	private final List<String> unstoredNames = new ArrayList<String>();
-	private final List<FieldBridge> unstoredBridges = new ArrayList<FieldBridge>();
-	private final List<XMember> textGetters = new ArrayList<XMember>();
-	private final List<String> textNames = new ArrayList<String>();
-	private final List<FieldBridge> textBridges = new ArrayList<FieldBridge>();
-	private final List<String> fieldNames = new ArrayList<String>();
-	private final List<XMember> fieldGetters = new ArrayList<XMember>();
-	private final List<FieldBridge> fieldBridges = new ArrayList<FieldBridge>();
-	private final List<Field.Store> fieldStore = new ArrayList<Field.Store>();
-	private final List<Field.Index> fieldIndex = new ArrayList<Field.Index>();
+	private static final Log log = LogFactory.getLog( DocumentBuilder.class );
 
+	private final PropertiesMetadata rootPropertiesMetadata = new PropertiesMetadata();
 	private final XClass beanClass;
 	private final DirectoryProvider directoryProvider;
 	private String idKeywordName;
@@ -68,6 +63,8 @@
 	private TwoWayFieldBridge idBridge;
 	private Set<Class> mappedSubclasses = new HashSet<Class>();
 	private ReflectionManager reflectionManager;
+	private int level = 0;
+	private int maxLevel = Integer.MAX_VALUE;
 
 
 	public DocumentBuilder(XClass clazz, Analyzer analyzer, DirectoryProvider directory,
@@ -78,31 +75,41 @@
 		//FIXME get rid of it when boost is stored?
 		this.reflectionManager = reflectionManager;
 
-		if ( clazz == null ) throw new AssertionFailure( "Unable to build a DocumentBuilder with a null class" );
+		if ( clazz == null ) throw new AssertionFailure( "Unable to build a DocumemntBuilder with a null class" );
 
-		for ( XClass currClass = beanClass; currClass != null; currClass = currClass.getSuperclass() ) {
+		rootPropertiesMetadata.boost = getBoost( clazz );
+		Set<XClass> processedClasses = new HashSet<XClass>();
+		processedClasses.add( clazz );
+		initializeMembers(clazz, rootPropertiesMetadata, true, "", processedClasses );
+		//processedClasses.remove( clazz ); for the sake of completness
+
+		if ( idKeywordName == null ) {
+			throw new SearchException( "No document id for: " + clazz.getName() );
+		}
+	}
+
+	private void initializeMembers(XClass clazz, PropertiesMetadata propertiesMetadata, boolean isRoot, String prefix,
+								   Set<XClass> processedClasses) {
+		for ( XClass currClass = clazz; currClass != null; currClass = currClass.getSuperclass() ) {
 			//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 ) {
-				initializeMember( method );
+				initializeMember( method, propertiesMetadata, isRoot, prefix, processedClasses );
 			}
 
 			List<XProperty> fields = currClass.getDeclaredProperties( XClass.ACCESS_FIELD );
 			for ( XProperty field : fields ) {
-				initializeMember( field );
+				initializeMember( field, propertiesMetadata, isRoot, prefix, processedClasses );
 			}
 		}
-
-		if ( idKeywordName == null ) {
-			throw new SearchException( "No document id for: " + clazz.getName() );
-		}
 	}
 
-	private void initializeMember(XProperty member) {
+	private void initializeMember(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot,
+								  String prefix, Set<XClass> processedClasses) {
 		Keyword keywordAnn = member.getAnnotation( Keyword.class );
 		if ( keywordAnn != null ) {
-			String name = BinderHelper.getAttributeName( member, keywordAnn.name() );
-			if ( keywordAnn.id() ) {
+			String name = prefix + BinderHelper.getAttributeName( member, keywordAnn.name() );
+			if ( isRoot && keywordAnn.id() ) {
 				idKeywordName = name;
 				idBoost = getBoost( member );
 				FieldBridge fieldBridge = BridgeFactory.guessType( member );
@@ -116,35 +123,35 @@
 			}
 			else {
 				setAccessible( member );
-				keywordGetters.add( member );
-				keywordNames.add( name );
-				keywordBridges.add( BridgeFactory.guessType( member ) );
+				propertiesMetadata.keywordGetters.add( member );
+				propertiesMetadata.keywordNames.add( name );
+				propertiesMetadata.keywordBridges.add( BridgeFactory.guessType( member ) );
 			}
 		}
 
 		Unstored unstoredAnn = member.getAnnotation( Unstored.class );
 		if ( unstoredAnn != null ) {
 			setAccessible( member );
-			unstoredGetters.add( member );
-			unstoredNames.add( BinderHelper.getAttributeName( member, unstoredAnn.name() ) );
-			unstoredBridges.add( BridgeFactory.guessType( member ) );
+			propertiesMetadata.unstoredGetters.add( member );
+			propertiesMetadata.unstoredNames.add( prefix + BinderHelper.getAttributeName( member, unstoredAnn.name() ) );
+			propertiesMetadata.unstoredBridges.add( BridgeFactory.guessType( member ) );
 		}
 
 		Text textAnn = member.getAnnotation( Text.class );
 		if ( textAnn != null ) {
 			setAccessible( member );
-			textGetters.add( member );
-			textNames.add( BinderHelper.getAttributeName( member, textAnn.name() ) );
-			textBridges.add( BridgeFactory.guessType( member ) );
+			propertiesMetadata.textGetters.add( member );
+			propertiesMetadata.textNames.add( prefix + BinderHelper.getAttributeName( member, textAnn.name() ) );
+			propertiesMetadata.textBridges.add( BridgeFactory.guessType( member ) );
 		}
 
 		DocumentId documentIdAnn = member.getAnnotation( DocumentId.class );
-		if ( documentIdAnn != null ) {
+		if ( isRoot && documentIdAnn != null ) {
 			if ( idKeywordName != null ) {
 				throw new AssertionFailure( "Two document id assigned: "
 						+ idKeywordName + " and " + BinderHelper.getAttributeName( member, documentIdAnn.name() ) );
 			}
-			idKeywordName = BinderHelper.getAttributeName( member, documentIdAnn.name() );
+			idKeywordName = prefix + BinderHelper.getAttributeName( member, documentIdAnn.name() );
 			FieldBridge fieldBridge = BridgeFactory.guessType( member );
 			if ( fieldBridge instanceof TwoWayFieldBridge ) {
 				idBridge = (TwoWayFieldBridge) fieldBridge;
@@ -160,14 +167,63 @@
 				member.getAnnotation( org.hibernate.search.annotations.Field.class );
 		if ( fieldAnn != null ) {
 			setAccessible( member );
-			fieldGetters.add( member );
-			fieldNames.add( BinderHelper.getAttributeName( member, fieldAnn.name() ) );
-			fieldStore.add( getStore( fieldAnn.store() ) );
-			fieldIndex.add( getIndex( fieldAnn.index() ) );
-			fieldBridges.add( BridgeFactory.guessType( member ) );
+			propertiesMetadata.fieldGetters.add( member );
+			propertiesMetadata.fieldNames.add( prefix + BinderHelper.getAttributeName( member, fieldAnn.name() ) );
+			propertiesMetadata.fieldStore.add( getStore( fieldAnn.store() ) );
+			propertiesMetadata.fieldIndex.add( getIndex( fieldAnn.index() ) );
+			propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( member ) );
 		}
+
+		IndexedEmbedded embeddedAnn = member.getAnnotation( IndexedEmbedded.class );
+		if ( embeddedAnn != null ) {
+			int oldMaxLevel = maxLevel;
+			maxLevel = embeddedAnn.depth() + level > maxLevel ? maxLevel : embeddedAnn.depth() + level;
+			level++;
+
+			if ( maxLevel == Integer.MAX_VALUE //infinite
+					&& processedClasses.contains( member.getClassOrElementClass() ) ) {
+				throw new SearchException(
+						"Circular reference. Duplicate use of "
+						+ member.getClassOrElementClass().getName()
+						+ " in root entity " + beanClass.getName()
+						+ "#" + buildEmbeddedPrefix( prefix, embeddedAnn, member )
+				);
+			}
+			if (level <= maxLevel) {
+				processedClasses.add( member.getClassOrElementClass() ); //push
+
+				setAccessible( member );
+				propertiesMetadata.embeddedGetters.add( member );
+				PropertiesMetadata metadata = new PropertiesMetadata();
+				propertiesMetadata.embeddedPropertiesMetadata.add(metadata);
+				metadata.boost = getBoost( member );
+				String localPrefix = buildEmbeddedPrefix( prefix, embeddedAnn, member );
+				initializeMembers( member.getClassOrElementClass(), metadata, false, localPrefix, processedClasses);
+
+				processedClasses.remove( member.getClassOrElementClass() ); //pop
+			}
+			else if ( log.isTraceEnabled() ) {
+				String localPrefix = buildEmbeddedPrefix( prefix, embeddedAnn, member );
+				log.trace( "depth reached, ignoring " + localPrefix );
+			}
+
+			level--;
+			maxLevel = oldMaxLevel; //set back the the old max level
+		}
 	}
 
+	private String buildEmbeddedPrefix(String prefix, IndexedEmbedded embeddedAnn, XProperty member) {
+		String localPrefix = prefix;
+		if ( ".".equals( embeddedAnn.prefix() ) ) {
+			//default to property name
+			localPrefix += member.getName() + '.';
+		}
+		else {
+			localPrefix += embeddedAnn.prefix();
+		}
+		return localPrefix;
+	}
+
 	private Field.Store getStore(Store store) {
 		switch (store) {
 			case NO:
@@ -204,7 +260,7 @@
 				null;
 	}
 
-	private Object getMemberValue(T bean, XMember getter) {
+	private Object getMemberValue(Object bean, XMember getter) {
 		Object value;
 		try {
 			value = getter.invoke( bean );
@@ -218,9 +274,8 @@
 	public Document getDocument(T instance, Serializable id) {
 		Document doc = new Document();
 		XClass instanceClass = reflectionManager.toXClass( instance.getClass() );
-		Float boost = getBoost( instanceClass );
-		if ( boost != null ) {
-			doc.setBoost( boost );
+		if ( rootPropertiesMetadata.boost != null ) {
+			doc.setBoost( rootPropertiesMetadata.boost );
 		}
 		{
 			Field classField =
@@ -228,39 +283,52 @@
 			doc.add( classField );
 			idBridge.set( idKeywordName, id, doc, Field.Store.YES, Field.Index.UN_TOKENIZED, idBoost );
 		}
-		for ( int i = 0; i < keywordNames.size(); i++ ) {
-			XMember member = keywordGetters.get( i );
+		buildDocumentFields( instance, doc, rootPropertiesMetadata );
+		return doc;
+	}
+
+	private void buildDocumentFields(Object instance, Document doc, PropertiesMetadata propertiesMetadata) {
+		if (instance == null) return;
+
+		for ( int i = 0; i < propertiesMetadata.keywordNames.size(); i++ ) {
+			XMember member = propertiesMetadata.keywordGetters.get( i );
 			Object value = getMemberValue( instance, member );
-			keywordBridges.get( i ).set(
-					keywordNames.get( i ), value, doc, Field.Store.YES,
+			propertiesMetadata.keywordBridges.get( i ).set(
+					propertiesMetadata.keywordNames.get( i ), value, doc, Field.Store.YES,
 					Field.Index.UN_TOKENIZED, getBoost( member )
 			);
 		}
-		for ( int i = 0; i < textNames.size(); i++ ) {
-			XMember member = textGetters.get( i );
+		for ( int i = 0; i < propertiesMetadata.textNames.size(); i++ ) {
+			XMember member = propertiesMetadata.textGetters.get( i );
 			Object value = getMemberValue( instance, member );
-			textBridges.get( i ).set(
-					textNames.get( i ), value, doc, Field.Store.YES,
+			propertiesMetadata.textBridges.get( i ).set(
+					propertiesMetadata.textNames.get( i ), value, doc, Field.Store.YES,
 					Field.Index.TOKENIZED, getBoost( member )
 			);
 		}
-		for ( int i = 0; i < unstoredNames.size(); i++ ) {
-			XMember member = unstoredGetters.get( i );
+		for ( int i = 0; i < propertiesMetadata.unstoredNames.size(); i++ ) {
+			XMember member = propertiesMetadata.unstoredGetters.get( i );
 			Object value = getMemberValue( instance, member );
-			unstoredBridges.get( i ).set(
-					unstoredNames.get( i ), value, doc, Field.Store.NO,
+			propertiesMetadata.unstoredBridges.get( i ).set(
+					propertiesMetadata.unstoredNames.get( i ), value, doc, Field.Store.NO,
 					Field.Index.TOKENIZED, getBoost( member )
 			);
 		}
-		for ( int i = 0; i < fieldNames.size(); i++ ) {
-			XMember member = fieldGetters.get( i );
+		for ( int i = 0; i < propertiesMetadata.fieldNames.size(); i++ ) {
+			XMember member = propertiesMetadata.fieldGetters.get( i );
 			Object value = getMemberValue( instance, member );
-			fieldBridges.get( i ).set(
-					fieldNames.get( i ), value, doc, fieldStore.get( i ),
-					fieldIndex.get( i ), getBoost( member )
+			propertiesMetadata.fieldBridges.get( i ).set(
+					propertiesMetadata.fieldNames.get( i ), value, doc, propertiesMetadata.fieldStore.get( i ),
+					propertiesMetadata.fieldIndex.get( i ), getBoost( member )
 			);
 		}
-		return doc;
+		for ( int i = 0; i < propertiesMetadata.embeddedGetters.size(); i++ ) {
+			XMember member = propertiesMetadata.embeddedGetters.get( i );
+			Object value = getMemberValue( instance, member );
+			//if ( ! Hibernate.isInitialized( value ) ) continue; //this sounds like a bad idea 
+			//TODO handle boost at embedded level: already stored in propertiesMedatada.boost
+			buildDocumentFields( value, doc, propertiesMetadata.embeddedPropertiesMetadata.get( i ) );
+		}
 	}
 
 	public Term getTerm(Serializable id) {
@@ -320,4 +388,24 @@
 	public Set<Class> getMappedSubclasses() {
 		return mappedSubclasses;
 	}
+
+	private static class PropertiesMetadata {
+		public Float boost = null;
+		public final List<XMember> keywordGetters = new ArrayList<XMember>();
+		public final List<String> keywordNames = new ArrayList<String>();
+		public final List<FieldBridge> keywordBridges = new ArrayList<FieldBridge>();
+		public final List<XMember> unstoredGetters = new ArrayList<XMember>();
+		public final List<String> unstoredNames = new ArrayList<String>();
+		public final List<FieldBridge> unstoredBridges = new ArrayList<FieldBridge>();
+		public final List<XMember> textGetters = new ArrayList<XMember>();
+		public final List<String> textNames = new ArrayList<String>();
+		public final List<FieldBridge> textBridges = new ArrayList<FieldBridge>();
+		public final List<String> fieldNames = new ArrayList<String>();
+		public final List<XMember> fieldGetters = new ArrayList<XMember>();
+		public final List<FieldBridge> fieldBridges = new ArrayList<FieldBridge>();
+		public final List<Field.Store> fieldStore = new ArrayList<Field.Store>();
+		public final List<Field.Index> fieldIndex = new ArrayList<Field.Index>();
+		public final List<XMember> embeddedGetters = new ArrayList<XMember>();
+		public final List<PropertiesMetadata> embeddedPropertiesMetadata = new ArrayList<PropertiesMetadata>();
+	}
 }

Added: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Address.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Address.java	                        (rev 0)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Address.java	2007-03-07 23:02:51 UTC (rev 11260)
@@ -0,0 +1,69 @@
+//$Id: $
+package org.hibernate.search.test.embedded;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+import javax.persistence.OneToOne;
+
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+import org.hibernate.search.annotations.IndexedEmbedded;
+
+/**
+ * @author Emmanuel Bernard
+ */
+
+ at Entity
+ at Indexed
+public class Address {
+	@Id
+	@GeneratedValue
+	@DocumentId
+	private Long id;
+
+	@Field(index= Index.TOKENIZED)
+	private String street;
+
+	@IndexedEmbedded(depth = 1, prefix = "ownedBy_")
+	private Owner ownedBy;
+
+	@OneToOne(mappedBy = "address")
+	private Tower tower;
+
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getStreet() {
+		return street;
+	}
+
+	public void setStreet(String street) {
+		this.street = street;
+	}
+
+	public Owner getOwnedBy() {
+		return ownedBy;
+	}
+
+	public void setOwnedBy(Owner ownedBy) {
+		this.ownedBy = ownedBy;
+	}
+
+
+	public Tower getTower() {
+		return tower;
+	}
+
+	public void setTower(Tower tower) {
+		this.tower = tower;
+	}
+}

Added: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java	                        (rev 0)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java	2007-03-07 23:02:51 UTC (rev 11260)
@@ -0,0 +1,63 @@
+//$Id: $
+package org.hibernate.search.test.embedded;
+
+import java.util.List;
+
+import org.hibernate.search.test.SearchTestCase;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.search.Query;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class EmbeddedTest extends SearchTestCase {
+
+	public void testEmbeddedIndexing() throws Exception {
+		Tower tower = new Tower();
+		tower.setName( "JBoss tower" );
+		Address a = new Address();
+		a.setStreet( "Tower place");
+		a.setTower( tower );
+		tower.setAddress( a );
+		Owner o = new Owner();
+		o.setName( "Atlanta Renting corp" );
+		a.setOwnedBy( o );
+		o.setAddress( a );
+
+		Session s = openSession( );
+		Transaction tx = s.beginTransaction();
+		s.persist( tower );
+		tx.commit();
+
+		s.clear();
+		
+
+		FullTextSession session = Search.createFullTextSession(s);
+        QueryParser parser = new QueryParser("id", new StandardAnalyzer() );
+        Query query;
+        List result;
+
+        query = parser.parse("address.street:place");
+		result = session.createFullTextQuery(query).list();
+        assertEquals( "unable to find property in embedded", 1, result.size() );
+
+		query = parser.parse("address.ownedBy_name:renting");
+		result = session.createFullTextQuery(query, Tower.class).list();
+		assertEquals( "unable to find property in embedded", 1, result.size() );
+
+		s.close();
+
+	}
+
+	protected Class[] getMappings() {
+		return new Class[] {
+				Tower.class,
+				Address.class
+		};
+	}
+}

Added: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Owner.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Owner.java	                        (rev 0)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Owner.java	2007-03-07 23:02:51 UTC (rev 11260)
@@ -0,0 +1,39 @@
+//$Id: $
+package org.hibernate.search.test.embedded;
+
+import javax.persistence.Embeddable;
+
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+import org.hibernate.search.annotations.IndexedEmbedded;
+import org.hibernate.annotations.Parent;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at Embeddable
+public class Owner {
+	@Field(index = Index.TOKENIZED)
+	private String name;
+
+	@Parent
+	@IndexedEmbedded //play the lunatic user
+	private Address address;
+
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(Address address) {
+		this.address = address;
+	}
+}

Added: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Tower.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Tower.java	                        (rev 0)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/embedded/Tower.java	2007-03-07 23:02:51 UTC (rev 11260)
@@ -0,0 +1,58 @@
+//$Id: $
+package org.hibernate.search.test.embedded;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.IndexedEmbedded;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at Entity
+ at Indexed
+public class Tower {
+	@Id
+	@GeneratedValue
+	@DocumentId
+	private Long id;
+
+	@Field( index = Index.TOKENIZED )
+	private String name;
+
+	@OneToOne( cascade = CascadeType.PERSIST )
+	@IndexedEmbedded
+	private Address address;
+
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(Address address) {
+		this.address = address;
+	}
+}




More information about the hibernate-commits mailing list