Friday, May 09, 2014

Why Hibernate is a disaster

I am forced to work with this Java Object Relational Mapping “solution” (a collection of functions, annotations and configuration hell to try to fit the round peg of object oriented programming into the square hole of relational databases) for the next 4 months (2 already done - luckily). And I really have not much to say in its favor.

  • Read http://empire-db.apache.org/empiredb/hibernate.htm: The use of annotations and strings to provide information is a bad choice. The former because it cannot be modified or easily read at runtime (only through awkward interfaces), the latter because it is only checked at runtime, which means never for the 90% of the code that are run 10% of the time (don’t comment with “well you need unit tests”).

  • The developers of Hibernate have never heard of the Law of Demeter.

    session.buildLockRequest().setLockMode(LockMode.PESSIMISTIC_WRITE).setTimeOut(1000 * 60).lock(entity);
    

    They used method chaining (the “builder pattern”) extensively.
    http://stackoverflow.com/questions/1103985/method-chaining-why-is-it-a-good-practice-or-not

  • The Criteria API is a distaster http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch12.html
    Tell me you get what these queries do without looking at the documentation:

    CriteriaQuery criteria = builder.createTupleQuery();
    Root personRoot = criteria.from( Person.class );
    Path idPath = personRoot.get( Person_.id );
    Path agePath = personRoot.get( Person_.age );
    criteria.multiselect( idPath, agePath );
    criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
    
    List tuples = em.createQuery( criteria ).getResultList();
    
    CriteriaQuery query = builder.createQuery();
    Root men = query.from( Person.class );
    Root women = query.from( Person.class );
    Predicate menRestriction = builder.and(
      builder.equal( men.get( Person_.gender ), Gender.MALE ),
      builder.equal( men.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE )
    );
    Predicate womenRestriction = builder.and(
      builder.equal( women.get( Person_.gender ), Gender.FEMALE ),
      builder.equal( women.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE )
    );
    
    query.where( builder.and( menRestriction, womenRestriction ) );
    

    and even if you do, tell me why I have to call “builder.” all the time.
    Well that’s because Java just wasn’t made for building code like that - which should have been clear from the start.
    Their older api seems to have been slightly better:

    List cats = sess.createCriteria(Cat.class)
        .add( Restrictions.like("name", "Fritz%") )
        .add( Restrictions.or(
            Restrictions.eq( "age", new Integer(0) ),
            Restrictions.isNull("age")
        ) )
        .list();
    
    List cats = sess.createCriteria(Cat.class)
        .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
        .add( Restrictions.disjunction()
            .add( Restrictions.isNull("age") )
            .add( Restrictions.eq("age", new Integer(0) ) )
            .add( Restrictions.eq("age", new Integer(1) ) )
            .add( Restrictions.eq("age", new Integer(2) ) )
        ) )
        .list();
    

    But what does the word “Criteria” have to do with the notion of a database query?

  • Of their guides and docs I have looked at, the “Getting started guide (brief)” is a joke, “Getting started guide (full)” too and “Developer’s Guide” is hard to read, incomplete and full of spelling mistakes.

  • The javadoc documentation for the most important class “Session” is poorly written, e.g. referring to this interchangably (and patternless) with any of “the current session”, “this current session”, “the session”, “this session”.
  • From the javadoc

    Change the default for entities and proxies loaded into this session
    from modifiable to read-only mode, or from modifiable to read-only
    mode.

    (Yes, it is twice the same.)

  • Flags are either documented as “Checks” or Questions:

    Session::isConnected()
    Check if the session is currently connected.

    Session::isDefaultReadOnly()
    Will entities and proxies that are loaded into this session be made read-only by default?

    (not to mention that javadoc doesn’t recognize the ? as ending a sentence and therefore goes on to find the next dot).

  • Spelling mistakes even in the javadoc: In Hibernate.Query:

    … to Hibernate types using hueristics.

  • In Query, the methods taking LockMode are not deprecated, unlike in Session.

  • Everything throws HibernateException, there is no way to differentiate between these programmatically excpet with their message strings - for which of course you will only know (if you are lucky) at runtime that you spelled them wrong.

  • getNamedParameters()
    Return the names of all named parameters of the query.

    Obviously, this method should have been called getNamedParameterNames() [let’s not discuss the poor naming choice], then the documentation would be moot. But if I read get(Named)Parameters, I think of getting their values.

  • The forum consists only of spam (first non-sticky entry in “Hibernate Users”: “Watch Frozen Online Free”). Which is also why I did not post all of that there.

I think I could go on. Unfortunately I don’t have the time nor the creativity to write as entertaining a rant as “PHP A fractal of bad design
Maybe I will wrap this up one more time once I’m done with it.

PS: Wow, the blogspot editor is annoying to use too, copying the style of the text I paste - can I turn that off? Please forgive the terrible formatting.

Edit: Now using https://stackedit.io to write my entries with markdown.

No comments:

Post a Comment