Bug 833393 - "Example 1.7. Using JPA to create and execute a search" java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
"Example 1.7. Using JPA to create and execute a search" java.lang.ClassCastE...
Status: CLOSED CURRENTRELEASE
Product: JBoss Enterprise WFK Platform 2
Classification: JBoss
Component: doc-Hibernate-Search-Guide (Show other bugs)
2.0.0.GA
Unspecified Unspecified
unspecified Severity high
: GA
: 2.1.0
Assigned To: WFK Docs Team
Marek Schmidt
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2012-06-19 07:53 EDT by Marek Schmidt
Modified: 2013-06-27 08:17 EDT (History)
4 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2013-06-27 08:17:08 EDT
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)
source code of the example (85.71 KB, application/x-gzip)
2012-06-19 08:04 EDT, Marek Schmidt
no flags Details

  None (edit)
Description Marek Schmidt 2012-06-19 07:53:38 EDT
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 08:04:28 EDT
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 08:17:19 EDT
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 08:31:58 EDT
(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 09:22:03 EDT
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 03:34:07 EDT
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-12 20:11:11 EST
Marek - Those changes should be done now.
Comment 8 Marek Schmidt 2012-11-26 03:43:36 EST
Verified for WFK 2, Revision 2-0

Note You need to log in before you can comment on or make changes to this bug.