Home » Modeling » UML2 » Stereotype.getAllExtendedMetaclasses() does not respect propety visibility
Stereotype.getAllExtendedMetaclasses() does not respect propety visibility [message #1847550] |
Mon, 01 November 2021 10:25 |
|
It seems like the Stereotype.getAllExtendedMetaclasses() operation does not respecty visibility of nested properties to the superclasses to the stereotype.
Lets say I have a profile with stereotype A that extends UML::Class and also has a generalization relationship to a super stereotype B that extends UML::Element by a private "base_Element" property. (see attached profile created in Papyrus).
When invoking getAllExtendedMetaclasses() on stereotype A I get a list of both UML::Class and UML::Element as result.
I expected to only get a list with UML::Class as result.
Is this by design or is it a bug?
I am using UML2 framework (v5.5.2) in Papyrus 2021-09.
/Thomas
Thomas Wiman
MetaModelAgent Product Manager
|
|
| |
Re: Stereotype.getAllExtendedMetaclasses() does not respect propety visibility [message #1847562 is a reply to message #1847560] |
Mon, 01 November 2021 13:05 |
|
Hi Ed,
If so I think the name of the operation is missleading as I assumed that instances of the returned metaclasses (or any of their non-abstract submetaclasses) should be able to apply the stereotype for which the operation was invoked.
The workaround I will use is the following operation:
public static Set<Class>getAllExtendedMetaClasses(Stereotype stereotype) {
Set<Class> metaClasses = new HashSet<Class>();
for (Property property : stereotype.getAllAttributes()) {
if (property.getType() instanceof Class) {
Class _class = (Class)property.getType();
if (_class != null && property.getAssociation() instanceof Extension) {
metaClasses.add(_class);
}
}
}
return metaClasses;
}
Where I hope that getAllAttributes() behaves as expected....
/Thomas
Thomas Wiman
MetaModelAgent Product Manager
|
|
|
Re: Stereotype.getAllExtendedMetaclasses() does not respect propety visibility [message #1847602 is a reply to message #1847562] |
Tue, 02 November 2021 09:19 |
German Vega Messages: 104 Registered: December 2015 Location: Grenoble, France |
Senior Member |
|
|
Hi Thomas,
I think the behavior of getAllExtendedMetaclasses is correct. In your example
Quote:Lets say I have a profile with stereotype A that extends UML::Class and also has a generalization relationship to a super stereotype B that extends UML::Element by a private "base_Element" property. (see attached profile created in Papyrus).
For me, the stereotype A can be applied both to UML::Class and UML::Element, this is equivalent to a multiple metaclass extension. So it is correct that both are returned by getAllExtendedMetaclasses, and you are able to apply the stereotype to instances of both metaclasses
I think this has nothing to do with property visibility, you are simply inheriting the properties of the superclass, in particular the extension ends of the parent stereotype.
Concerning your code snippet, I do not see how it workarounds the "problem", you are iterating over all attributes (including the inherited ones) . Anyway, if you compare with the implementation of getAllExtendedMetaclasses I do not see a difference :
protected static EList<org.eclipse.uml2.uml.Class> getExtendedMetaclasses(
Stereotype stereotype,
EList<org.eclipse.uml2.uml.Class> extendedMetaclasses) {
for (Property ownedAttribute : stereotype.getOwnedAttributes()) {
if (ownedAttribute.getAssociation() instanceof Extension) {
Type type = ownedAttribute.getType();
if (type instanceof org.eclipse.uml2.uml.Class) {
extendedMetaclasses.add((org.eclipse.uml2.uml.Class) type);
}
}
}
return extendedMetaclasses;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* Retrieves the metaclasses extended by this stereotype.
* @param stereotype The receiving '<em><b>Stereotype</b></em>' model object.
* <!-- end-model-doc -->
* @generated NOT
*/
public static EList<org.eclipse.uml2.uml.Class> getExtendedMetaclasses(
Stereotype stereotype) {
return ECollections.unmodifiableEList(getExtendedMetaclasses(stereotype,
new UniqueEList.FastCompare<org.eclipse.uml2.uml.Class>()));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* Retrieves all the metaclasses extended by this stereotype, including the metaclasses extended by its superstereotypes.
* @param stereotype The receiving '<em><b>Stereotype</b></em>' model object.
* <!-- end-model-doc -->
* @generated NOT
*/
public static EList<org.eclipse.uml2.uml.Class> getAllExtendedMetaclasses(
Stereotype stereotype) {
EList<org.eclipse.uml2.uml.Class> allExtendedMetaclasses = getExtendedMetaclasses(
stereotype,
new UniqueEList.FastCompare<org.eclipse.uml2.uml.Class>());
for (Classifier parent : stereotype.allParents()) {
if (parent instanceof Stereotype) {
getExtendedMetaclasses((Stereotype) parent,
allExtendedMetaclasses);
}
}
return ECollections.unmodifiableEList(allExtendedMetaclasses);
}
Hope this helps clarify the issue
German Vega
|
|
|
Re: Stereotype.getAllExtendedMetaclasses() does not respect propety visibility [message #1847662 is a reply to message #1847602] |
Wed, 03 November 2021 08:13 |
|
Hi German, thanks for your concern.
You say "For me, the stereotype A can be applied both to UML::Class and UML::Element, this is equivalent to a multiple metaclass extension. So it is correct that both are returned by getAllExtendedMetaclasses, and you are able to apply the stereotype to instances of both metaclasses"
But when I invoke the UML2-method Element.getAllApplicableStereotypes() for example on a package (which is an instance of UML::Package which is a subclass to UML::Element) in my model where the profile has been applied, the stereotype A is not returned, indicating the stereotype cannot be applied to a package.
/Thomas
Thomas Wiman
MetaModelAgent Product Manager
|
|
|
Re: Stereotype.getAllExtendedMetaclasses() does not respect propety visibility [message #1847671 is a reply to message #1847662] |
Wed, 03 November 2021 11:21 |
German Vega Messages: 104 Registered: December 2015 Location: Grenoble, France |
Senior Member |
|
|
Hi Thomas,
I just tested a little your case, and effectively there is an inconsistency between getAllExtendedMetaclasses and getAllApplicableStereotypes.
And you were right, the inconsistency comes from the handling of the visibility of the properties representing the extensions.
The implementation of getAllExtendedMetaclasses doesn't consider the visibility of the properties, as shown in my previous post.
The implementation of getAllApplicableStereotypes on the other hand is based on this method
protected static Extension getExtension(Element element,
Stereotype stereotype) {
for (Property attribute : stereotype.getAllAttributes()) {
Association association = attribute.getAssociation();
if (association instanceof Extension) {
String name = attribute.getName();
if (!isEmpty(name)
&& name.startsWith(Extension.METACLASS_ROLE_PREFIX)) {
Type type = attribute.getType();
if (type instanceof org.eclipse.uml2.uml.Class) {
EClassifier eClassifier = getEClassifier(
(org.eclipse.uml2.uml.Class) type);
if (eClassifier != null
&& eClassifier.isInstance(element)) {
return (Extension) association;
}
}
}
}
}
return null;
}
It uses stereotype.getAllAttributes() which indeed consider the visibility of the properties of the stereotype, and because they are declared private (in the super stereotype) they are not inherited.
All this being said, I think this may not be a bug of the UML implementation but rather of the way you created your profile.
I just created a profile (attached to this post) using the basic UML tree editor (not papyrus) and the properties representing the extension have visibility "public". With this profile, every thing is consistent, and the editor proposes me to apply stereotype A to any element.
I even looked at the UML specification (UML 2.5.1 Section 12.3.3.1.3 MOF-Equivalent Semantics) and although is not explicitly stated the properties shown in the example do not have visibility private.
How did you create your profile? did you use Papyrus or something else ? did you manually modify the visibility of the properties?
Regards,
German Vega
|
|
| | |
Re: Stereotype.getAllExtendedMetaclasses() does not respect propety visibility [message #1847689 is a reply to message #1847679] |
Wed, 03 November 2021 17:26 |
Ed Willink Messages: 7671 Registered: July 2009 |
Senior Member |
|
|
Hi
I don't see why private attributes are not inherited. visibility is about access so yes derived contexts may be prevented from accessing, but we are dealing with structural existence. The private attributes must exist in derived contexts else the appropriate invocation of a superclass method would encounter a 'PropertyNotFound'. An invisible private Property might as well not exist so it should be a WFR violation.
Arguably the bug is actually that getAllAttributes should ignore visibility. It's Java doc is "Retrieves all the attributes of this classifier, including those inherited from its parents." - no mention of visibility. The corresp[onding OMG specification is "The query allAttributes gives an ordered set of all owned and inherited attributes of the Classifier. All owned attributes appear before any inherited attributes, and the attributes inherited from any more specific parent Classifier appear before those of any more general parent Classifier. However, if the Classifier has multiple immediate parents, then the relative ordering of the sets of attributes from those parents is not defined." - again no mention of visibility.
As I commented before visibility is dubious in UML and at the metamodel level best ignored. It really only controls your final code generators and it is possible that the UAF values suit the tooling of some UAF authors. Sadly many OMG metamodels are almost untooled at the time of release and so contain many debatable details. (It was not until UML 2.5 that the prolific OCL syntax errors in UML 2.0 were reduced to just 4.)
----
Sadly there is minimal commercial support for Eclipse UML2 and so https://projects.eclipse.org/projects/modeling.mdt.uml2 shows very little activity.
If you want a fix I suggest that you at least develop the fix, demonstrate that JUnit tests are not unjustifiably broken, and make it available via GIT.
----
If I was a UML2 committer, I would be very reluctant to make this change without a clear imperative from either specification or API Javadoc. This is exactly the kind of change where pleasing one user upsets another. Much safer to preserve stable functionality; the new user can develop a new workaround; the old user's workaround is not broken. However both spec and Javadoc suggest a getAllAttributes fix if it does indeed use visibility, but I don't see it in the code.
Regards
Ed Willink
|
|
|
Re: Stereotype.getAllExtendedMetaclasses() does not respect propety visibility [message #1847705 is a reply to message #1847689] |
Thu, 04 November 2021 08:20 |
|
Ed, I understand and accept your reasoning. But among ordinary users, like myself, the general perception is that private attributes are not inherited.
I do not intend to propose any change to any of the existing methods in the UML2 framework as any change will break backwards compatibility. But I think it would be an improvement if the documentation of each method was more detailed. Especially in cases where the behavior differs from the general perception.
/Thomas
Thomas Wiman
MetaModelAgent Product Manager
|
|
| |
Re: Stereotype.getAllExtendedMetaclasses() does not respect propety visibility [message #1847708 is a reply to message #1847689] |
Thu, 04 November 2021 09:39 |
German Vega Messages: 104 Registered: December 2015 Location: Grenoble, France |
Senior Member |
|
|
Hi Ed,
I really agree with you that visibility is dubious in UML, but I think that the current implementation of getAllAttributes is right, and that to conform to the UML 2.5.1 specification it should consider visibility.
The definition of allAttributes in the specification is the following
allAttributes() : Property [0..*]{ordered}
body: attribute->asSequence()->union(parents()->asSequence().allAttributes())->select(p |
member->includes(p))->asOrderedSet()
You can notice that after gathering all the attributes in the hierarchy (without looking at visibility) it filters the collection based on whether the attribute is considered a member of the classifier or not.
This is based on property member that is a derived union property that (among others subsets) includes inheritedMember that ultimately filters based on visibility and redefinitions, as following :
inheritedMember() : NamedElement [0..*]
The inheritedMember association is derived by inheriting the inheritable members of the parents.
body: inherit(parents()->collect(inheritableMembers(self))->asSet())
inherit(inhs : NamedElement [0..*]) : NamedElement [0..*]
The query inherit() defines how to inherit a set of elements passed as its argument. It excludes redefined
elements from the result.
body: inhs->reject(inh |
inh.oclIsKindOf(RedefinableElement) and
ownedMember->select(oclIsKindOf(RedefinableElement))->
select(redefinedElement->includes(inh.oclAsType(RedefinableElement)))
->notEmpty())
inheritableMembers(c : Classifier) : NamedElement [0..*]
The query inheritableMembers() gives all of the members of a Classifier that may be inherited in one of its
descendants, subject to whatever visibility restrictions apply.
pre: c.allParents()->includes(self)
body: member->select(m | c.hasVisibilityOf(m))
hasVisibilityOf(n : NamedElement) : Boolean
The query hasVisibilityOf() determines whether a NamedElement is visible in the classifier. Non-private
members are visible. It is only called when the argument is something owned by a parent.
pre: allParents()->including(self)->collect(member)->includes(n)
body: n.visibility <> VisibilityKind::private
The current implementation literally translates these OCL expressions into java, this is the code that I debugged yesterday when looking at Thomas' issue. I was surprised by this behavior, but it seems to be faithful to the specification.
On the other hand, operations getAllExtendedMetaclasses and getAllApplicableStereotypes are not at all defined in the specification, the section about profiles doesn't mention visibility at all, so things are open to tool interpretation.
Howver, as Thomas mentioned, one would expect them to be consistent : for a given element, and for each stereotype returned by element.getAllApplicableStereotypes one expects that stereotype.getAllExtendedMetaclasses contains at least one supertype of the type of element. And conversely, given an stereotype , for every subtype of one type in stereotype.getAllExtendedMetaclasses , one expects that for an element instance of the subtype element.getAllApplicableStereotypes includes the stereotype.
This is not the case right now (when inheritance of private extensions is involved), and this inconsistent behavior is what I consider a bug.
Now, should getAllExtendedMetaclasses include or not private extensions defined in a super stereotype, that may be open to debate. But I tend to agree with Thomas, for most programmers the general perception is that private attributes are not inherited
Regards,
G.Vega
|
|
| |
Goto Forum:
Current Time: Thu Sep 26 13:10:05 GMT 2024
Powered by FUDForum. Page generated in 0.05272 seconds
|