-->
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.  [ 12 posts ] 
Author Message
 Post subject: Custom type for nullable boolean
PostPosted: Tue Jul 31, 2007 7:28 am 
Beginner
Beginner

Joined: Mon Aug 02, 2004 1:08 pm
Posts: 42
I have a primitive boolean property which maps to the nullable database column. I assume that NULL means false. I've found this in the FAQ:

Quote:
If your object has a primitive-type property mapped to a nullable database column then you will need to use a Hibernate custom type to assign a sensible default (primitive) value for the case of a null column value.


My first question: how is this supposed to be done considering that all the nullSafeSet/nullSafeSet methods are declared final in the NullableType? Should I reimplement/copypaste the whole type hierarchy (NullableType, PrimitiveType and so on)?

Okay, I've done that. And then I have found out that my type does not work in queries. Namely, BooleanLiteralNode throws CCE:

Caused by: java.lang.ClassCastException: de.disy.preludio2.hibernate.type.PrimitiveBooleanType
at org.hibernate.hql.ast.tree.BooleanLiteralNode.getTypeInternal(BooleanLiteralNode.java:22)
at org.hibernate.hql.ast.tree.BooleanLiteralNode.getRenderText(BooleanLiteralNode.java:44)
...

I've checked the BooleanLiteralNode. For some reason it converts the getDataType() into BooleanType:

Code:
public BooleanType getTypeInternal() {
      return ( BooleanType ) getDataType();
   }


Actually it would have been enough to cast the data type to LiteralType, since objectToSQLString is the only specific operation used:

Code:
public String getRenderText(SessionFactoryImplementor sessionFactory) {
      try {
         return getTypeInternal().objectToSQLString( getValue(), sessionFactory.getDialect() );
      }
      catch( Throwable t ) {
         throw new QueryException( "Unable to render boolean literal value", t );
      }
   }


Does this make sense? Should I file issues in JIRA?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 31, 2007 9:40 am 
Newbie

Joined: Sun Apr 09, 2006 8:38 am
Posts: 14
if you use a primitive boolean, it's always one value or the other.

so when hibernate saves your data, there should always be a value in the database.


so:
1. either you're using a Boolean (object) which can be nullable
and then: use the
<property access="property"
type="java.lang.Boolean" name="available" />
and just implement the logic of null=>false in the getter.

public Boolean getAvailable(){
return this.available==null?Boolean.FALSE:available;
}


2. or you're using the primitive, and you're worried about your column in the database being nullable (in case someone deletes this value not through hibernate or something)in this case you can:
<property
type="java.lang.Boolean" name="available" not-null="true"/>

And the column will not be nullable in the database.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 31, 2007 9:56 am 
Beginner
Beginner

Joined: Mon Aug 02, 2004 1:08 pm
Posts: 42
Assafp wrote:
if you use a primitive boolean, it's always one value or the other.


Not always. I have started getting problems when I extend an existing Hibernate mapping with a new primitive boolean property.

I can't specify the default column value since DDL syntax is different in different databases. (false inder PostgreSQL, 1). So I end up having NULLs in "boolean" columns. An these NULLs can't be loaded by Hibernate.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 31, 2007 10:04 am 
Newbie

Joined: Sun Apr 09, 2006 8:38 am
Posts: 14
Are you talking a case of table per hierarchy, where there are
class A{
String name;
}
class B extende A{
boolean available = false;
}

mapped to the same table?

in this case, rows that represent instances of B will have values in the "available" column,
and instances of class A won't.

But that's ok because when hibernate will load instaces of A,
he won't even look at the value in the "availble" column -
because A doesn't have a property "available"!
That's the whole point behind table-per-hierarchy -
there are many columns, and for each row - hibernate checks according to the class which columns should be selected for the instance.

hope this helps.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 01, 2007 5:25 am 
Beginner
Beginner

Joined: Mon Aug 02, 2004 1:08 pm
Posts: 42
Assafp wrote:
Are you talking a case of table per hierarchy...


No, sorry, this has nothing to do with polymorphism and so on.

My case is as follows:

Entity A with string propeties p and q. The table table_a has columns id, p and q. There is already a bunch of record in the table.

Now for some reason I need to extend entity A with a boolean property r. I add the property and run schema update with Hibernate.

The question is: which values will column r for the old table records have? Obviously if I don't specify <column name="r" default="false"/>, these values will be all NULLs. And Hibernate BooleanType does not handle NULL.

The reason I can't specify default value of the column is because the default value for boolean is different for different databases. 'false' for PostgreSQL, 0 for Oracle.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 20, 2007 2:21 am 
Beginner
Beginner

Joined: Thu Oct 16, 2003 7:25 pm
Posts: 38
Location: New York City
It seems that, even now in mid-07, and using the Hibernate annotations, I cannot find a good way to generate new "default" column values through into my DDL. I am forced to choose between these unfortunate options:

