Home » Modeling » EMF » Child extenders
Child extenders [message #540665] |
Wed, 16 June 2010 21:54 |
Hallvard Traetteberg Messages: 673 Registered: July 2009 Location: Trondheim, Norway |
Senior Member |
|
|
Hi,
I'm trying to use the extensible provider factory and child creation
extenders, but I cannot get it to work as I want it to.
I (actually Wazaabi) have container class AbstractContainer with a
containment feature for AbstractComponents. In a separate/foreign
package (and plugin) I have a subclass of AbstractComponent for which I
want a Creation action and menu entry to appear. If I understand this
correctly, AbstractContainer's package's provider factory is supposed to
use the org.eclipse.emf.edit.childCreationExtenders extension point for
finding potential child EClasses.
Using breakpoints (Ed always says the debugger is your best friend), I
see that the generated ChildCreationExtender (for the foreign package)
is asked for newChildDescriptors (by calling getNewChildDescriptors),
but none are added. I've traced the code into an inner class called
CreationSwitch which ultimately calls the following doSwitch (in the
AbstractContainer's package's XxxSwitch class):
protected Object doSwitch(EClass theEClass, EObject theEObject) {
if (theEClass.eContainer() == modelPackage) {
return doSwitch(theEClass.getClassifierID(), theEObject);
}
else {
List eSuperTypes = theEClass.getESuperTypes();
return eSuperTypes.isEmpty() ?
defaultCase(theEObject) :
doSwitch((EClass)eSuperTypes.get(0), theEObject);
}
}
The code seems to walk up the superclass chain until it finds a
superclass in AbstractContainer's package. If this class ends up being
AbstractContainer I think the code will work. However, due to multiple
inheritance and the fact that it only uses eSuperTypes.get(0) instead of
the whole list, it doesn't find AbstractContainer, although it is a
superclass. Hence, no newChildDescriptor is found using the
ChildCreationExtender.
I hope the explanation makes sense for those familiar with the code. Is
this behavior intentional? If yes, why? And what should I do, besides
changing the class hierarchy?
Hallvard
|
|
|
Re: Child extenders [message #540666 is a reply to message #540665] |
Wed, 16 June 2010 22:11 |
Ed Merks Messages: 33218 Registered: July 2009 |
Senior Member |
|
|
Hallvard,
Comments below.
Hallvard Trætteberg wrote:
> Hi,
>
> I'm trying to use the extensible provider factory and child creation
> extenders, but I cannot get it to work as I want it to.
>
> I (actually Wazaabi) have container class AbstractContainer with a
> containment feature for AbstractComponents. In a separate/foreign
> package (and plugin) I have a subclass of AbstractComponent for which
> I want a Creation action and menu entry to appear. If I understand
> this correctly, AbstractContainer's package's provider factory is
> supposed to use the org.eclipse.emf.edit.childCreationExtenders
> extension point for finding potential child EClasses.
>
> Using breakpoints (Ed always says the debugger is your best friend), I
> see that the generated ChildCreationExtender (for the foreign package)
> is asked for newChildDescriptors (by calling getNewChildDescriptors),
> but none are added. I've traced the code into an inner class called
> CreationSwitch which ultimately calls the following doSwitch (in the
> AbstractContainer's package's XxxSwitch class):
Isn't there a switch more specific to the derived class you're instance
actually is?
>
> protected Object doSwitch(EClass theEClass, EObject theEObject) {
> if (theEClass.eContainer() == modelPackage) {
> return doSwitch(theEClass.getClassifierID(), theEObject);
> }
> else {
> List eSuperTypes = theEClass.getESuperTypes();
> return eSuperTypes.isEmpty() ?
> defaultCase(theEObject) :
> doSwitch((EClass)eSuperTypes.get(0), theEObject);
> }
> }
>
> The code seems to walk up the superclass chain until it finds a
> superclass in AbstractContainer's package. If this class ends up being
> AbstractContainer I think the code will work. However, due to multiple
> inheritance and the fact that it only uses eSuperTypes.get(0) instead
> of the whole list, it doesn't find AbstractContainer, although it is a
> superclass. Hence, no newChildDescriptor is found using the
> ChildCreationExtender.
In general the generated switches are designed to ensure that each
interface is visited at most once. If we call doSwitch on each super
type, we'd easily get into the situation of taking the same action
multiple times, i.e., adding the same descriptors more than once.
>
> I hope the explanation makes sense for those familiar with the code.
> Is this behavior intentional? If yes, why? And what should I do,
> besides changing the class hierarchy?
When designing a class hierarchy, it is important to consider carefully
what's the first super type because this is the Impl class that will be
extended and you'll derive the most reused code from that.
For the above situation, I'm not sure if there shouldn't be a registered
adapter more specific to the actual instance class, i.e., one that would
cover all the cases of the multiple inheritance. Note that plugin.xmls
don't regenerate so perhaps you've not generated all the necessary
registrations...
>
> Hallvard
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
|
Re: Child extenders [message #540680 is a reply to message #540666] |
Wed, 16 June 2010 23:36 |
Hallvard Traetteberg Messages: 673 Registered: July 2009 Location: Trondheim, Norway |
Senior Member |
|
|
On 17.06.10 00.11, Ed Merks wrote:
> Hallvard,
>
> Comments below.
>
>
> Hallvard Trætteberg wrote:
>>
>> Using breakpoints (Ed always says the debugger is your best friend), I
>> see that the generated ChildCreationExtender (for the foreign package)
>> is asked for newChildDescriptors (by calling getNewChildDescriptors),
>> but none are added. I've traced the code into an inner class called
>> CreationSwitch which ultimately calls the following doSwitch (in the
>> AbstractContainer's package's XxxSwitch class):
>
> Isn't there a switch more specific to the derived class you're instance
> actually is?
I'm not sure I understand what you mean by "a specific more
specific...". I'll try to explain what package and class structure and
what is generated:
- widgets (package) contains AbstractContainer and AbstractComponent.
- widgets (same name, different plugin and Java package) contains
Composite, which indirectly extends AbstractContainer, but not through
the main supertype chain (and this is what I think causes the problem)
- browsersupport (package) contains Browser, which extends
AbstractComponent, and hence may be contained in an AbstractContainer or
a Composite
The object for which I want a Browser CreationAction is a Composite.
An IChildCreationExtender named WidgetsChildCreationExtender is
generated in BrowsersupportItemProviderAdapterFactory, with an entry in
plugin.xml. I guess this is because it's AbstractContainer in the
widgets package that may contain the Browser objects.
Inside WidgetsChildCreationExtender there is a CreationSwitch which
extends WidgetsSwitch (from the first widgets package). The
CreationSwitch contains a case method named caseAbstractContainer:
public Object caseAbstractContainer(AbstractContainer object) {
newChildDescriptors.add(createChildParameter
(WidgetsPackage.Literals.ABSTRACT_CONTAINER__CHILDREN,
BrowsersupportFactory.eINSTANCE.createBrowser()));
return null;
}
It's this method that is never called, because the main supertype chain
of Composite does contain AbstractContainer (although it is a mixed-in
supertype).
> In general the generated switches are designed to ensure that each
> interface is visited at most once. If we call doSwitch on each super
> type, we'd easily get into the situation of taking the same action
> multiple times, i.e., adding the same descriptors more than once.
I understand that this may be a problem, but somehow all superclasses
should be visited/tried.
> When designing a class hierarchy, it is important to consider carefully
> what's the first super type because this is the Impl class that will be
> extended and you'll derive the most reused code from that.
First of all, it's not my hierarchy, so there's little I can do to tweak
it for solving this problem. Second, usually EMF copies necessary code
that should be "inherited" into the subclass', when it cannot be really
inherited from the first superclass' Impl class. How should it work in
this case?
> For the above situation, I'm not sure if there shouldn't be a registered
> adapter more specific to the actual instance class, i.e., one that would
> cover all the cases of the multiple inheritance. Note that plugin.xmls
> don't regenerate so perhaps you've not generated all the necessary
> registrations...
I've regenerated plugin.xml several times, for all relevant plugins.
I notice one thing: There's a generated item provider for a class in
between Browser and AbstractComponent in the class hierarchy. This class
is abstract and its item provider isn't referenced anywhere. Removing it
does give any errors. Is this a hint of a problem?
Hallvard
|
|
|
Re: Child extenders [message #540688 is a reply to message #540680] |
Thu, 17 June 2010 01:42 |
Ed Merks Messages: 33218 Registered: July 2009 |
Senior Member |
|
|
Hallvard,
Comments below.
Hallvard Trætteberg wrote:
> On 17.06.10 00.11, Ed Merks wrote:
>> Hallvard,
>>
>> Comments below.
>>
>>
>> Hallvard Trætteberg wrote:
>>>
>>> Using breakpoints (Ed always says the debugger is your best friend), I
>>> see that the generated ChildCreationExtender (for the foreign package)
>>> is asked for newChildDescriptors (by calling getNewChildDescriptors),
>>> but none are added. I've traced the code into an inner class called
>>> CreationSwitch which ultimately calls the following doSwitch (in the
>>> AbstractContainer's package's XxxSwitch class):
>>
>> Isn't there a switch more specific to the derived class you're instance
>> actually is?
>
> I'm not sure I understand what you mean by "a specific more specific...".
Every package has its own switch and when that switch is used, only the
first case is hit. The generated case methods for that specific
package's class will handle all the cases for all the super types. Th
> I'll try to explain what package and class structure and what is
> generated:
It's of course quite challenging to turn a bunch of English description
mentally into what's generated from the corresponding model...
>
> - widgets (package) contains AbstractContainer and AbstractComponent.
> - widgets (same name, different plugin and Java package) contains
> Composite, which indirectly extends AbstractContainer, but not through
> the main supertype chain (and this is what I think causes the problem)
> - browsersupport (package) contains Browser, which extends
> AbstractComponent, and hence may be contained in an AbstractContainer
> or a Composite
>
> The object for which I want a Browser CreationAction is a Composite.
>
> An IChildCreationExtender named WidgetsChildCreationExtender is
> generated in BrowsersupportItemProviderAdapterFactory, with an entry
> in plugin.xml. I guess this is because it's AbstractContainer in the
> widgets package that may contain the Browser objects.
>
> Inside WidgetsChildCreationExtender there is a CreationSwitch which
> extends WidgetsSwitch (from the first widgets package). The
> CreationSwitch contains a case method named caseAbstractContainer:
> public Object caseAbstractContainer(AbstractContainer object) {
> newChildDescriptors.add(createChildParameter
> (WidgetsPackage.Literals.ABSTRACT_CONTAINER__CHILDREN,
> BrowsersupportFactory.eINSTANCE.createBrowser()));
> return null;
> }
> It's this method that is never called, because the main supertype
> chain of Composite does contain AbstractContainer (although it is a
> mixed-in supertype).
>
>> In general the generated switches are designed to ensure that each
>> interface is visited at most once. If we call doSwitch on each super
>> type, we'd easily get into the situation of taking the same action
>> multiple times, i.e., adding the same descriptors more than once.
>
> I understand that this may be a problem, but somehow all superclasses
> should be visited/tried.
Yes though without repeats. So when dealing with a switch that's not
specific enough, we generally drop down to one that's specific enough.
>
>> When designing a class hierarchy, it is important to consider carefully
>> what's the first super type because this is the Impl class that will be
>> extended and you'll derive the most reused code from that.
>
> First of all, it's not my hierarchy, so there's little I can do to
> tweak it for solving this problem. Second, usually EMF copies
> necessary code that should be "inherited" into the subclass', when it
> cannot be really inherited from the first superclass' Impl class. How
> should it work in this case?
Well, again, it's hard to say without the actual concrete example in
front of me. It's pretty complicated stuff so it's fairly easy to
overlook some case.
>
>> For the above situation, I'm not sure if there shouldn't be a registered
>> adapter more specific to the actual instance class, i.e., one that would
>> cover all the cases of the multiple inheritance. Note that plugin.xmls
>> don't regenerate so perhaps you've not generated all the necessary
>> registrations...
>
> I've regenerated plugin.xml several times, for all relevant plugins.
>
> I notice one thing: There's a generated item provider for a class in
> between Browser and AbstractComponent in the class hierarchy. This
> class is abstract and its item provider isn't referenced anywhere.
> Removing it does give any errors. Is this a hint of a problem?
Maybe. It's definitely easy to have overlooked some case. If you could
synthesize an example that reproduces the problem, I'd be able to have a
look at that.
>
> Hallvard
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
| | | |
Goto Forum:
Current Time: Wed Sep 25 22:55:24 GMT 2024
Powered by FUDForum. Page generated in 0.04476 seconds
|