It all started one day when I saw this in our codebase (revision 8378):
//...[snip]...
List<Long> someIds = getSomeIds(1234);
if (someIds.contains( Integer.valueOf( something.getLongId().intValue() ) )) {
//...
}
}
//...[snip]...
Since I know that all of our ID fields in our classes are of type Long, and the someIds collection is a List of Longs, why do we need to have an Integer and an intValue() in there? I figured out which developer added it and asked him about it. He said it was needed because otherwise the contains() didn't work and had no explanation. He showed me the JUnit test and the variable values from inside the debugger. He agreed it didn't make much sense. And you can see from the line above that we should be dealing with Longs.
So, let's look at where the List
//...[snip]...Okay, so we're getting the values from Hibernate. Note how we're using an SQL query rather than an HQL query. (Some of the developers here are kinda old-fashioned that way.) Turns out that it has to do with Hibernate deciding that the values that come back from the query should be of type Integer. I really don't have a problem with that -- We should be using HQL and real objects and if I had thought about it more I would have realized when the project began that a couple billion (MAX_INT) is enough for this particular ID.
@SuppressWarnings("unchecked")
private List<Long> getSomeIds(Long recordId) {
List<Long> results =
getSession()
.createSQLQuery("SELECT id FROM records WHERE rec_id = :recordId")
.setLong("recordId", recordId)
.list();
return Collections.unmodifiableList(results);
}
//...[snip]...
So anyway, the list() method isn't specifying a type. And at runtime the type declaration on the results variable is already erased so the JVM doesn't have a problem putting Integers into that variable even though we want Longs. A little change to the return parameter type and at least we're no longer lying to ourselves. The code is a little prettier today than it was yesterday.
I've noticed that we really enjoy using @SuppressWarnings("unchecked")... Maybe we should see a psychiatrist about that.
Why does hibernate decide to return Ints?
ReplyDeleteAh, I should have explained that in the post. Hibernate picks the datatype for the return value based on column type defined in the database. I'm sure these mappings can be overridden in some configuration somewhere, but the defaults are usually pretty good. I didn't see any quick reference on the Hibernate site, but the Manning book Java Persistence with Hibernate by Christian Bauer and Gavin King, page 214, has a nice reference table with what the default, built-in mapping types are for type database column types. (P.S. All Hibernate developers should own that book).
ReplyDeleteReally, I think the takeaway lesson from this is that it's better to use HQL whenever possible because then the results will always match the datatypes defined in the class.