[hibernate-commits] Hibernate SVN: r15532 - in search/trunk/src: java/org/hibernate/search/impl and 1 other directories.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Fri Nov 7 11:06:17 EST 2008
Author: hardy.ferentschik
Date: 2008-11-07 11:06:17 -0500 (Fri, 07 Nov 2008)
New Revision: 15532
Added:
search/trunk/src/test/org/hibernate/search/test/id/Animal.java
search/trunk/src/test/org/hibernate/search/test/id/ImplicitIdTest.java
Modified:
search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java
search/trunk/src/java/org/hibernate/search/impl/InitContext.java
Log:
HSEARCH-104
Use @Id when no @DocumentId is specified.
Modified: search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java 2008-11-07 11:58:00 UTC (rev 15531)
+++ search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java 2008-11-07 16:06:17 UTC (rev 15532)
@@ -3,6 +3,8 @@
import java.io.Serializable;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Method;
+import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -75,6 +77,11 @@
private final DirectoryProvider[] directoryProviders;
private final IndexShardingStrategy shardingStrategy;
private String idKeywordName;
+
+ /**
+ * Flag indicating whether <code>@DocumentId</code> was explicitly specified.
+ */
+ private boolean explicitDocumentId = false;
private XMember idGetter;
private Float idBoost;
public static final String CLASS_FIELDNAME = "_hibernate_class";
@@ -91,13 +98,8 @@
private boolean idProvided = false;
private EntityState entityState;
-
- public boolean isRoot() {
- return isRoot;
- }
-
/**
- * used on an @Indexed entity
+ * Constructor used on an @Indexed entity.
*/
public DocumentBuilder(XClass clazz, InitContext context, DirectoryProvider[] directoryProviders,
IndexShardingStrategy shardingStrategy, ReflectionManager reflectionManager) {
@@ -135,7 +137,7 @@
}
/**
- * used on a non @Indexed entity
+ * Constructor used on a non @Indexed entity.
*/
public DocumentBuilder(XClass clazz, InitContext context, ReflectionManager reflectionManager) {
this.entityState = EntityState.CONTAINED_IN_ONLY;
@@ -153,6 +155,10 @@
}
}
+ public boolean isRoot() {
+ return isRoot;
+ }
+
private ProvidedId findProvidedId(XClass clazz, ReflectionManager reflectionManager) {
ProvidedId id = null;
XClass currentClass = clazz;
@@ -214,7 +220,7 @@
if ( analyzer != null ) {
propertiesMetadata.analyzer = analyzer;
}
- getAnalyzerDefs( currClass, context );
+ checkForAnalyzerDefs( currClass, context );
// Check for any ClassBridges annotation.
ClassBridges classBridgesAnn = currClass.getAnnotation( ClassBridges.class );
if ( classBridgesAnn != null ) {
@@ -265,7 +271,7 @@
}
}
- private void getAnalyzerDefs(XAnnotatedElement annotatedElement, InitContext context) {
+ private void checkForAnalyzerDefs(XAnnotatedElement annotatedElement, InitContext context) {
AnalyzerDefs defs = annotatedElement.getAnnotation( AnalyzerDefs.class );
if ( defs != null ) {
for (AnalyzerDef def : defs.value()) {
@@ -287,62 +293,41 @@
private void initializeMember(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot,
String prefix, Set<XClass> processedClasses, InitContext context) {
- DocumentId documentIdAnn = member.getAnnotation( DocumentId.class );
- if ( documentIdAnn != null ) {
- if ( isRoot ) {
- if ( idKeywordName != null ) {
- throw new AssertionFailure( "Two document id assigned: "
- + idKeywordName + " and " + BinderHelper.getAttributeName( member, documentIdAnn.name() ) );
- }
- idKeywordName = prefix + BinderHelper.getAttributeName( member, documentIdAnn.name() );
- FieldBridge fieldBridge = BridgeFactory.guessType( null, member, reflectionManager );
- if ( fieldBridge instanceof TwoWayFieldBridge ) {
- idBridge = (TwoWayFieldBridge) fieldBridge;
- }
- else {
- throw new SearchException(
- "Bridge for document id does not implement TwoWayFieldBridge: " + member.getName() );
- }
- idBoost = getBoost( member, null );
- setAccessible( member );
- idGetter = member;
- }
- else {
- //component should index their document id
- setAccessible( member );
- propertiesMetadata.fieldGetters.add( member );
- String fieldName = prefix + BinderHelper.getAttributeName( member, documentIdAnn.name() );
- propertiesMetadata.fieldNames.add( fieldName );
- propertiesMetadata.fieldStore.add( getStore( Store.YES ) );
- propertiesMetadata.fieldIndex.add( getIndex( Index.UN_TOKENIZED ) );
- propertiesMetadata.fieldTermVectors.add( getTermVector( TermVector.NO ) );
- propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( null, member, reflectionManager ) );
- propertiesMetadata.fieldBoosts.add( getBoost( member, null ) );
- // property > entity analyzer (no field analyzer)
- Analyzer analyzer = getAnalyzer( member, context );
- if ( analyzer == null ) analyzer = propertiesMetadata.analyzer;
- if ( analyzer == null ) throw new AssertionFailure( "Analizer should not be undefined" );
- this.analyzer.addScopedAnalyzer( fieldName, analyzer );
- }
- }
- {
- org.hibernate.search.annotations.Field fieldAnn =
- member.getAnnotation( org.hibernate.search.annotations.Field.class );
- if ( fieldAnn != null ) {
+ checkDocumentId( member, propertiesMetadata, isRoot, prefix, context );
+ checkForField( member, propertiesMetadata, prefix, context );
+ checkForFields( member, propertiesMetadata, prefix, context );
+ checkForAnalyzerDefs( member, context );
+ checkForIndexedEmbedded( member, propertiesMetadata, prefix, processedClasses, context );
+ checkForConstraintIn( member, propertiesMetadata );
+ }
+
+ private void checkForFields(XProperty member, PropertiesMetadata propertiesMetadata, String prefix, InitContext context) {
+ org.hibernate.search.annotations.Fields fieldsAnn =
+ member.getAnnotation( org.hibernate.search.annotations.Fields.class );
+ if ( fieldsAnn != null ) {
+ for (org.hibernate.search.annotations.Field fieldAnn : fieldsAnn.value()) {
bindFieldAnnotation( member, propertiesMetadata, prefix, fieldAnn, context );
}
}
- {
- org.hibernate.search.annotations.Fields fieldsAnn =
- member.getAnnotation( org.hibernate.search.annotations.Fields.class );
- if ( fieldsAnn != null ) {
- for (org.hibernate.search.annotations.Field fieldAnn : fieldsAnn.value()) {
- bindFieldAnnotation( member, propertiesMetadata, prefix, fieldAnn, context );
- }
- }
+ }
+
+ private void checkForField(XProperty member, PropertiesMetadata propertiesMetadata, String prefix, InitContext context) {
+ org.hibernate.search.annotations.Field fieldAnn =
+ member.getAnnotation( org.hibernate.search.annotations.Field.class );
+ if ( fieldAnn != null ) {
+ bindFieldAnnotation( member, propertiesMetadata, prefix, fieldAnn, context );
}
- getAnalyzerDefs( member, context );
+ }
+ private void checkForConstraintIn(XProperty member, PropertiesMetadata propertiesMetadata) {
+ ContainedIn containedAnn = member.getAnnotation( ContainedIn.class );
+ if ( containedAnn != null ) {
+ setAccessible( member );
+ propertiesMetadata.containedInGetters.add( member );
+ }
+ }
+
+ private void checkForIndexedEmbedded(XProperty member, PropertiesMetadata propertiesMetadata, String prefix, Set<XClass> processedClasses, InitContext context) {
IndexedEmbedded embeddedAnn = member.getAnnotation( IndexedEmbedded.class );
if ( embeddedAnn != null ) {
int oldMaxLevel = maxLevel;
@@ -411,14 +396,103 @@
level--;
maxLevel = oldMaxLevel; //set back the the old max level
}
+ }
- ContainedIn containedAnn = member.getAnnotation( ContainedIn.class );
- if ( containedAnn != null ) {
- setAccessible( member );
- propertiesMetadata.containedInGetters.add( member );
+ private void checkDocumentId(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot, String prefix, InitContext context) {
+ Annotation idAnnotation = getIdAnnotation( member, context );
+ if ( idAnnotation != null ) {
+ String attributeName = getIdAttributeName( member, idAnnotation );
+ if ( isRoot ) {
+ if ( idKeywordName != null && explicitDocumentId ) {
+ throw new AssertionFailure( "Two document id assigned: "
+ + idKeywordName + " and " + attributeName );
+ }
+ idKeywordName = prefix + attributeName;
+ FieldBridge fieldBridge = BridgeFactory.guessType( null, member, reflectionManager );
+ if ( fieldBridge instanceof TwoWayFieldBridge ) {
+ idBridge = (TwoWayFieldBridge) fieldBridge;
+ }
+ else {
+ throw new SearchException(
+ "Bridge for document id does not implement TwoWayFieldBridge: " + member.getName() );
+ }
+ idBoost = getBoost( member, null );
+ setAccessible( member );
+ idGetter = member;
+ }
+ else {
+ //component should index their document id
+ setAccessible( member );
+ propertiesMetadata.fieldGetters.add( member );
+ String fieldName = prefix + attributeName;
+ propertiesMetadata.fieldNames.add( fieldName );
+ propertiesMetadata.fieldStore.add( getStore( Store.YES ) );
+ propertiesMetadata.fieldIndex.add( getIndex( Index.UN_TOKENIZED ) );
+ propertiesMetadata.fieldTermVectors.add( getTermVector( TermVector.NO ) );
+ propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( null, member, reflectionManager ) );
+ propertiesMetadata.fieldBoosts.add( getBoost( member, null ) );
+ // property > entity analyzer (no field analyzer)
+ Analyzer analyzer = getAnalyzer( member, context );
+ if ( analyzer == null ) analyzer = propertiesMetadata.analyzer;
+ if ( analyzer == null ) throw new AssertionFailure( "Analizer should not be undefined" );
+ this.analyzer.addScopedAnalyzer( fieldName, analyzer );
+ }
}
}
+ /**
+ * Checks whether the specified property contains an annotation used as document id.
+ * This can either be an explicit <code>@DocumentId</code> or if no <code>@DocumentId</code> is specified a
+ * JPA <code>@Id</code> annotation. The check for the JPA annotation is indirectly to avoid a hard dependency
+ * to Hibernate Annotations.
+ *
+ * @param member the property to check for the id annotation.
+ * @return the annotation used as document id or <code>null</code> if id annotation is specified on the property.
+ */
+ private Annotation getIdAnnotation(XProperty member, InitContext context) {
+ // check for explicit DocumentId
+ Annotation documentIdAnn = member.getAnnotation( DocumentId.class );
+ if ( documentIdAnn != null ) {
+ explicitDocumentId = true;
+ return documentIdAnn;
+ }
+
+ // check for JPA @Id
+ if ( !explicitDocumentId && context.isJpaPresent() ) {
+ Class idClass;
+ try {
+ idClass = org.hibernate.util.ReflectHelper.classForName( "javax.persistence.Id", InitContext.class );
+ } catch ( ClassNotFoundException e ) {
+ throw new SearchException( "Unable to load @Id.class even though it should be present ?!" );
+ }
+ documentIdAnn = member.getAnnotation( idClass );
+ if ( documentIdAnn != null )
+ log.debug( "Found JPA id and using it as document id" );
+ }
+ return documentIdAnn;
+ }
+
+ /**
+ * Determines the property name for the document id. It is either the name of the property itself or the
+ * value of the name attribute of the <code>idAnnotation</code>.
+ *
+ * @param member the property used as id property.
+ * @param idAnnotation the id annotation
+ * @return property name to be used as document id.
+ */
+ private String getIdAttributeName(XProperty member, Annotation idAnnotation) {
+ String name = null;
+ try {
+ Method m = idAnnotation.getClass().getMethod( "name" );
+ name = (String) m.invoke( idAnnotation );
+ }
+ catch ( Exception e ) {
+ // ignore
+ }
+
+ return BinderHelper.getAttributeName( member, name );
+ }
+
private void bindClassAnnotation(String prefix, PropertiesMetadata propertiesMetadata, ClassBridge ann, InitContext context) {
//FIXME name should be prefixed
String fieldName = prefix + ann.name();
Modified: search/trunk/src/java/org/hibernate/search/impl/InitContext.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/impl/InitContext.java 2008-11-07 11:58:00 UTC (rev 15531)
+++ search/trunk/src/java/org/hibernate/search/impl/InitContext.java 2008-11-07 16:06:17 UTC (rev 15532)
@@ -19,7 +19,12 @@
import org.hibernate.util.ReflectHelper;
/**
+ * Provides access to some default configuration settings (eg default <code>Analyzer</code> or default
+ * <code>Similarity</code>) and checks whether certain optional libraries are available.
+ *
+ *
* @author Emmanuel Bernard
+ * @author Hardy Ferentschik
*/
public class InitContext {
private final Map<String, AnalyzerDef> analyzerDefs = new HashMap<String, AnalyzerDef>();
@@ -27,11 +32,13 @@
private final Analyzer defaultAnalyzer;
private final Similarity defaultSimilarity;
private final boolean solrPresent;
+ private final boolean jpaPresent;
public InitContext(SearchConfiguration cfg) {
defaultAnalyzer = initAnalyzer(cfg);
defaultSimilarity = initSimilarity(cfg);
solrPresent = isPresent( "org.apache.solr.analysis.TokenizerFactory" );
+ jpaPresent = isPresent( "javax.persistence.Id" );
}
public void addAnalyzerDef(AnalyzerDef ann) {
@@ -68,8 +75,6 @@
analyzerClass = ReflectHelper.classForName(analyzerClassName);
} catch (Exception e) {
return buildLazyAnalyzer( analyzerClassName );
-// throw new SearchException("Lucene analyzer class '" + analyzerClassName + "' defined in property '"
-// + Environment.ANALYZER_CLASS + "' could not be found.", e);
}
} else {
analyzerClass = StandardAnalyzer.class;
@@ -88,7 +93,10 @@
}
/**
- * Initializes the Lucene similarity to use
+ * Initializes the Lucene similarity to use.
+ *
+ * @param cfg the search configuration.
+ * @return returns the default similarity class.
*/
private Similarity initSimilarity(SearchConfiguration cfg) {
Class similarityClass;
@@ -165,8 +173,8 @@
if ( ! solrPresent ) {
throw new SearchException( "Use of @AnalyzerDef while Solr is not present in the classpath. Add apache-solr-analyzer.jar" );
}
- //SolrAnalyzerBuilder references Solr classes.
- //InitContext should not (directly or indirectly) load a Solr class to avoid hard dependency
+ // SolrAnalyzerBuilder references Solr classes.
+ // InitContext should not (directly or indirectly) load a Solr class to avoid hard dependency
// unless necessary
// the curent mecanism (check sor class presence and call SolrAnalyzerBuilder if needed
// seems to be sufficient on Apple VM (derived from Sun's
@@ -174,6 +182,10 @@
return SolrAnalyzerBuilder.buildAnalyzer( analyzerDef );
}
+ public boolean isJpaPresent() {
+ return jpaPresent;
+ }
+
private boolean isPresent(String classname) {
try {
ReflectHelper.classForName( classname, InitContext.class );
Property changes on: search/trunk/src/java/org/hibernate/search/impl/InitContext.java
___________________________________________________________________
Name: svn:keywords
+ Id
Added: search/trunk/src/test/org/hibernate/search/test/id/Animal.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/id/Animal.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/id/Animal.java 2008-11-07 16:06:17 UTC (rev 15532)
@@ -0,0 +1,56 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.search.test.id;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+import org.hibernate.search.annotations.Indexed;
+
+/**
+ * @author Hardy Ferentschik
+ */
+ at Entity
+ at Indexed(index = "Animal")
+public class Animal {
+ @Id @GeneratedValue
+ private Integer id;
+
+ @Field(index = Index.TOKENIZED)
+ private String name;
+
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
Copied: search/trunk/src/test/org/hibernate/search/test/id/ImplicitIdTest.java (from rev 15529, search/trunk/src/test/org/hibernate/search/test/id/EmbeddedIdTest.java)
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/id/ImplicitIdTest.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/id/ImplicitIdTest.java 2008-11-07 16:06:17 UTC (rev 15532)
@@ -0,0 +1,48 @@
+// $Id$
+package org.hibernate.search.test.id;
+
+import java.util.List;
+
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.TermQuery;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.search.Search;
+import org.hibernate.search.test.SearchTestCase;
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class ImplicitIdTest extends SearchTestCase {
+
+ /**
+ * Tests that @DocumentId is optional. See HSEARCH-104.
+ *
+ * @throws Exception in case the test fails.
+ */
+ public void testImplicitDocumentId() throws Exception {
+ Animal dog = new Animal();
+ dog.setName( "Dog" );
+
+ Session s = openSession();
+ Transaction tx = s.beginTransaction();
+ s.save( dog );
+ tx.commit();
+ s.clear();
+
+ tx = s.beginTransaction();
+ List results = Search.getFullTextSession( s ).createFullTextQuery(
+ new TermQuery( new Term( "name", "dog" ) )
+ ).list();
+ assertEquals( 1, results.size() );
+ tx.commit();
+ s.close();
+ }
+
+ protected Class[] getMappings() {
+ return new Class[] {
+ Animal.class
+ };
+ }
+}
\ No newline at end of file
Property changes on: search/trunk/src/test/org/hibernate/search/test/id/ImplicitIdTest.java
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:mergeinfo
+
More information about the hibernate-commits
mailing list