-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: Criteria.list() should throw exception for unmapped entity?
PostPosted: Thu Jul 14, 2005 7:25 pm 
Newbie

Joined: Thu Jul 14, 2005 6:35 pm
Posts: 2
Location: Virginia, USA
Summary
Calling Criteria.list() on an unmappped entity class does not throw a MappingException. Admittedly this was my fault, since I had forgotten to add a new persistent class to the Hibernate configuration. However, if you call Session.get(MyClass.class, id) when MyClass is not mapped it correctly throws a MappingException. My problem was that I was creating a Criteria query to build a dynamic query and then calling the list() method. I did not get a MappingException, no SQL was shown with hibernate.show_sql=true, and it always returned a List with zero results. Two hours later I figured out it was my fault that the class wasn't in the Hibernate configuration. Doh. Anyway, though this occurs if you have an invalid configuration (an unmapped entity class), I would think Criteria.list() would throw a MappingException just as calling Session.get() does.

Hibernate version:
2.1.8, 3.0.5

b]Name and version of the database you are using:[/b]
Oracle 9, HSQL 1.7.3

Mapping documents and Java code:
Same as sample application that comes with Hibernate distribution, except add a Person.java and Person.hbm.xml to the org.hibernate.auction package.

Person.java
Code:
package org.hibernate.auction;

public class Person extends Persistent {
    private String firstName;
    private String lastName;

    public Person() {}

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String toString() {
        StringBuffer buf = new StringBuffer().append(firstName).append(' ').append(lastName);
        return buf.toString();
    }

}


Person.hbm.xml
Code:
<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<!-- Change DOCTYPE to 2.0 DTD when testing against 2.1.8 -->

<hibernate-mapping
   package="org.hibernate.auction">
   <class name="Person" table="Person">
      <id name="id">
         <generator class="native"/>
      </id>
      <property name="firstName"/>
      <property name="lastName"/>
   </class>
</hibernate-mapping>


More Code

Go into the Main.java file in the sample application and add the following methods:

Code:
public void createTestPersons() throws Exception {
    System.out.println("Setting up some test data");

    Session s = factory.openSession();
    Transaction tx = s.beginTransaction();

    Person person1 = new Person("Bob", "Smith");
    s.save(person1);
    Person person2 = new Person("Joe", "Smith");
    s.save(person2);
    Person person3 = new Person("Jane", "Johnson");
    s.save(person3);
    Person person4 = new Person("Sally", "Jones");
    s.save(person4);

    tx.commit();
    s.close();
}

public void viewAllPersons() throws Exception {
    System.out.println("Viewing all Person objects");

    Session s = factory.openSession();
    Transaction tx = null;
    try {
        s.setFlushMode(FlushMode.NEVER);
        tx = s.beginTransaction();
        Criteria criteria = s.createCriteria(Person.class);
        List persons = criteria.list();
        System.out.println("Found " + persons.size() + " persons!");
        Iterator iter = persons.iterator();
        while (iter.hasNext()) {
            Person person = (Person)iter.next();
            System.out.println("Found person " + person.getId() + ": " + person);
        }
        tx.commit();
    }
    catch (Exception e) {
        if (tx != null) tx.rollback();
        throw e;
    }
    finally {
        s.close();
    }
}

public void viewSinglePerson(Long id) throws Exception {
    System.out.println("Viewing Person object with id " + id);

    Session s = factory.openSession();
    Transaction tx = null;
    try {
        s.setFlushMode(FlushMode.NEVER);
        tx = s.beginTransaction();
        Person person = (Person)s.get(Person.class, id);
        System.out.println("Person with id " + id + ": " + person);
        tx.commit();
    }
    catch (Exception e) {
        if (tx != null) tx.rollback();
        throw e;
    }
    finally {
        s.close();
    }
}


Now replace the sample app's main() method with the following one:

Code:
public static void main(String[] args) throws Exception {

    final Main test = new Main();

    // Add Person to Configuration
    Configuration cfg = new Configuration()
        .addClass(Person.class)
        .setProperty(Environment.HBM2DDL_AUTO, "create");

    test.factory = cfg.buildSessionFactory();

    // Since we mapped Person above in the Configuration, these are fine
    System.out.println("1. Test with Person mapped in Configuration.");
    test.createTestPersons();
    test.viewAllPersons();
    test.viewSinglePerson(new Long(1));

    test.factory.close();

    // Now produce "bug" by not mapping Person in Configuration
    System.out.println();
    System.out.println("2. Test with Person NOT mapped in Configuration.");
    cfg = new Configuration()
        .setProperty(Environment.HBM2DDL_AUTO, "create");
    test.factory = cfg.buildSessionFactory();

    System.out.println("Using Criteria.list() to find unmapped Person " +
                       "class should produce a MappingException but does not.");
    test.viewAllPersons();

    // Will produce MappingException using Session.get()
    System.out.println("Using Session.get() to get unmapped Person class " +
                       "does produce a MappingException.");
    try {
        test.viewSinglePerson(new Long(1));
    } catch (Exception e) {
        e.printStackTrace();
    }

    test.factory.close();
}


