/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.test.query;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.Iterator;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.engine.ProjectionConstants;
import org.hibernate.search.exception.AssertionFailure;
import org.hibernate.search.test.SearchTestBase;
import org.hibernate.search.testsupport.TestForIssue;
import org.junit.Before;
import org.junit.Test;
/**
* Tests all kinds of loading when the entities have public fields.
*
* We take care to test all of those because they trigger different kinds of loading:
* <ul>
* <li>Single result or multiple results
* <li>Single class or multiple classes
* <li>list() without projection, list() with THIS projection, or iterate()
* </ul>
*
* @author Yoann Rodiere
*/
@TestForIssue(jiraKey = "HSEARCH-2541")
public class ObjectLoadingPublicFieldTest extends SearchTestBase {
private Query fieldFooQuery;
private Query fieldBarQuery;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
try ( Session session = openSession() ) {
Transaction tx = session.beginTransaction();
// used for the filtering tests
A a1 = new A();
a1.id = 1L;
a1.field = "foo";
B b = new B();
b.id = 2L;
b.field = "foo";
C c = new C();
c.id = 3L;
c.field = "foo";
session.persist( a1 );
session.persist( b );
session.persist( c );
// used for the not found test
A a2 = new A();
a2.id = 4L;
a2.field = "bar";
session.persist( a2 );
tx.commit();
}
fieldFooQuery = new TermQuery( new Term( "field", "foo" ) );
fieldBarQuery = new TermQuery( new Term( "field", "bar" ) );
}
@Test
public void singleClass_singleResult() throws Exception {
Session session = openSession();
Transaction tx = session.beginTransaction();
FullTextSession fullTextSession = Search.getFullTextSession( session );
FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( fieldFooQuery, A.class );
List<?> result = fullTextQuery.list();
assertEquals( "Should match B only", 1, result.size() );
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( fieldFooQuery, A.class )
.setProjection( ProjectionConstants.THIS );
result = fullTextQuery.list();
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( fieldFooQuery, A.class );
assertPopulated( fullTextQuery.iterate() );
tx.commit();
fullTextSession.close();
}
@Test
public void singleClass_multipleResults() throws Exception {
Session session = openSession();
Transaction tx = session.beginTransaction();
Query luceneQuery = new MatchAllDocsQuery();
FullTextSession fullTextSession = Search.getFullTextSession( session );
FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, A.class );
List<?> result = fullTextQuery.list();
assertEquals( "Should match A only", 2, result.size() );
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, A.class )
.setProjection( ProjectionConstants.THIS );
result = fullTextQuery.list();
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, A.class );
assertPopulated( fullTextQuery.iterate() );
tx.commit();
fullTextSession.close();
}
@Test
public void twoClasses_singleResult() throws Exception {
Session session = openSession();
Transaction tx = session.beginTransaction();
FullTextSession fullTextSession = Search.getFullTextSession( session );
FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( fieldBarQuery, A.class, B.class );
List<?> result = fullTextQuery.list();
assertEquals( "Should match a single A only", 1, result.size() );
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( fieldBarQuery, A.class, B.class )
.setProjection( ProjectionConstants.THIS );
result = fullTextQuery.list();
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( fieldBarQuery, A.class, B.class );
assertPopulated( fullTextQuery.iterate() );
tx.commit();
fullTextSession.close();
}
@Test
public void twoClasses_multipleResults() throws Exception {
Session session = openSession();
Transaction tx = session.beginTransaction();
FullTextSession fullTextSession = Search.getFullTextSession( session );
FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( fieldFooQuery, A.class, B.class );
List<?> result = fullTextQuery.list();
assertEquals( "Should match A and B only", 2, result.size() );
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( fieldFooQuery, A.class, B.class )
.setProjection( ProjectionConstants.THIS );
result = fullTextQuery.list();
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( fieldFooQuery, A.class, B.class );
assertPopulated( fullTextQuery.iterate() );
tx.commit();
fullTextSession.close();
}
@Test
public void threeClasses() throws Exception {
Session session = openSession();
Transaction tx = session.beginTransaction();
FullTextSession fullTextSession = Search.getFullTextSession( session );
FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery(
fieldFooQuery, A.class, B.class, C.class
);
List<?> result = fullTextQuery.list();
assertEquals( "Should match all types", 3, result.size() );
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery(
fieldFooQuery, A.class, B.class, C.class
)
.setProjection( ProjectionConstants.THIS );
result = fullTextQuery.list();
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( fieldFooQuery );
assertPopulated( fullTextQuery.iterate() );
tx.commit();
fullTextSession.close();
}
@Test
public void implicitAllClasses() throws Exception {
Session session = openSession();
Transaction tx = session.beginTransaction();
FullTextSession fullTextSession = Search.getFullTextSession( session );
FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( fieldFooQuery );
List<?> result = fullTextQuery.list();
assertEquals( "Should match all types", 3, result.size() );
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( fieldFooQuery )
.setProjection( ProjectionConstants.THIS );
result = fullTextQuery.list();
assertPopulated( result );
fullTextSession.clear();
fullTextQuery = fullTextSession.createFullTextQuery( fieldFooQuery );
assertPopulated( fullTextQuery.iterate() );
tx.commit();
fullTextSession.close();
}
private void assertPopulated(Iterator<?> iterator) {
while ( iterator.hasNext() ) {
Object result = iterator.next();
assertPopulated( result );
}
}
private void assertPopulated(List<?> results) {
for ( Object result : results ) {
assertPopulated( result );
}
}
private void assertPopulated(Object result) {
if ( result instanceof Object[] ) {
Object[] tuple = (Object[]) result;
if ( tuple.length != 1 ) {
throw new AssertionFailure( "Unexpected tuple size for result " + result );
}
result = tuple[0];
}
if ( result instanceof A ) {
assertNotNull( ((A) result).id );
}
else if ( result instanceof B ) {
assertNotNull( ((B) result).id );
}
else if ( result instanceof C ) {
assertNotNull( ((C) result).id );
}
else {
throw new AssertionFailure( "Unexpected type for result " + result );
}
}
@Override
public Class<?>[] getAnnotatedClasses() {
return new Class[] {
A.class,
B.class,
C.class
};
}
@Entity
@Table(name = "A")
@Indexed
private static class A {
protected A() {
}
@Id
public Long id;
@Field
public String field;
}
@Entity
@Indexed
private static class B {
protected B() {
}
@Id
public Long id;
@Field
public String field;
}
@Entity
@Indexed
private static class C {
protected C() {
}
@Id
public Long id;
@Field
public String field;
}
}