[hibernate-commits] Hibernate SVN: r15592 - in search/trunk/src: java/org/hibernate/search/impl and 4 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Nov 19 09:17:48 EST 2008


Author: hardy.ferentschik
Date: 2008-11-19 09:17:48 -0500 (Wed, 19 Nov 2008)
New Revision: 15592

Added:
   search/trunk/src/test/org/hibernate/search/test/inheritance/Fish.java
Modified:
   search/trunk/src/java/org/hibernate/search/engine/MultiClassesQueryLoader.java
   search/trunk/src/java/org/hibernate/search/engine/ProjectionLoader.java
   search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java
   search/trunk/src/java/org/hibernate/search/impl/FullTextSessionImpl.java
   search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
   search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java
   search/trunk/src/test/org/hibernate/search/test/SearchTestCase.java
   search/trunk/src/test/org/hibernate/search/test/filter/FilterTest.java
   search/trunk/src/test/org/hibernate/search/test/inheritance/Animal.java
   search/trunk/src/test/org/hibernate/search/test/inheritance/Being.java
   search/trunk/src/test/org/hibernate/search/test/inheritance/InheritanceTest.java
   search/trunk/src/test/org/hibernate/search/test/inheritance/Mammal.java
Log:
HSEARCH-160 HSEARCH-265
- Added new data structure in order to support polymorphic queries
- Added warning for abstract classes annotated with @Indexed (no DocumentBuilder will be created)

Modified: search/trunk/src/java/org/hibernate/search/engine/MultiClassesQueryLoader.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/MultiClassesQueryLoader.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/java/org/hibernate/search/engine/MultiClassesQueryLoader.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -1,16 +1,15 @@
 // $Id$
 package org.hibernate.search.engine;
 
-import java.util.List;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.HashMap;
-import java.util.Arrays;
 
-import org.hibernate.Session;
 import org.hibernate.Criteria;
+import org.hibernate.Session;
 import org.hibernate.annotations.common.AssertionFailure;
 
 /**
@@ -30,13 +29,12 @@
 		this.objectLoader.init( session, searchFactoryImplementor );
 	}
 
-	public void setEntityTypes(Class[] entityTypes) {
-		List<Class> safeEntityTypes;
+	public void setEntityTypes(Set<Class<?>> entityTypes) {
+		List<Class<?>> safeEntityTypes = new ArrayList<Class<?>>();
 		//TODO should we go find the root entity for a given class rather than just checking for it's root status?
 		//     root entity could lead to quite inefficient queries in Hibernate when using table per class
-		if ( entityTypes.length == 0 ) {
+		if ( entityTypes.size() == 0 ) {
 			//support all classes
-			safeEntityTypes = new ArrayList<Class>();
 			for( Map.Entry<Class<?>, DocumentBuilder<?>> entry : searchFactoryImplementor.getDocumentBuilders().entrySet() ) {
 				//get only root entities to limit queries
 				if ( entry.getValue().isRoot() ) {
@@ -45,7 +43,7 @@
 			}
 		}
 		else {
-			safeEntityTypes = Arrays.asList(entityTypes);
+			safeEntityTypes.addAll(entityTypes);
 		}
 		entityMatadata = new ArrayList<RootEntityMetadata>( safeEntityTypes.size() );
 		for (Class clazz :  safeEntityTypes) {

Modified: search/trunk/src/java/org/hibernate/search/engine/ProjectionLoader.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/ProjectionLoader.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/java/org/hibernate/search/engine/ProjectionLoader.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -3,6 +3,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 import org.hibernate.Session;
 import org.hibernate.transform.ResultTransformer;
@@ -21,7 +22,7 @@
 	private Boolean projectThis;
 	private ResultTransformer transformer;
 	private String[] aliases;
-	private Class[] entityTypes;
+	private Set<Class<?>> entityTypes;
 
 	public void init(Session session, SearchFactoryImplementor searchFactoryImplementor) {
 		this.session = session;
@@ -34,7 +35,7 @@
 		this.aliases = aliases;
 	}
 
-	public void setEntityTypes(Class[] entityTypes) {
+	public void setEntityTypes(Set<Class<?>> entityTypes) {
 		this.entityTypes = entityTypes;
 	}
 

Modified: search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -58,5 +58,7 @@
 
 	void addDirectoryProvider(DirectoryProvider<?> provider);
 	
-	int getFilterCacheBitResultsSize();	
+	int getFilterCacheBitResultsSize();
+
+	Set<Class<?>> getIndexedTypesPolymorphic(Class<?>[] classes);
 }

Modified: search/trunk/src/java/org/hibernate/search/impl/FullTextSessionImpl.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/impl/FullTextSessionImpl.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/java/org/hibernate/search/impl/FullTextSessionImpl.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -109,30 +109,34 @@
 		// accessing the document builders is not strictly necessary but a small optimization plus let's make sure the
 		// client didn't mess something up.
 		SearchFactoryImplementor searchFactoryImplementor = getSearchFactoryImplementor();
-		DocumentBuilder builder = searchFactoryImplementor.getDocumentBuilder( entityType );
-		if ( builder == null ) {
-			String msg = "Entity to index is not an @Indexed entity: " + entityType.getName();
-			throw new IllegalArgumentException( msg );
-		}
+		Set<Class<?>> targetedClasses = searchFactoryImplementor.getIndexedTypesPolymorphic( new Class[] {entityType} );
 
-		Work<T> work;
-		if ( id == null ) {
-			// purge the main entity
-			work = new Work<T>( entityType, id, WorkType.PURGE_ALL );
-			searchFactoryImplementor.getWorker().performWork( work, transactionContext );
+		for ( Class clazz : targetedClasses ) {
+			DocumentBuilder builder = searchFactoryImplementor.getDocumentBuilder( clazz );
+			if ( builder == null ) {
+				String msg = "Entity to index is not an @Indexed entity: " + clazz.getName();
+				throw new IllegalArgumentException( msg );
+			}
 
-			// purge the subclasses
-			Set<Class<?>> subClasses = builder.getMappedSubclasses();
-			for ( Class clazz : subClasses ) {
-				@SuppressWarnings( "unchecked" )
-				Work subClassWork = new Work( clazz, id, WorkType.PURGE_ALL );
-				searchFactoryImplementor.getWorker().performWork( subClassWork, transactionContext );
+			Work<T> work;
+			if ( id == null ) {
+				// purge the main entity
+				work = new Work<T>( clazz, id, WorkType.PURGE_ALL );
+				searchFactoryImplementor.getWorker().performWork( work, transactionContext );
+
+				// purge the subclasses
+				Set<Class<?>> subClasses = builder.getMappedSubclasses();
+				for ( Class subClazz : subClasses ) {
+					@SuppressWarnings( "unchecked" )
+					Work subClassWork = new Work( subClazz, id, WorkType.PURGE_ALL );
+					searchFactoryImplementor.getWorker().performWork( subClassWork, transactionContext );
+				}
 			}
+			else {
+				work = new Work<T>( clazz, id, WorkType.PURGE );
+				searchFactoryImplementor.getWorker().performWork( work, transactionContext );
+			}
 		}
-		else {
-			work = new Work<T>( entityType, id, WorkType.PURGE );
-			searchFactoryImplementor.getWorker().performWork( work, transactionContext );
-		}
 	}
 
 	/**

Modified: search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -12,6 +12,7 @@
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.Arrays;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -75,8 +76,11 @@
 	private Map<String, Analyzer> analyzers;
 	private final AtomicBoolean stopped = new AtomicBoolean( false );
 	private final int cacheBitResultsSize;
+
+	private final PolymorphicIndexHierarchy indexHierarchy = new PolymorphicIndexHierarchy();
+
 	/*
-	 * used as a barrier (piggyback usage) between initialization and subsequent usage of searchFactory in different threads
+	 * Used as a barrier (piggyback usage) between initialization and subsequent usage of searchFactory in different threads
 	 * this is due to our use of the initialize pattern is a few areas
 	 * subsequent reads on volatiles should be very cheap on most platform especially since we don't write after init
 	 *
@@ -90,12 +94,13 @@
 	 * Each directory provider (index) can have its own performance settings.
 	 */
 	private Map<DirectoryProvider, LuceneIndexingParameters> dirProviderIndexingParams =
