Community
Participate
Working Groups
Created attachment 147564 [details] Test case, several generated models with compilation erros. Recursive bounds on an abstract associations cause compilations errors in model and edit. You will find here attached a test case to reproduce such errors.
I'm having trouble wrapping my mind around the error message. I.e., how does one correctly call this create method? Or in other words, what should we be generating? I suppose it's even possible it's a compiler error...
Created attachment 147593 [details] new test case new test case with no compilation error. However the generic contract is not respected while retrieving the edit newChildDescriptors.
I made a mistake in my modelcore model. A class who should be abstract was a concrete one. Anyway I fixed it and here is a new test case. The second problem I face relies on the extended associations all the possible children are collected. The generic contract is not respected. here is the code snippet : @Override public <T extends ExtensibleModelElement<T>> Object caseExtensibleModelElement(ExtensibleModelElement<T> object) { newChildDescriptors.add (createChildParameter (ModelcorePackage.Literals.EXTENSIBLE_MODEL_ELEMENT__EXTENDEDS, ViewpointperformanceFactory.eINSTANCE.createPerformanceLC())); newChildDescriptors.add (createChildParameter (ModelcorePackage.Literals.EXTENSIBLE_MODEL_ELEMENT__EXTENDEDS, ViewpointperformanceFactory.eINSTANCE.createPerformancePC())); return null; } all the collected newChilsDescriptors are retrieved. T should LC or PC but not both, I guess filtering such things would be nice. Anyway model validation should enforce that rule. I will investigate this one tomorrow. Bye
I imagine this doesn't block anything so I'm reducing the severity. I'm not sure I understand your comment. The children are supposed to include all possible children so I don't understand the comment about it should have one or the other but not both...
(In reply to comment #4) > I imagine this doesn't block anything so I'm reducing the severity. > > I'm not sure I understand your comment. The children are supposed to include > all possible children so I don't understand the comment about it should have > one or the other but not both... LC is a concrete class and a subclass of ExtensibleModelElement. As such the 'extendeds' association is typed with LC. When I work on an instance of LC I expected to see only commands related to LC. However all the commands who create ExtendedModelElement are available. I can populate my containment with all of them with no complain. In this use case children are supposed to include children of their own type. If I don't use generics the result is virtually the same. I hope you have better understanding.
I've come across the same issues over the past couple of days and find it rather frustrating. I have re-created a simple test case based on the article: "Generics in Eclipse Modelling Framework" - http://eclipse.dzone.com/articles/generics-eclipse-modelling-fra?page=0,0 My model consists of the following: EClasses: ModelObject BasketContainer -> ModelObject FoodBasket<F extends Food> -> ModelObject FruitBasket<F extends Fruit> -> FoodBasket<F> AppleBasket -> FruitBasket OrangeBasket -> FruitBasket Food -> ModelObject Fruit -> Food Apple -> Fruit Orange -> Fruit EReferences: BasketContainer contains 0..* FoodBasket<?> FoodBasket<F extends Food> contains 0..* F Now I'm really happy that the eCore model is able to express the specialization that I want in the FoodBasket to Food reference, however I'm disappointed that the generated code fails in the two areas that Xavier mentioned. 1) Type-safety of the getFood() EList This list is created with the top-level class Food as the dataClass for its storage array. You can't really blame them here because Java provides no run-time information on generic types, so how is it to know the actual dataClass of that instance? There is a solution using Java generics that is described in this article "Reflecting generics": http://www.artima.com/weblogs/viewpost.jsp?thread=208860. My test case includes a TypeUtility class that can be used to get a list of all the generic type runtime values (in my case there's just the one - F). I've modified his code a bit so that it returns a list of EClasses instead of classes. Then in the FoodBasket() constructor we can easily ask for the EClass's instance class, which we will use as the dataClass parameter in the getFood EList constructor. 2) ItemProviders present inappropriate NewChildDescriptors resulting in inappropriate CreateChild commands In my case, I should not be allowed to add an Apple to an Orange Basket (and vice versa). If we've implemented the proposal in (1) then the command will still be executable but will throw a runtime exception when the EList tries to add the inappropriate object to its (now) type-safe array. So at least the object doesn't get added and the CommandStack handles the exception gracefully. However, I think we can do better and, furthermore, I think the code generator can do it for us. First of all, the FoodBasketItemProvider.collectNewChildDescriptors looks like this, which means that both Apple and Orange child descriptors will always be added no matter what the base class that initiated the call (e.g. AppleBasketItemProvider) protected void collectNewChildDescriptors(Collection<Object> newChildDescriptors, Object object) { super.collectNewChildDescriptors(newChildDescriptors, object); newChildDescriptors.add (createChildParameter (FoodPackage.Literals.FOOD_BASKET__FOOD, FoodFactory.eINSTANCE.createApple())); newChildDescriptors.add (createChildParameter (FoodPackage.Literals.FOOD_BASKET__FOOD, FoodFactory.eINSTANCE.createOrange())); } I propose that the generator takes the same approach as it does with property descriptors, which is to create a separate, protected function for creating each one. It would look something like this: @Override protected void collectNewChildDescriptors(Collection<Object> newChildDescriptors, Object object) { super.collectNewChildDescriptors(newChildDescriptors, object); addAppleNewChildDescriptor(newChildDescriptors, object); addOrangeNewChildDescriptor(newChildDescriptors, object); } protected void addAppleNewChildDescriptor (Collection<Object> newChildDescriptors, Object object) { newChildDescriptors.add (createChildParameter (FoodPackage.Literals.FOOD_BASKET__FOOD, FoodFactory.eINSTANCE.createApple())); } protected void addOrangeNewChildDescriptor (Collection<Object> newChildDescriptors, Object object) { newChildDescriptors.add (createChildParameter (FoodPackage.Literals.FOOD_BASKET__FOOD, FoodFactory.eINSTANCE.createOrange())); } With this approach we (i.e. the code generator) can override the specific Add???NewChildDescriptor functions. In the case of AppleBasketItemProvider, since AppleBasket specifies that it can contain only Apples, then all other (non-abstract) subclasses of Food must not have a NewChildDescriptor. In our case there is only one: Orange. Here's the overridden function in AppleBasketItemProvider: /* * (non-Javadoc) * @see food.provider.FoodBasketItemProvider#addOrangeNewChildDescriptor(java.util.Collection, java.lang.Object) * * We override this because we don't support creating Oranges in an Apple Basket, so it just doesn't add anything * * Ideally, this would be generated. * In the eCore model we've specified a specific eClassifier (Apple) for the type parameter F, so we need * an overridden method for each of the other subclasses of Fruit */ @Override protected void addOrangeNewChildDescriptor (Collection<Object> newChildDescriptors, Object object) { // Do Nothing } Now when we work our way up the chain of ItemProviders, successively calling super.collectNewChildDescriptors, we eventually get to FoodBasketItemProvider.collectNewChildDescriptors, and when it calls addOrangeNewChildDescriptor then the overriden function in AppleBasketItemProvider is called, thus adding no NewChildDescriptor for Oranges. Well, that's it. I hope I've explained that clearly. I'll upload my test case asap. Cheers, Greg
Created attachment 163420 [details] Test Case - EMF Project See my previous comment
The changes I committed for 382774 address the problem reported here (as far as I can tell). It would be great if you could confirm that and report any oversights! *** This bug has been marked as a duplicate of bug 382774 ***