Hi,
So in response to my previous mail, I’ve
applied a short fix for IdentifierGeneratorFactory to enable custom types to be
used for auto-generated keys.
Here’s IdentifierGeneratorFactory’s
modified public static Serializable get(….) method, which was extended
based on the 3.3.1.GA release:
public static
Serializable get(ResultSet rs, Type type) throws SQLException,
IdentifierGenerationException {
Class
clazz = type.getReturnedClass();
if ( clazz
== Long.class ) {
return
new Long( rs.getLong( 1 ) );
}
else if (
clazz == Integer.class ) {
return
new Integer( rs.getInt( 1 ) );
}
else if (
clazz == Short.class ) {
return
new Short( rs.getShort( 1 ) );
}
else if (
clazz == String.class ) {
return
rs.getString( 1 );
}
else {
// try
to instantiate the custom type through reflection
try {
Constructor<?>[] constructors =
type.getReturnedClass().getConstructors();
for
(Constructor<?> constructor : constructors)
{
Class<?>[] parameterTypes = constructor.getParameterTypes();
if
(parameterTypes.length == 1)
if (Long.class.equals(parameterTypes[0]))
return
(Serializable) constructor.newInstance(rs.getLong(1));
else if
(Integer.class.equals(parameterTypes[0]))
return (Serializable) constructor.newInstance(rs.getInt(1));
else if (Short.class.equals(parameterTypes[0]))
return (Serializable) constructor.newInstance(rs.getShort(1));
else if (String.class.equals(parameterTypes[0]))
return (Serializable) constructor.newInstance(rs.getString(1));
}
} catch (Throwable t) {
throw new
IdentifierGenerationException( "Error instantiating custom type: " +
type + " with value class: " + type.getReturnedClass(), t );
}
throw new
IdentifierGenerationException( "Supplied custom type doesn't have a
1-argument constructor which could take either long, integer, short or string:
" + type.getReturnedClass().getName() );
}
}
So this would allow you to use any class for an
auto-generated ID, for example:
public class
UniqueInteger implements Serializable {
private Integer internal;
public UniqueInteger()
{
}
public UniqueInteger(Integer
internal)
{
this.internal = internal;
}
}
The only requirement is that it should have a 1-argument
constructor that can take either long, integer, short or string.
Which I think makes sense.
Please submit your feedback and thoughts on this!
--Dávid
From: Nádaski Dávid
[mailto:david@aquilanet.hu]
Sent: Wednesday, December 10, 2008
7:23 AM
To: '
Subject: Using custom types for
auto-generated id columns
Hi,
I was trying to use a custom type for which there was a
valid Type implementation, and have run into the following error:
28240 [http-8080-1] ERROR org.hibernate.event.def.AbstractFlushingEventListener
- Could not synchronize database state with session
org.hibernate.id.IdentifierGenerationException: this id
generator generates long, integer, short or string
at
org.hibernate.id.IdentifierGeneratorFactory.get(IdentifierGeneratorFactory.java:116)
etc.
I’m using MySQL.
Looking at the source, it seems like Hibernate doesn’t
support anything other than a “long, integer, short or string”.
In the parameters of
IdentifierGeneratorFactory.get(….), there’s one called “Type
type”. This gets mapped correctly to my custom, but since that’s
none of those “primitive” types, I get the error – but since
the Type information is available, it could easily be used to map say a String
using Type.nullSafeGet(ResultSet rs, String[] names, SessionImplementor
session, Object owner), since we have both the ResultSet and the Type parameter
available in IdentifierGeneratorFactory.get(ResultSet rs, Type type). So then,
the proper custom type could be returned if it indeed supports this kind of
mapping (which is by definition it’s job).
So I propose a patch should be made to
IdentifierGeneratorFactory that would enable the use of custom types for
identity-generated columns.
It’s possible that I’m missing something, in that
case please point out my error.
Upon request, I think I can supply the appropriate patch,
although it seems easy to code.
Thanks,
David