-		new HashMap<DirectoryProvider, LuceneIndexingParameters>();
+			new HashMap<DirectoryProvider, LuceneIndexingParameters>();
 	private final String indexingStrategy;
 
 
 	public BackendQueueProcessorFactory getBackendQueueProcessorFactory() {
-		if (barrier != 0) { } //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return backendQueueProcessorFactory;
 	}
 
@@ -113,56 +118,60 @@
 		initDocumentBuilders( cfg, reflectionManager );
 
 		Set<Class<?>> indexedClasses = documentBuilders.keySet();
-		for (DocumentBuilder builder : documentBuilders.values()) {
+		for ( DocumentBuilder builder : documentBuilders.values() ) {
 			builder.postInitialize( indexedClasses );
 		}
 		//not really necessary today
-		for (DocumentBuilder builder : containedInOnlyBuilders.values()) {
+		for ( DocumentBuilder builder : containedInOnlyBuilders.values() ) {
 			builder.postInitialize( indexedClasses );
 		}
 		this.worker = WorkerFactory.createWorker( cfg, this );
 		this.readerProvider = ReaderProviderFactory.createReaderProvider( cfg, this );
 		this.filterCachingStrategy = buildFilterCachingStrategy( cfg.getProperties() );
-		this.cacheBitResultsSize = ConfigurationParseHelper.getIntValue( cfg.getProperties(), Environment.CACHE_BIT_RESULT_SIZE, CachingWrapperFilter.DEFAULT_SIZE );
+		this.cacheBitResultsSize = ConfigurationParseHelper.getIntValue(
+				cfg.getProperties(), Environment.CACHE_BIT_RESULT_SIZE, CachingWrapperFilter.DEFAULT_SIZE
+		);
 		this.barrier = 1; //write barrier
 	}
 
 	private static String defineIndexingStrategy(SearchConfiguration cfg) {
 		String indexingStrategy = cfg.getProperties().getProperty( Environment.INDEXING_STRATEGY, "event" );
-		if ( ! ("event".equals( indexingStrategy ) || "manual".equals( indexingStrategy ) ) ) {
+		if ( !( "event".equals( indexingStrategy ) || "manual".equals( indexingStrategy ) ) ) {
 			throw new SearchException( Environment.INDEXING_STRATEGY + " unknown: " + indexingStrategy );
 		}
 		return indexingStrategy;
 	}
 
 	public String getIndexingStrategy() {
-		if (barrier != 0) { } //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return indexingStrategy;
 	}
 
 	public void close() {
-		if (barrier != 0) { } //read barrier
-		if ( stopped.compareAndSet( false, true) ) {
+		if ( barrier != 0 ) {
+		} //read barrier
+		if ( stopped.compareAndSet( false, true ) ) {
 			try {
 				worker.close();
 			}
-			catch (Exception e) {
+			catch ( Exception e ) {
 				log.error( "Worker raises an exception on close()", e );
 			}
 
 			try {
 				readerProvider.destroy();
 			}
-			catch (Exception e) {
+			catch ( Exception e ) {
 				log.error( "ReaderProvider raises an exception on destroy()", e );
 			}
 
 			//TODO move to DirectoryProviderFactory for cleaner
-			for (DirectoryProvider dp : getDirectoryProviders() ) {
+			for ( DirectoryProvider dp : getDirectoryProviders() ) {
 				try {
 					dp.stop();
 				}
-				catch (Exception e) {
+				catch ( Exception e ) {
 					log.error( "DirectoryProvider raises an exception on stop() ", e );
 				}
 			}
@@ -171,17 +180,18 @@
 
 	public void addClassToDirectoryProvider(Class<?> clazz, DirectoryProvider<?> directoryProvider) {
 		//no need to set a read barrier, we only use this class in the init thread
-		DirectoryProviderData data = dirProviderData.get(directoryProvider);
-		if (data == null) {
+		DirectoryProviderData data = dirProviderData.get( directoryProvider );
+		if ( data == null ) {
 			data = new DirectoryProviderData();
 			dirProviderData.put( directoryProvider, data );
 		}
-		data.classes.add(clazz);
+		data.classes.add( clazz );
 	}
 
 	public Set<Class<?>> getClassesInDirectoryProvider(DirectoryProvider<?> directoryProvider) {
-		if (barrier != 0) { } //read barrier
-		return Collections.unmodifiableSet( dirProviderData.get(directoryProvider).classes );
+		if ( barrier != 0 ) {
+		} //read barrier
+		return Collections.unmodifiableSet( dirProviderData.get( directoryProvider ).classes );
 	}
 
 	private void bindFilterDefs(XClass mappedXClass) {
@@ -190,7 +200,7 @@
 			bindFilterDef( defAnn, mappedXClass );
 		}
 		FullTextFilterDefs defsAnn = mappedXClass.getAnnotation( FullTextFilterDefs.class );
-		if (defsAnn != null) {
+		if ( defsAnn != null ) {
 			for ( FullTextFilterDef def : defsAnn.value() ) {
 				bindFilterDef( def, mappedXClass );
 			}
@@ -199,35 +209,45 @@
 
 	private void bindFilterDef(FullTextFilterDef defAnn, XClass mappedXClass) {
 		if ( filterDefinitions.containsKey( defAnn.name() ) ) {
-			throw new SearchException("Multiple definition of @FullTextFilterDef.name=" + defAnn.name() + ": "
-					+ mappedXClass.getName() );
+			throw new SearchException(
+					"Multiple definition of @FullTextFilterDef.name=" + defAnn.name() + ": "
+							+ mappedXClass.getName()
+			);
 		}
 
-		FilterDef filterDef = new FilterDef(defAnn);
+		FilterDef filterDef = new FilterDef( defAnn );
 		try {
 			filterDef.getImpl().newInstance();
 		}
-		catch (IllegalAccessException e) {
-			throw new SearchException("Unable to create Filter class: " + filterDef.getImpl().getName(), e);
+		catch ( IllegalAccessException e ) {
+			throw new SearchException( "Unable to create Filter class: " + filterDef.getImpl().getName(), e );
 		}
-		catch (InstantiationException e) {
-			throw new SearchException("Unable to create Filter class: " + filterDef.getImpl().getName(), e);
+		catch ( InstantiationException e ) {
+			throw new SearchException( "Unable to create Filter class: " + filterDef.getImpl().getName(), e );
 		}
 		for ( Method method : filterDef.getImpl().getMethods() ) {
 			if ( method.isAnnotationPresent( Factory.class ) ) {
 				if ( filterDef.getFactoryMethod() != null ) {
-					throw new SearchException("Multiple @Factory methods found" + defAnn.name() + ": "
-							+ filterDef.getImpl().getName() + "." + method.getName() );
+					throw new SearchException(
+							"Multiple @Factory methods found" + defAnn.name() + ": "
+									+ filterDef.getImpl().getName() + "." + method.getName()
+					);
 				}
-				if ( !method.isAccessible() ) method.setAccessible( true );
+				if ( !method.isAccessible() ) {
+					method.setAccessible( true );
+				}
 				filterDef.setFactoryMethod( method );
 			}
 			if ( method.isAnnotationPresent( Key.class ) ) {
 				if ( filterDef.getKeyMethod() != null ) {
-					throw new SearchException("Multiple @Key methods found" + defAnn.name() + ": "
-							+ filterDef.getImpl().getName() + "." + method.getName() );
+					throw new SearchException(
+							"Multiple @Key methods found" + defAnn.name() + ": "
+									+ filterDef.getImpl().getName() + "." + method.getName()
+					);
 				}
-				if ( !method.isAccessible() ) method.setAccessible( true );
+				if ( !method.isAccessible() ) {
+					method.setAccessible( true );
+				}
 				filterDef.setKeyMethod( method );
 			}
 
@@ -241,36 +261,41 @@
 
 
 	public Map<Class<?>, DocumentBuilder<?>> getDocumentBuilders() {
-		if (barrier != 0) { } //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return documentBuilders;
 	}
 
-	@SuppressWarnings( "unchecked" )
+	@SuppressWarnings("unchecked")
 	public <T> DocumentBuilder<T> getDocumentBuilder(Class<T> entityType) {
-		if (barrier != 0) { } //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return ( DocumentBuilder<T> ) documentBuilders.get( entityType );
 	}
 
-	@SuppressWarnings( "unchecked" )
+	@SuppressWarnings("unchecked")
 	public <T> DocumentBuilder<T> getContainedInOnlyBuilder(Class<T> entityType) {
-		if (barrier != 0) { } //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return ( DocumentBuilder<T> ) containedInOnlyBuilders.get( entityType );
 	}
 
 	public Set<DirectoryProvider<?>> getDirectoryProviders() {
-		if (barrier != 0) { } //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return this.dirProviderData.keySet();
 	}
 
 	public Worker getWorker() {
-		if (barrier != 0) { } //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return worker;
 	}
 
 	public void addOptimizerStrategy(DirectoryProvider<?> provider, OptimizerStrategy optimizerStrategy) {
 		//no need to set a read barrier, we run this method on the init thread
-		DirectoryProviderData data = dirProviderData.get(provider);
-		if (data == null) {
+		DirectoryProviderData data = dirProviderData.get( provider );
+		if ( data == null ) {
 			data = new DirectoryProviderData();
 			dirProviderData.put( provider, data );
 		}
@@ -283,63 +308,74 @@
 	}
 
 	public OptimizerStrategy getOptimizerStrategy(DirectoryProvider<?> provider) {
-		if (barrier != 0) {} //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return dirProviderData.get( provider ).optimizerStrategy;
 	}
 
-	public LuceneIndexingParameters getIndexingParameters(DirectoryProvider<?> provider ) {
-		if (barrier != 0) {} //read barrier
+	public LuceneIndexingParameters getIndexingParameters(DirectoryProvider<?> provider) {
+		if ( barrier != 0 ) {
+		} //read barrier
 		return dirProviderIndexingParams.get( provider );
 	}
 
 	public ReaderProvider getReaderProvider() {
-		if (barrier != 0) {} //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return readerProvider;
 	}
 
 	public DirectoryProvider[] getDirectoryProviders(Class<?> entity) {
-		if (barrier != 0) {} //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		DocumentBuilder<?> documentBuilder = getDocumentBuilder( entity );
 		return documentBuilder == null ? null : documentBuilder.getDirectoryProviders();
 	}
 
 	public void optimize() {
-		if (barrier != 0) {} //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		Set<Class<?>> clazzs = getDocumentBuilders().keySet();
-		for (Class clazz : clazzs) {
+		for ( Class clazz : clazzs ) {
 			optimize( clazz );
 		}
 	}
 
 	public void optimize(Class entityType) {
-		if (barrier != 0) {} //read barrier
-		if ( ! getDocumentBuilders().containsKey( entityType ) ) {
-			throw new SearchException("Entity not indexed: " + entityType);
+		if ( barrier != 0 ) {
+		} //read barrier
+		if ( !getDocumentBuilders().containsKey( entityType ) ) {
+			throw new SearchException( "Entity not indexed: " + entityType );
 		}
-		List<LuceneWork> queue = new ArrayList<LuceneWork>(1);
+		List<LuceneWork> queue = new ArrayList<LuceneWork>( 1 );
 		queue.add( new OptimizeLuceneWork( entityType ) );
 		getBackendQueueProcessorFactory().getProcessor( queue ).run();
 	}
 
 	public Analyzer getAnalyzer(String name) {
-		if (barrier != 0) {} //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		final Analyzer analyzer = analyzers.get( name );
-		if ( analyzer == null) throw new SearchException( "Unknown Analyzer definition: " + name);
+		if ( analyzer == null ) {
+			throw new SearchException( "Unknown Analyzer definition: " + name );
+		}
 		return analyzer;
 	}
-	
+
 	public Analyzer getAnalyzer(Class clazz) {
-		if ( clazz ==  null) {
+		if ( clazz == null ) {
 			throw new IllegalArgumentException( "A class has to be specified for retrieving a scoped analyzer" );
 		}
-		
+
 		DocumentBuilder<?> builder = documentBuilders.get( clazz );
 		if ( builder == null ) {
-			throw new IllegalArgumentException( "Entity for which to retrieve the scoped analyzer is not an @Indexed entity: " + clazz.getName() );
+			throw new IllegalArgumentException(
+					"Entity for which to retrieve the scoped analyzer is not an @Indexed entity: " + clazz.getName()
+			);
 		}
-		
+
 		return builder.getAnalyzer();
-	}	
+	}
 
 	private void initDocumentBuilders(SearchConfiguration cfg, ReflectionManager reflectionManager) {
 		InitContext context = new InitContext( cfg );
@@ -348,35 +384,48 @@
 
 		while ( iter.hasNext() ) {
 			Class mappedClass = iter.next();
-			if (mappedClass != null) {
-				XClass mappedXClass = reflectionManager.toXClass(mappedClass);
-				if ( mappedXClass != null) {
-					if ( mappedXClass.isAnnotationPresent( Indexed.class ) ) {
-						DirectoryProviderFactory.DirectoryProviders providers = factory.createDirectoryProviders( mappedXClass, cfg, this, reflectionManager );
-						//FIXME DocumentBuilder needs to be built by a helper method receiving Class<T> to infer T properly
-						//XClass unfortunately is not (yet) genericized: TODO?
-						final DocumentBuilder<?> documentBuilder = new DocumentBuilder(
-								mappedXClass, context, providers.getProviders(), providers.getSelectionStrategy(),
-								reflectionManager
-						);
+			if ( mappedClass == null ) {
+				continue;
+			}
+			@SuppressWarnings( "unchecked" )
+			XClass mappedXClass = reflectionManager.toXClass( mappedClass );
+			if ( mappedXClass == null ) {
+				continue;
+			}
 
-						documentBuilders.put( mappedClass, documentBuilder );
-					}
-					else {
-						//FIXME DocumentBuilder needs to be built by a helper method receiving Class<T> to infer T properly
-						//XClass unfortunately is not (yet) genericized: TODO?
-						final DocumentBuilder<?> documentBuilder = new DocumentBuilder(
-								mappedXClass, context, reflectionManager
-						);
-						//TODO enhance that, I don't like to expose EntityState
-						if ( documentBuilder.getEntityState() != EntityState.NON_INDEXABLE ) {
-							containedInOnlyBuilders.put( mappedClass, documentBuilder );
-						}
-					}
-					bindFilterDefs(mappedXClass);
-					//TODO should analyzer def for classes at tyher sqme level???
+			if ( mappedXClass.isAnnotationPresent( Indexed.class ) ) {
+
+				if ( mappedXClass.isAbstract() ) {
+					log.warn( "Abstract classes can never insert index documents. Remove @Indexed." );
+					continue;
 				}
+
+				DirectoryProviderFactory.DirectoryProviders providers = factory.createDirectoryProviders(
+						mappedXClass, cfg, this, reflectionManager
+				);
+				//FIXME DocumentBuilder needs to be built by a helper method receiving Class<T> to infer T properly
+				//XClass unfortunately is not (yet) genericized: TODO?
+				final DocumentBuilder<?> documentBuilder = new DocumentBuilder(
+						mappedXClass, context, providers.getProviders(), providers.getSelectionStrategy(),
+						reflectionManager
+				);
+
+				indexHierarchy.addIndexedClass( mappedClass );
+				documentBuilders.put( mappedClass, documentBuilder );
 			}
+			else {
+				//FIXME DocumentBuilder needs to be built by a helper method receiving Class<T> to infer T properly
+				//XClass unfortunately is not (yet) genericized: TODO?
+				final DocumentBuilder<?> documentBuilder = new DocumentBuilder(
+						mappedXClass, context, reflectionManager
+				);
+				//TODO enhance that, I don't like to expose EntityState
+				if ( documentBuilder.getEntityState() != EntityState.NON_INDEXABLE ) {
+					containedInOnlyBuilders.put( mappedClass, documentBuilder );
+				}
+			}
+			bindFilterDefs( mappedXClass );
+			//TODO should analyzer def for classes at tyher sqme level???
 		}
 		analyzers = context.initLazyAnalyzers();
 		factory.startDirectoryProviders();
@@ -390,16 +439,21 @@
 		}
 		else {
 			try {
-				Class filterCachingStrategyClass = org.hibernate.annotations.common.util.ReflectHelper.classForName( impl, SearchFactoryImpl.class );
-				filterCachingStrategy = (FilterCachingStrategy) filterCachingStrategyClass.newInstance();
+				Class filterCachingStrategyClass = org.hibernate
+						.annotations
+						.common
+						.util
+						.ReflectHelper
+						.classForName( impl, SearchFactoryImpl.class );
+				filterCachingStrategy = ( FilterCachingStrategy ) filterCachingStrategyClass.newInstance();
 			}
-			catch (ClassNotFoundException e) {
+			catch ( ClassNotFoundException e ) {
 				throw new SearchException( "Unable to find filterCachingStrategy class: " + impl, e );
 			}
-			catch (IllegalAccessException e) {
+			catch ( IllegalAccessException e ) {
 				throw new SearchException( "Unable to instantiate filterCachingStrategy class: " + impl, e );
 			}
-			catch (InstantiationException e) {
+			catch ( InstantiationException e ) {
 				throw new SearchException( "Unable to instantiate filterCachingStrategy class: " + impl, e );
 			}
 		}
@@ -408,23 +462,26 @@
 	}
 
 	public FilterCachingStrategy getFilterCachingStrategy() {
-		if (barrier != 0) {} //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return filterCachingStrategy;
 	}
 
 	public FilterDef getFilterDefinition(String name) {
-		if (barrier != 0) {} //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return filterDefinitions.get( name );
 	}
 
 	private static class DirectoryProviderData {
 		public final ReentrantLock dirLock = new ReentrantLock();
 		public OptimizerStrategy optimizerStrategy;
-		public Set<Class<?>> classes = new HashSet<Class<?>>(2);
+		public Set<Class<?>> classes = new HashSet<Class<?>>( 2 );
 	}
 
 	public ReentrantLock getDirectoryProviderLock(DirectoryProvider<?> dp) {
-		if (barrier != 0) {} //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return this.dirProviderData.get( dp ).dirLock;
 	}
 
@@ -434,7 +491,58 @@
 	}
 
 	public int getFilterCacheBitResultsSize() {
-		if (barrier != 0) {} //read barrier
+		if ( barrier != 0 ) {
+		} //read barrier
 		return cacheBitResultsSize;
 	}
+
+	public Set<Class<?>> getIndexedTypesPolymorphic(Class<?>[] classes) {
+		return indexHierarchy.getIndexedClasses( classes );
+	}
+
+	/**
+	 * Helper class which keeps track of all super classes and interfaces of the indexed entities.
+	 */
+	private static class PolymorphicIndexHierarchy {
+		private Map<Class<?>, Set<Class<?>>> classToIndexedClass;
+
+		PolymorphicIndexHierarchy() {
+			classToIndexedClass = new HashMap<Class<?>, Set<Class<?>>>();
+		}
+
+		void addIndexedClass(Class indexedClass) {
+			addClass( indexedClass, indexedClass );
+			Class superClass = indexedClass.getSuperclass();
+			while ( superClass != null ) {
+				addClass( superClass, indexedClass );
+				superClass = superClass.getSuperclass();
+			}
+			for ( Class clazz : indexedClass.getInterfaces() ) {
+				addClass( clazz, indexedClass );
+			}
+		}
+
+		private void addClass(Class superclass, Class indexedClass) {
+			Set<Class<?>> classesSet = classToIndexedClass.get( superclass );
+			if ( classesSet == null ) {
+				classesSet = new HashSet<Class<?>>();
+				classToIndexedClass.put( superclass, classesSet );
+			}
+			classesSet.add( indexedClass );
+		}
+
+		Set<Class<?>> getIndexedClasses(Class<?>[] classes) {
+			Set<Class<?>> classesSet = new HashSet<Class<?>>();
+			for ( Class clazz : classes ) {
+				Set<Class<?>> set = classToIndexedClass.get( clazz );
+				if ( set != null ) {
+					classesSet.addAll( set );
+				}
+			}
+			if ( log.isTraceEnabled() ) {
+				log.trace( "Targeted indexed classes for {}: {}", Arrays.toString( classes ), classesSet );
+			}
+			return classesSet;
+		}
+	}
 }

Modified: search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -72,7 +72,7 @@
 public class FullTextQueryImpl extends AbstractQueryImpl implements FullTextQuery {
 	private static final Logger log = LoggerFactory.make();
 	private final org.apache.lucene.search.Query luceneQuery;
-	private Class<?>[] classes;
+	private Set<Class<?>> targetedEntities;
 	private Set<Class<?>> classesAndSubclasses;
 	//optimization: if we can avoid the filter clause (we can most of the time) do it as it has a significant perf impact
 	private boolean needClassFilterClause;
@@ -93,17 +93,17 @@
 	/**
 	 * Constructs a  <code>FullTextQueryImpl</code> instance.
 	 *
-	 * @param query  The Lucene query
-	 * @param classes  Array of classes (must be immutable) used to filter the results to the given class types.
+	 * @param query The Lucene query.
+	 * @param classes Array of classes (must be immutable) used to filter the results to the given class types.
 	 * @param session Access to the Hibernate session.
-	 * @param parameterMetadata  Additional query metadata.
+	 * @param parameterMetadata Additional query metadata.
 	 */
 	public FullTextQueryImpl(org.apache.lucene.search.Query query, Class[] classes, SessionImplementor session,
 							 ParameterMetadata parameterMetadata) {
 		//TODO handle flushMode
 		super( query.toString(), null, session, parameterMetadata );
 		this.luceneQuery = query;
-		this.classes = classes;
+		this.targetedEntities = getSearchFactoryImplementor().getIndexedTypesPolymorphic( classes );
 	}
 
 	/**
@@ -132,7 +132,7 @@
 		//user stop using it
 		//scrollable is better in this area
 
-		SearchFactoryImplementor searchFactoryImplementor = ContextHelper.getSearchFactoryBySFI( session );
+		SearchFactoryImplementor searchFactoryImplementor = getSearchFactoryImplementor();
 		//find the directories
 		IndexSearcher searcher = buildSearcher( searchFactoryImplementor );
 		if ( searcher == null ) {
@@ -173,22 +173,23 @@
 		if ( indexProjection != null ) {
 			ProjectionLoader loader = new ProjectionLoader();
 			loader.init( session, searchFactoryImplementor, resultTransformer, indexProjection );
-			loader.setEntityTypes( classes );
+			loader.setEntityTypes( targetedEntities );
 			return loader;
 		}
 		if ( criteria != null ) {
-			if ( classes.length > 1 ) {
+			if ( targetedEntities.size() > 1 ) {
 				throw new SearchException( "Cannot mix criteria and multiple entity types" );
 			}
 			if ( criteria instanceof CriteriaImpl ) {
 				String targetEntity = ( ( CriteriaImpl ) criteria ).getEntityOrClassName();
-				if ( classes.length == 1 && !classes[0].getName().equals( targetEntity ) ) {
+				if ( targetedEntities.size() == 1 && !targetedEntities.iterator().next().getName().equals( targetEntity ) ) {
 					throw new SearchException( "Criteria query entity should match query entity" );
 				}
 				else {
 					try {
 						Class entityType = ReflectHelper.classForName( targetEntity );
-						classes = new Class[] { entityType };
+						targetedEntities = new HashSet<Class<?>>( 1 );
+						targetedEntities.add( entityType );
 					}
 					catch ( ClassNotFoundException e ) {
 						throw new SearchException( "Unable to load entity class from criteria: " + targetEntity, e );
@@ -197,20 +198,20 @@
 			}
 			QueryLoader loader = new QueryLoader();
 			loader.init( session, searchFactoryImplementor );
-			loader.setEntityType( classes[0] );
+			loader.setEntityType( targetedEntities.iterator().next() );
 			loader.setCriteria( criteria );
 			return loader;
 		}
-		else if ( classes.length == 1 ) {
+		else if ( targetedEntities.size() == 1 ) {
 			final QueryLoader loader = new QueryLoader();
 			loader.init( session, searchFactoryImplementor );
-			loader.setEntityType( classes[0] );
+			loader.setEntityType( targetedEntities.iterator().next() );
 			return loader;
 		}
 		else {
 			final MultiClassesQueryLoader loader = new MultiClassesQueryLoader();
 			loader.init( session, searchFactoryImplementor );
-			loader.setEntityTypes( classes );
+			loader.setEntityTypes( targetedEntities );
 			return loader;
 		}
 	}
@@ -227,7 +228,7 @@
 			int first = first();
 			int max = max( first, queryHits.totalHits );
 			DocumentExtractor extractor = new DocumentExtractor(
-					queryHits, searchFactory, indexProjection, idFieldNames,allowFieldSelectionInProjection
+					queryHits, searchFactory, indexProjection, idFieldNames, allowFieldSelectionInProjection
 			);
 			Loader loader = getLoader( ( Session ) this.session, searchFactory );
 			return new ScrollableResultsImpl(
@@ -574,8 +575,9 @@
 	 * Build the index searcher for this fulltext query.
 	 *
 	 * @param searchFactoryImplementor the search factory.
+	 *
 	 * @return the <code>IndexSearcher</code> for this query (can be <code>null</code>.
-	 * TODO change classesAndSubclasses by side effect, which is a mismatch with the Searcher return, fix that.
+	 *         TODO change classesAndSubclasses by side effect, which is a mismatch with the Searcher return, fix that.
 	 */
 	private IndexSearcher buildSearcher(SearchFactoryImplementor searchFactoryImplementor) {
 		Map<Class<?>, DocumentBuilder<?>> builders = searchFactoryImplementor.getDocumentBuilders();
@@ -583,9 +585,9 @@
 		Set<String> idFieldNames = new HashSet<String>();
 
 		Similarity searcherSimilarity = null;
-		//TODO check if caching this work for the last n list of classes makes a perf boost
-		if ( classes == null || classes.length == 0 ) {
-			// empty classes array means search over all indexed enities,
+		//TODO check if caching this work for the last n list of targetedEntities makes a perf boost
+		if ( targetedEntities.size() == 0 ) {
+			// empty targetedEntities array means search over all indexed enities,
 			// but we have to make sure there is at least one
 			if ( builders.isEmpty() ) {
 				throw new HibernateException(
@@ -606,9 +608,9 @@
 			classesAndSubclasses = null;
 		}
 		else {
-			Set<Class<?>> involvedClasses = new HashSet<Class<?>>( classes.length );
-			Collections.addAll( involvedClasses, classes );
-			for ( Class<?> clazz : classes ) {
+			Set<Class<?>> involvedClasses = new HashSet<Class<?>>( targetedEntities.size() );
+			involvedClasses.addAll( targetedEntities );
+			for ( Class<?> clazz : targetedEntities ) {
 				DocumentBuilder<?> builder = builders.get( clazz );
 				if ( builder != null ) {
 					involvedClasses.addAll( builder.getMappedSubclasses() );

Modified: search/trunk/src/test/org/hibernate/search/test/SearchTestCase.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/SearchTestCase.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/test/org/hibernate/search/test/SearchTestCase.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -6,11 +6,19 @@
 import org.apache.lucene.analysis.StopAnalyzer;
 import org.apache.lucene.store.Directory;
 import org.hibernate.HibernateException;
+import org.hibernate.Transaction;
 import org.hibernate.event.PostInsertEventListener;
 import org.hibernate.impl.SessionFactoryImpl;
 import org.hibernate.search.Environment;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.test.inheritance.Animal;
+import org.hibernate.search.test.inheritance.Mammal;
 import org.hibernate.search.event.FullTextIndexEventListener;
 import org.hibernate.search.store.RAMDirectoryProvider;
+import org.hibernate.search.store.FSDirectoryProvider;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,6 +66,18 @@
         return listener;
     }
 
+	protected void ensureIndexesAreEmpty() {
+		FullTextSession s = Search.getFullTextSession( openSession() );
+		Transaction tx;
+		tx = s.beginTransaction();
+		for ( Class clazz : getMappings() ) {
+			if ( clazz.getAnnotation( Indexed.class ) != null ) {
+				s.purgeAll( clazz );
+			}
+		}
+		tx.commit();
+	}
+
 	protected void configure(org.hibernate.cfg.Configuration cfg) {
 		cfg.setProperty( "hibernate.search.default.directory_provider", RAMDirectoryProvider.class.getName() );
 		cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );

Modified: search/trunk/src/test/org/hibernate/search/test/filter/FilterTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/filter/FilterTest.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/test/org/hibernate/search/test/filter/FilterTest.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -96,11 +96,7 @@
 			//success
 		}
 
-
 		s.getTransaction().commit();
-
-
-
 		s.close();
 		deleteData();
 	}

Modified: search/trunk/src/test/org/hibernate/search/test/inheritance/Animal.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/inheritance/Animal.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/test/org/hibernate/search/test/inheritance/Animal.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -1,6 +1,7 @@
 //$Id$
 package org.hibernate.search.test.inheritance;
 
+import java.io.Serializable;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
 import javax.persistence.Id;
@@ -15,8 +16,7 @@
  * @author Emmanuel Bernard
  */
 @Entity
- at Indexed
-public class Animal extends Being {
+public abstract class Animal extends Being {
     private Long id;
     private String name;
 

Modified: search/trunk/src/test/org/hibernate/search/test/inheritance/Being.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/inheritance/Being.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/test/org/hibernate/search/test/inheritance/Being.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -6,6 +6,7 @@
 import org.hibernate.search.annotations.Field;
 import org.hibernate.search.annotations.Index;
 import org.hibernate.search.annotations.FieldBridge;
+import org.hibernate.search.annotations.Indexed;
 import org.hibernate.search.test.bridge.PaddedIntegerBridge;
 
 /**

Copied: search/trunk/src/test/org/hibernate/search/test/inheritance/Fish.java (from rev 15588, search/trunk/src/test/org/hibernate/search/test/inheritance/Mammal.java)
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/inheritance/Fish.java	                        (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/inheritance/Fish.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -0,0 +1,28 @@
+//$Id$
+package org.hibernate.search.test.inheritance;
+
+import javax.persistence.Entity;
+
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.Store;
+
+/**
+ * @author Hardy Ferentschik
+ */
+ at Entity
+ at Indexed
+public class Fish extends Animal {
+
+	private int numberOfDorsalFins;
+
+	@Field(index = Index.UN_TOKENIZED, store = Store.YES)
+	public int getNumberOfDorsalFins() {
+		return numberOfDorsalFins;
+	}
+
+	public void setNumberOfDorsalFins(int numberOfDorsalFins) {
+		this.numberOfDorsalFins = numberOfDorsalFins;
+	}
+}
\ No newline at end of file


Property changes on: search/trunk/src/test/org/hibernate/search/test/inheritance/Fish.java
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:mergeinfo
   + 

Modified: search/trunk/src/test/org/hibernate/search/test/inheritance/InheritanceTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/inheritance/InheritanceTest.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/test/org/hibernate/search/test/inheritance/InheritanceTest.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -2,6 +2,7 @@
 package org.hibernate.search.test.inheritance;
 
 import java.util.List;
+import java.io.Serializable;
 
 import org.apache.lucene.analysis.StopAnalyzer;
 import org.apache.lucene.index.Term;
@@ -26,41 +27,76 @@
 
 	public void testInheritance() throws Exception {
 		createTestData();
+
 		FullTextSession s = Search.getFullTextSession( openSession() );
 		Transaction tx = s.beginTransaction();
+
 		QueryParser parser = new QueryParser( "name", new StopAnalyzer() );
+		Query query = parser.parse( "Elephant" );
+		org.hibernate.Query hibQuery = s.createFullTextQuery( query, Mammal.class );
+		assertItsTheElephant( hibQuery.list() );
 
-		Query query;
-		org.hibernate.Query hibQuery;
+		query = parser.parse( "hasSweatGlands:false" );
+		hibQuery = s.createFullTextQuery( query, Animal.class, Mammal.class );
+		assertItsTheElephant( hibQuery.list() );
 
-		query = parser.parse( "Elephant" );
-		hibQuery = s.createFullTextQuery( query, Mammal.class );
+		query = parser.parse( "Elephant OR White Pointer" );
+		hibQuery = s.createFullTextQuery( query, Being.class );
 		List result = hibQuery.list();
 		assertNotNull( result );
-		assertEquals( "Query subclass by superclass attribute", 1, result.size() );
+		assertEquals( "Query filtering on superclass return mapped subclasses", 2, result.size() );
 
-		query = parser.parse( "mammalNbr:[2 TO 2]" );
-		hibQuery = s.createFullTextQuery( query, Animal.class, Mammal.class );
-		result = hibQuery.list();
-		assertNotNull( result );
-		assertEquals( "Query subclass by subclass attribute", 1, result.size() );
-
-		query = parser.parse( "Jr" );
+		query = new RangeQuery( new Term( "weight", "04000" ), new Term( "weight", "05000" ), true );
 		hibQuery = s.createFullTextQuery( query, Animal.class );
-		result = hibQuery.list();
-		assertNotNull( result );
-		assertEquals( "Query filtering on superclass return mapped subclasses", 2, result.size() );
+		assertItsTheElephant( hibQuery.list() );
 
-		query = new RangeQuery( new Term( "weight", "00200" ), null, true );
+		query = parser.parse( "Elephant" );
+		hibQuery = s.createFullTextQuery( query, Being.class );
+		assertItsTheElephant( hibQuery.list() );
+
+		tx.commit();
+		s.close();
+	}
+
+
+	public void testPolymorphicQueries() throws Exception {
+		createTestData();
+
+		FullTextSession s = Search.getFullTextSession( openSession() );
+		Transaction tx = s.beginTransaction();
+		QueryParser parser = new QueryParser( "name", new StopAnalyzer() );
+		Query query = parser.parse( "Elephant" );
+
+		org.hibernate.Query hibQuery = s.createFullTextQuery( query, Mammal.class );
+		assertItsTheElephant( hibQuery.list() );
+
 		hibQuery = s.createFullTextQuery( query, Animal.class );
-		result = hibQuery.list();
-		assertNotNull( result );
-		assertEquals( "Query on non @Indexed superclass property", 1, result.size() );
+		assertItsTheElephant( hibQuery.list() );
 
+		hibQuery = s.createFullTextQuery( query, Being.class );
+		assertItsTheElephant( hibQuery.list() );
+
+		hibQuery = s.createFullTextQuery( query, Object.class );
+		assertItsTheElephant( hibQuery.list() );
+
+		hibQuery = s.createFullTextQuery( query, Serializable.class );
+		assertItsTheElephant( hibQuery.list() );
+
+		hibQuery = s.createFullTextQuery( query, Mammal.class, Animal.class, Being.class, Object.class, Serializable.class );
+		assertItsTheElephant( hibQuery.list() );
+
 		tx.commit();
 		s.close();
 	}
 
+	private void assertItsTheElephant(List result) {
+		assertNotNull( result );
+		assertEquals( "Wrong number of results", 1, result.size() );
+		assertTrue( "Wrong result type", result.get( 0 ) instanceof Mammal );
+		Mammal mammal = ( Mammal ) result.get( 0 );
+		assertEquals( "Wrong animal name", "Elephant", mammal.getName() );
+	}
+
 	/**
 	 * Tests that purging the index of a class also purges the index of the subclasses. See also HSEARCH-262.
 	 *
@@ -72,10 +108,10 @@
 		Transaction tx = s.beginTransaction();
 		QueryParser parser = new QueryParser( "name", new StopAnalyzer() );
 
-		Query query = parser.parse( "Jr" );
+		Query query = parser.parse( "Elephant OR White Pointer OR Chimpanzee" );
 		List result = s.createFullTextQuery( query, Animal.class ).list();
 		assertNotNull( result );
-		assertEquals( "Wrong number of hits. There should be one elephant and one shark.", 2, result.size() );
+		assertEquals( "Wrong number of hits. There should be one elephant and one shark.", 3, result.size() );
 
 		s.purgeAll( Animal.class );
 		tx.commit();
@@ -87,38 +123,40 @@
 		);
 
 		tx.commit();
-
 		s.close();
 	}
 
 	private void createTestData() {
 		FullTextSession s = Search.getFullTextSession( openSession() );
 		Transaction tx = s.beginTransaction();
-		Animal a = new Animal();
-		a.setName( "Shark Jr" );
-		s.save( a );
-		Mammal m = new Mammal();
-		m.setMammalNbr( 2 );
-		m.setName( "Elephant Jr" );
-		m.setWeight( 400 );
-		s.save( m );
-		tx.commit();//post commit events for lucene
-		s.clear();
-	}
 
-	private void ensureIndexesAreEmpty() {
-		FullTextSession s = Search.getFullTextSession( openSession() );
-		Transaction tx;
-		tx = s.beginTransaction();
-		s.purgeAll( Animal.class );
-		s.purgeAll( Mammal.class );
+		Fish shark = new Fish();
+		shark.setName( "White Pointer" );
+		shark.setNumberOfDorsalFins( 2 );
+		shark.setWeight( 1500 );
+		s.save( shark );
+
+		Mammal elephant = new Mammal();
+		elephant.setName( "Elephant" );
+		elephant.setHasSweatGlands( false );
+		elephant.setWeight( 4500 );
+		s.save( elephant );
+
+		Mammal chimp = new Mammal();
+		chimp.setName( "Chimpanzee" );
+		chimp.setHasSweatGlands( true );
+		chimp.setWeight( 50 );
+		s.save( chimp );
+
 		tx.commit();
+		s.clear();
 	}
 
 	protected Class[] getMappings() {
 		return new Class[] {
 				Animal.class,
-				Mammal.class
+				Mammal.class,
+				Fish.class
 		};
 	}
 }

Modified: search/trunk/src/test/org/hibernate/search/test/inheritance/Mammal.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/inheritance/Mammal.java	2008-11-19 14:11:26 UTC (rev 15591)
+++ search/trunk/src/test/org/hibernate/search/test/inheritance/Mammal.java	2008-11-19 14:17:48 UTC (rev 15592)
@@ -1,6 +1,7 @@
 //$Id$
 package org.hibernate.search.test.inheritance;
 
+import java.io.Serializable;
 import javax.persistence.Entity;
 
 import org.hibernate.search.annotations.Field;
@@ -13,15 +14,15 @@
  */
 @Entity
 @Indexed
-public class Mammal extends Animal {
-    private int mammalNbr;
+public class Mammal extends Animal implements Serializable {
+    private boolean hasSweatGlands;
 
     @Field(index= Index.UN_TOKENIZED, store= Store.YES)
-	public int getMammalNbr() {
-        return mammalNbr;
-    }
+	public boolean isHasSweatGlands() {
+		return hasSweatGlands;
+	}
 
-    public void setMammalNbr(int mammalNbr) {
-        this.mammalNbr = mammalNbr;
-    }
+	public void setHasSweatGlands(boolean hasSweatGlands) {
+		this.hasSweatGlands = hasSweatGlands;
+	}
 }




More information about the hibernate-commits mailing list