Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.

Bug 833393

Summary: "Example 1.7. Using JPA to create and execute a search" java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
Product: [Retired] JBoss Enterprise WFK Platform 2 Reporter: Marek Schmidt <maschmid>
Component: doc-Hibernate-Search-GuideAssignee: WFK Docs Team <wfk-docs>
Status: CLOSED CURRENTRELEASE QA Contact: Marek Schmidt <maschmid>
Severity: high Docs Contact:
Priority: unspecified    
Version: 2.0.0.GACC: misty, myarboro, ppenicka, sanne
Target Milestone: GA   
Target Release: 2.1.0   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2013-06-27 12:17:08 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
source code of the example none

Description Marek Schmidt 2012-06-19 11:53:38 UTC
Description of problem:

Recreating a simple hibernate search application based "JavaEE Web Project" and "Example 1.7. Using JPA to create and execute a search" in the Hibernate Search guide

http://documentation-stage.bne.redhat.com/docs/en-US/JBoss_Web_Framework_Kit/2/html-single/Hibernate_Search/index.html#id3910797

doesn't work properly.

I have added the hibernate search annotations to the Member entity and created a new field to verify the @DateBridge:

@Entity
@XmlRootElement
@Table(uniqueConstraints = @UniqueConstraint(columnNames = "email"))
@Indexed
public class Member implements Serializable {
   /** Default value included to remove warning. Remove or modify at will. **/
   private static final long serialVersionUID = 1L;

   @Id
   @GeneratedValue
   private Long id;

   @NotNull
   @Size(min = 1, max = 25)
   @Pattern(regexp = "[A-Za-z ]*", message = "must contain only letters and spaces")
   @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
   private String name;

   @NotNull
   @NotEmpty
   @Email
   @Field(index=Index.YES, analyze=Analyze.NO, store=Store.NO)
   private String email;

   @NotNull
   @Size(min = 10, max = 12)
   @Digits(fraction = 0, integer = 12)
   @Column(name = "phone_number")
   @Field(index=Index.YES, analyze=Analyze.NO, store=Store.NO)
   private String phoneNumber;
   
   @Field(index=Index.YES, analyze=Analyze.NO, store=Store.YES)
   @DateBridge(resolution=Resolution.DAY)
   private Date dateOfBirth;
...

and created a search method as described in the example from the Hibernate Search guide:

public List<Member> search(String queryString) {
      FullTextEntityManager fullTextEntityManager = 
            org.hibernate.search.jpa.Search.getFullTextEntityManager(em);

        // create native Lucene query unsing the query DSL
        // alternatively you can write the Lucene query using the Lucene query parser
        // or the Lucene programmatic API. The Hibernate Search DSL is recommended though
        QueryBuilder qb = fullTextEntityManager.getSearchFactory()
            .buildQueryBuilder().forEntity( Member.class ).get();
        org.apache.lucene.search.Query query = qb
          .keyword()
          .onFields("name", "email", "dateOfBirth")
          .matching(queryString)
          .createQuery();

        // wrap Lucene query in a javax.persistence.Query
        javax.persistence.Query persistenceQuery = 
            fullTextEntityManager.createFullTextQuery(query, Member.class);

        // execute search
        List<Member> result = (List<Member>)persistenceQuery.getResultList();

        return result;
   }


The following exception is shown when searching for "John", as the QueryBuilder.createQuery fails with ClassCastException:

java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
	org.hibernate.search.bridge.builtin.DateBridge.objectToString(DateBridge.java:88)
	org.hibernate.search.bridge.builtin.impl.TwoWayString2FieldBridgeAdaptor.objectToString(TwoWayString2FieldBridgeAdaptor.java:48)
	org.hibernate.search.bridge.util.impl.ContextualExceptionBridgeHelper$TwoWayConversionContextImpl.objectToString(ContextualExceptionBridgeHelper.java:146)
	org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity.objectToString(DocumentBuilderIndexedEntity.java:373)
	org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity.objectToString(DocumentBuilderIndexedEntity.java:743)
	org.hibernate.search.query.dsl.impl.ConnectedMultiFieldsTermQueryBuilder.buildSearchTerm(ConnectedMultiFieldsTermQueryBuilder.java:141)
	org.hibernate.search.query.dsl.impl.ConnectedMultiFieldsTermQueryBuilder.createQuery(ConnectedMultiFieldsTermQueryBuilder.java:95)
	org.hibernate.search.query.dsl.impl.ConnectedMultiFieldsTermQueryBuilder.createQuery(ConnectedMultiFieldsTermQueryBuilder.java:81)
	org.jboss.tools.examples.service.MemberSearch.search(MemberSearch.java:39)


Also, searching for an empty string or a string that is analysed as an empty query (such as stoplist words "a","an","and",..) will throw a org.hibernate.search.SearchException: Try to search with an empty string: name

The example in the documentation should be fixed to show how to use the QueryBuilder properly.

Comment 1 Marek Schmidt 2012-06-19 12:04:28 UTC
Created attachment 592927 [details]
source code of the example

attaching the example (Java EE Web Project + Hibernate Search pieces from the Hibernate Search docs)

Comment 2 Marek Schmidt 2012-06-19 12:17:19 UTC
Sanne, could you please take a look and check whether this is an actual Hibernate Search bug, or if the example should be fixed and how?

Comment 3 Marek Schmidt 2012-06-19 12:31:58 UTC
(note that you need to uncomment the "dateOfBirth" in the  org.jboss.tools.examples.service.MemberSearch class and change the hibernate.search.default.indexBase property in persistence.xml to reproduce the issue in the attached example)

Comment 4 Sanne Grinovero 2012-06-19 13:22:03 UTC
Marek, great catch. Indeed, the example is wrong.

The expected type of the argument for the matching(V) method should match the fields it's targeting *unless* _ignoreAnalyzer()_ is set as well.

So we have these options to fix the example:

1)
org.apache.lucene.search.Query query = qb
          .keyword()
          .onFields("name", "email")
          .matching(queryString)
          .createQuery();

2)
org.apache.lucene.search.Query query = qb
          .keyword()
          .onFields("name", "email", "dateOfBirth")
          .ignoreAnalyzer()
          .matching(queryString)
          .createQuery();

3) Make the example more complex by specifying a bool() Query using _should_ to provide different options to the String fields and the Date field.

I'd sugges solution 1) as it's simpler, and this is the introduction chapter.
The full boolean syntax is explained already in 5.1.2.6. Combining queries.

Thanks, I'll fix the example in the community docs.

Comment 5 Marek Schmidt 2012-06-20 07:34:07 UTC
Note to Bec, (since my example is a bit different than the exact one in the docs)

the lines

.onFields("title", "subtitle", "authors.name", "publicationDate")

should be changed to

.onFields("title", "subtitle", "authors.name")


in the 1.5. Searching chapter, 
"Example 1.6. Using Hibernate Session to create and execute a search"
and
"Example 1.7. Using JPA to create and execute a search"

Comment 6 lpearce 2012-11-13 01:11:11 UTC
Marek - Those changes should be done now.

Comment 8 Marek Schmidt 2012-11-26 08:43:36 UTC
Verified for WFK 2, Revision 2-0