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?