Output (in both 2.1.8 and 3.0.5):

Now simply run
Code:
ant eg
in either the Hibernate 2.1.8 or 3.0.5 directory. (Oh, don't forget to copy the HSQL JAR into the lib dir.)

Code:
C:\tools\hibernate-3.0.5>ant eg
Buildfile: build.xml
  [taskdef] Could not load definitions from resource checkstyletask.properties. It could not be found.
  [taskdef] Could not load definitions from resource clovertasks. It could not be found.

eg:
    [javac] Compiling 2 source files to C:\tools\hibernate-3.0.5\eg
     [echo] remember to place your JDBC driver in the lib directory
     [java] 1. Test with Person mapped in Configuration.
     [java] Setting up some test data
     [java] Viewing all Person objects
     [java] Found 4 persons!
     [java] Found person 1: Bob Smith
     [java] Found person 2: Joe Smith
     [java] Found person 3: Jane Johnson
     [java] Found person 4: Sally Jones
     [java] Viewing Person object with id 1
     [java] Person with id 1: Bob Smith

     [java] 2. Test with Person NOT mapped in Configuration.
     [java] Using Criteria.list() to find unmapped Person class should produce a MappingException but does not.
     [java] Viewing all Person objects
     [java] Found 0 persons!
     [java] Using Session.get() to get unmapped Person class does produce a MappingException.
     [java] Viewing Person object with id 1
     [java] org.hibernate.MappingException: Unknown entity: org.hibernate.auction.Person
     [java]     at org.hibernate.impl.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:569)
     [java]     at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:62)
     [java]     at org.hibernate.impl.SessionImpl.get(SessionImpl.java:621)
     [java]     at org.hibernate.impl.SessionImpl.get(SessionImpl.java:614)
     [java]     at org.hibernate.auction.Main.viewSinglePerson(Main.java:420)
     [java]     at org.hibernate.auction.Main.main(Main.java:541)
     [echo] for more examples, download the hibernate-examples package

BUILD SUCCESSFUL
Total time: 10 seconds


So in the above you can see that Criteria.list() simply returns an empty list and doesn't throw a MappingException, and that calling Session.get() does throw a MappingException when the Person class is not in the Hibernate configuration. Again, I realize this is my error but I would have found the problem much quicker had it thrown a MappingException.

The call to viewAllPersons() when Person.class is not mapped will not produce a MappingException by calling Criteria.list(). In 2.1.8 Criteria.list() simply calls back to Session.find(CriteriaImpl) so that is where the problem presumably is. It appears that when Session.find(CriteriaImpl) calls factory.getImplementors(), an empty array is returned since there are no mapped classes that extend or implement the Person class. In 3.0.5 Criteria.list() calls back to SessionImpl.list() where the same basic logic occurs.

_________________
Scott Leberknight


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 14, 2005 7:29 pm 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
This board needs more posters like you.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 14, 2005 7:33 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
This is all correct and intended behaviour. Hibernate implements "implicit polymorphism", meaning you can write queries that refer to unmapped classes.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 14, 2005 10:47 pm 
Newbie

Joined: Thu Jul 14, 2005 6:35 pm
Posts: 2
Location: Virginia, USA
Thanks Gavin. I went and read the sections in the Hibernate Reference (Chapter 10. Inheritance Mapping) and in Hibernate in Action (3.6 Mapping class inheritance and 7.2.3 Polymorphic queries). Cannot believe I didn't think of that, but I understand. I still wonder, though, whether it is considered programmer error, as in my case, if you issue a query and there are no persistent classes that implement an interface or subclass the specified class, e.g.

Code:
session.new Criteria(MyClass.class).list();


In other words, if Hibernate knows there is no chance of ever getting any results for a given class, should it issue a warning or is it simply my problem and not Hibernate's to deal with? Sorry in advance if this simply restates the original question.

_________________
Scott Leberknight


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 02, 2005 10:10 am 
Newbie

Joined: Mon Aug 01, 2005 5:47 pm
Posts: 4
Location: Austin, TX, USA
It is also entirely possible - from Hibernate's perspective - that you're setting that List externally from Hibernate and want to retrieve it as well. That would require an unmapped Collection just as you described.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.