1. Using the EJB3 standard, but "non-portable", columnDefinition attribute on the Column annotation. This is ugly, and in many cases totally not an option, when having to support multiple databases.

2. Modifying the DDL by hand before using on live databases, thereby not allowing the use of any Hibernate-based automatic tools. This also means that the DDL of the schema is not in synch with what Hibernate would produce if left to its own devices; not a pleasant situation to be sure.

3. Making the column nullable, by using a reference type, like Integer, or Boolean. Now, strictly speaking in Java beans, the standard boolean/Boolean rules are a little crazy, and stupid IMHO. Only bean properties that are the primitive "boolean" are allowed to use the accessor "is<property>" method name format. Properties that are of the reference type Boolean are not allowed to use this bean-convention method name. And this means that, if you happen to try and use these Hibernate beans on JSP pages, or in EL/MVEL/OGNL expressions, et.al., Boolean property accessors have unfortunate names like "getImageType", when "isImageType" is much more appropriate to the semantics.

Either way, we are forced to compromise.

Can there be a way to specify a column's default value that the various dialects can specify to their heart's content? And can this setting be made settable via a new Hibernate extension annotation named something like "DefaultValue", or "Default" maybe?

Since this is a feature request, should I put this into JIRA?

Tom Harris
mailto://tom@tharrisx.homedns.org
http://www.tharrisx.homedns.org/


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 20, 2007 4:03 am 
Beginner
Beginner

Joined: Mon Aug 02, 2004 1:08 pm
Posts: 42
Hi Tom,

If you're interested I can layout my solution. It's a bit of a hack, but may help you as well.

The problem is that there is no "default" value for properties (which would be DB-portable), there is a "default" value for columns (which is not portable).

So my idea is as follows:

1. In the column's "default" value I specify a Java-side database-independent value of the property. Like "true" or "false" for boolean (no matter which database is in the back-end.
2. During the start-up I post-process the Hibernate mappings and search for single-columned properties with "default" values.
3. For each of these "default" values I first convert the value into the object and then convert the object into the SQL string according to the configured dialect/type.
4. I assign the converted value back to the column's default value.

So I basically convert the database-independent string representations of property values into the database-dependent, according to the configured DB dialect. Like, "false"->Boolean.FALSE->"false" or "false"->Boolean.FALSE->"1" for booleans on different database.

Here's the code, if you're interested.

Code:
   protected void postProcessConfiguration(Configuration configuration)
         throws HibernateException {
      final Dialect dialect = configuration.buildSettings().getDialect();

      for (Iterator i = configuration.getClassMappings(); i.hasNext();) {
         final PersistentClass persistentClass = (PersistentClass) i.next();
         for (Iterator ip = persistentClass.getPropertyIterator(); ip
               .hasNext();) {
            final Property property = (Property) ip.next();
            if (property.getColumnSpan() == 1) {
               final Column column = (Column) property.getColumnIterator()
                     .next();
               if (column.getDefaultValue() != null &&

               property.getType() instanceof LiteralType
                     && property.getType() instanceof NullableType) {
                  final String defaultValue = column.getDefaultValue();
                  final LiteralType literalType = (LiteralType) property
                        .getType();
                  final NullableType nullableType = (NullableType) property
                        .getType();

                  Object object = nullableType
                        .fromStringValue(defaultValue);
                  //                  
                  try {
                     String string = literalType.objectToSQLString(
                           object, dialect);
                     column.setDefaultValue(string);
                  } catch (Exception ex) {
                     throw new HibernateException(ex);
                  }
               }

            }
         }
      }
   }


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 20, 2007 4:42 am 
Beginner
Beginner

Joined: Thu Oct 16, 2003 7:25 pm
Posts: 38
Location: New York City
Is this "default" settable via an annotation? I can't find it anywhere. Do you mean the columnDefinition? That's the only non-portable column attribute i can find.

Tom


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 20, 2007 5:02 am 
Beginner
Beginner

Joined: Mon Aug 02, 2004 1:08 pm
Posts: 42
Yes, must be in columnDefinition.
I'm using HBMs, not annotations - but this must be analogous.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 20, 2007 12:57 pm 
Beginner
Beginner

Joined: Thu Oct 16, 2003 7:25 pm
Posts: 38
Location: New York City
This is a good workaround for the missing feature, and I'll take it, thanks!

But, my request for an HBM attribute and associated annotation are not satisfied by the workaround, and I still suggest this feature be added.

Tom


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 20, 2007 4:03 pm 
Beginner
Beginner

Joined: Mon Aug 02, 2004 1:08 pm
Posts: 42
+1 from me.


Top
 Profile  
 
 Post subject: Re: Custom type for nullable boolean
PostPosted: Tue Dec 29, 2009 5:08 pm 
Newbie

Joined: Tue Dec 29, 2009 5:05 pm
Posts: 1
+1 for me too, JIRA created:
http://opensource.atlassian.com/project ... e/HHH-4743


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 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.