I haven’t fully thought it out yet, but are you SURE you want <? super BEANTYPE> as your generic parameter in BeanItemContainer?
The change from 6.4.9 to 6.5.0 breaks my application, which previously was supplying a parameter that matched <? extends BEANTYPE>. I’m not sure of the reason for the API change. Could someone elaborate, please?
My use case that I can’t–I don’t think–implement with 6.5.0’s new generic contract here:
I have an interface, call it T.
I have a factory that vends instances of that interface. I can get the implementation class from the factory, and when I do it comes back as a Class<? extends T>, as it should.
I then (used to) pass this Class<? extends T> into a BeanItemContainer. In 6.4.9, the contract for the constructor took a Class<? extends T>. But now it takes a Class<? super T>. I can’t reliably or safely cast this class to a Class<? super T>, because that doesn’t really make any sense.
Just checked out the 7.0 branch, and it looks like the constructor signature in question has reverted back to BeanItemContainer(Class<? extends BT>). A bit confused here.
Folks on IRC think that perhaps the 7.0 branch just hasn’t been updated with the 6.5 code.
So, assuming that the 6.5 branch code is correct, then I just want to make sure that people understand that Class<? super Fred> does NOT mean the set of classes that includes Fred.class and its subclasses–this means the set of classes that includes Fred.class and its SUPERclasses.
So, for example, something accepting a Class<? super BigDecimal> would accept BigDecimal.class, Number.class, Serializable.class, and Object.class. It would not accept MyHypotheticalBigDecimalSubclass.class.
Or: an argument of type Class<? super Serializable> will accept Object.class and Serializable.class. That’s it. It will not accept, say, String.class, Number.class, and so on (or any other subtype of Serializable). Similarly, if I have a Serializable object and I try to use its getClass() method to come up with the type, that won’t work either:
final Serializable someObject = mySerializableFactorySomewhere.produceSerializable();
assert someObject != null;
final Class<? extends Serializable> hisClass = someObject.getClass();
final BeanItemContainer<Object, Serializable> container = new BeanItemContainer<Object, Serializable>(hisClass); // compilation error
I’m still trying to figure out whether this API change was totally deliberate (in which case my entire application is broken, since I rely upon feeding the result of someObject.getClass() to the constructor of BeanItemContainer (and Object.getClass() returns a Class<? extends T>, not a Class<? super T>)), or whether it was due to a (very common) misunderstanding of the difference between super and extends with regard to generics.
My sincere apologies if of course I’m way off base and the Vaadin knows this distinction well and is instead supporting a different set of use cases.
Now you create a BeanItemContainer(C.class), where T is the type of beans you can add to, retrieve from and remove from the container and C is the class that defines what properties exist in the container. There are a couple of ways you can mix the classes the make a BeanItemContainer:
new BeanItemContainer(Fruit.class) - The container contains Fruits and the properties come from the Fruit class. Makes sense. Similar for all cases when the arguments match.
new BeanItemContainer(Orange.class) - Obviously makes no sense as an Apple does not necessary contain the same properties as an Orange, allows adding Apples, returns Apples instead of Oranges and so on
new BeanItemContainer(Fruit.class) - Class C is a super class of T. Defines that the container contains Apples but only the Fruit properties are used. Maybe not very useful but correct since the Fruit properties are always in an Apple. The same end result can usually be achieved using new BeanItemContainer(Apple.class) and hiding/ignoring some properties.
new BeanItemContainer(Apple.class) - Similar to using an interface and its implementor. This is wrong because the properties come from Apple but you are allowed to add an Orange aswell to the container (it extends Fruit). Adding an orange will fail at runtime because it is not an Apple and does not contain the same properties.
Case 1) should be the most typical and what you want to use. It is still possible to create an unchecked / unsafe container instance like new BeanItemContainer(Apple.class) (case 4) but BeanItemContainer will no longer hide the unsafe cast. For instance
BeanItemContainer c = new BeanItemContainer(Apple.class);
should work just fine. If you do not want to rely on the implementor of your interface you can of course do new BeanItemContainer(Fruit.class) instead.
What if–again–I don’t know the implementation class at compile time? That is, what if I cannot supply Apple.class, because the implementation class is deliberately bound at runtime?
That is, if instead of Apple.class all I have in my hand is Class<? extends Fruit>? What do I do with that? I can’t supply it to a Class<? super Fruit> argument. I don’t want to pass Fruit.class instead, because then my UI widgets bound to the container will not have the opportunity to show the properties known only to the implementation class.
In the new API, the only possibility I have is to supply Fruit.class. This means that the introspected properties will not contain extra properties defined by my implementation class. I think this was a mistake in the API.
To look at it another way: there is no API in the JDK that will return a Class<? super Anything>. But there are tons of APIs that, when supplied with a T, will return a Class<? extends T>. There is a good reason for this. Among other things, this means that I will NEVER have a Class in my hand that will meet the BeanItemContainer contract if that Class is not a literal. That is, if I get a Class from a method in pretty much any library on the planet it will be a Class<? extends T>. The only way to pass something to this new BeanItemContainer constructor is to pass it a class literal (e.g. Apple.class, Fruit.class), and at runtime I don’t have that.
If you do not know the class you want to use the properties from at compile time it’s not possible to use a generic type without an unsafe cast. This is proper behavior because indeed it is unsafe to use a BeanItemContainer like
new BeanItemContainer<Interface>(Implementor.class)
as there is no way that BeanItemContainer or Java can know that Implementor is the only class that implements Interface. For read operations it does not matter because they will always be castable to the Interface. For add operations on the other hand it is not safe because all implementors cannot necessarily be cast to the given Implementor class (and do not contain the same properties etc.).
The difference to Java collections and similar is that they do not care about the contents/fields/properties of the added object whereas BeanItemContainer needs to read the properties from the added object and do that in a consistent way. Therefore the restrictions differ.
If you know that you have only one class that implements the interface or that you are only adding instances of that class you can always do the unsafe cast, like:
BeanItemContainer<Fruit> c2 = new BeanItemContainer(Apple.class)
This will use the properties from Apple but also produce a compiler warning as it should.
PS. How do you use the methods/properties from the implementing class in the rest of your code if they are not found from the interface and you do not know the implementing class at compile time?
Think of a Person interface that I define. It has a getName()/setName() property.
Now think of a DetailedPerson class that you define that implements that interface. You add a getShoeSize()/setShoeSize() property. Using dependency injection or finder methods or lookup strategies or whatever you manage to get instances of your class vended as implementations of my interface.
In Swing–forget Vaadin for a moment–if I have a table model build itself from your class, then you have an opportunity to describe that property you made. You can do so via a number of different mechanisms; I’m most familiar with BeanInfo, PropertyDescriptors and PropertyEditors.
So in Swing, I introspect your class using Introspector.getBeanInfo(yourClass). Then I walk through the property descriptors. If any are marked hidden, then I don’t show them. I invoke property editors (which you, again, supply) for each property. The end result is a table that is capable of presenting the shoe size property, validating edits for it, etc. etc. and my app didn’t need to know a thing about it.
I am trying to bring the same level of functionality to Vaadin, and was pretty much there with 6.4.9.
It’s illustrative to me that you guys have the same sorts of issues. See, for example, line 123 of BeanItemContainer in the 6.5 branch. You have to cast a return value of Class<? extends BEANTYPE> to Class.