I'm puzzled by what I had to do to get this code to work. It seems as if the compiler optimized away a type conversion that I needed, or there's something else I don't understand here.
I have various objects that are stored in the database that implement the interface Foo
. I have an object, bar
, which holds data I'm using to retrieve my Foo
objects. bar
has these methods:
Class getFooClass()
Long getFooId()
I pass the class and ID to a method with this signature, which delegates to hibernate which retrieves the subject based on its class and ID:
public <T> T get(Class<T> clazz, Serializable id);
There are different implementers of Foo
, and some of these hibernate objects have a Long
id, and others have an Integer
id. Although this method accepts either, farther down it had better have the right one. So when I tried to call get()
on an object with an Integer
id, as follows, I understandably got an error complaining that I had provided a Long
where an Integer
was required:
get(bar.getFooClass(), bar.getFooId());
There's no hibernate problem here, I just need to provide an Integer
where an Integer
id is required and a Long
where a Long
id is required. So I added a method to bar
, hasLongId()
, and tried this: (at this point you may be thinking this isn't a good design, but that's not my question right now)
get(bar.getFooClass(),
bar.hasLongId() ? bar.getFooId() : bar.getFooId().intValue());
And it still complained that I had provided a Long
. That seemed strange. Then I tried this:
get(bar.getFooClass(),
bar.hasLongId() ? bar.getFooId()
: new Integer(bar.getFooId().intValue()));
Same error! How can this be? So I stepped through in the debugger, and yes, it stepped through intValue()
and also through the Integer
constructor, but then in the get method, the passed parameter was in fact a Long
—the same Long
object that was returned from getFooId()
.
I don't understand what's happening, so I just try various things:
Integer intId = bar.getFooId().intValue();
get(bar.getFooClass(), bar.hasLongId() ? bar.getFooId() : intId);
// same error
and
Serializable id = bar.hasLongId() ? bar.getFooId()
: new Integer(bar.getFooId().intValue());
get(bar.getFooClass(), id);
// same error
And finally:
Serializable id;
if (bar.hasLongId()) {
id = bar.getFooId();
} else {
id = bar.getFooId().intValue();
}
get(bar.getFooClass(), id);
This one works. So apparently it has something to do with the ternary operator. But why? Can someone explain what happened here?