Summary: | code generation ignores unidirectional association | ||
---|---|---|---|
Product: | [Applications] umbrello | Reporter: | Diederik van der Boor <vdboor> |
Component: | general | Assignee: | Umbrello Development Group <umbrello-devel> |
Status: | RESOLVED FIXED | ||
Severity: | normal | ||
Priority: | NOR | ||
Version: | unspecified | ||
Target Milestone: | --- | ||
Platform: | Gentoo Packages | ||
OS: | Linux | ||
Latest Commit: | Version Fixed In: | ||
Sentry Crash Report: | |||
Attachments: |
class diagram with unidirectional association
patch for #77042 |
Description
Diederik van der Boor
2004-01-07 11:13:53 UTC
Can you describe this further? The current code generation *wont* show any attributes for the association *IF* you didnt supply a role name. Is this the case? I'm sorry for not replying sooner. I've indeed misunderstood the association name; because I made an unidirectional-association, I assumed that the "association name" represented the role-name field. Could it be possible to: - edit the role name from the context menu? - gray-out the second role name for a unidirectional-association? I just tried this and the C++ code generator does not show the attribute from an association whatever I do. This bug is present on 1.5.2 version. I use unidirectional assotiation and supply a role B name. But the code generated dont show any atribute. I think this is an important issue. If we use unidirectional assotiations , what shoud up in the code : 1) private variable 2) getter method 3) setter method 4) private variable and getter and setter methods Created attachment 19795 [details]
class diagram with unidirectional association
With the patch submited further and this class diagram, the C++ generated code
is:
---------------------------------------------------
......
#ifndef CLASS1_H
#define CLASS1_H
#include <string>
#include <vector>
class Class2;
/**
* class Class1
*/
class Class1
{
public:
// Constructors/Destructors
//
/**
* Empty Constructor
*/
Class1 ( );
/**
* Empty Destructor
*/
virtual ~Class1 ( );
// Static public attributes
//
// public attributes
//
Class2 * m_rolea;
// public attribute accessor methods
//
// public attribute accessor methods
//
/**
* Set the value of m_rolea
* @param new_var the new value of m_rolea
*/
void setroleA ( Class2 * new_var );
/**
* Get the value of m_rolea
* @return the value of m_rolea
*/
Class2 * getroleA ( );
protected:
// Static protected attributes
//
// protected attributes
//
public:
// protected attribute accessor methods
//
protected:
public:
// protected attribute accessor methods
//
protected:
private:
// Static private attributes
//
// private attributes
//
public:
// private attribute accessor methods
//
private:
public:
// private attribute accessor methods
//
private:
};
#endif // CLASS1_H
--------------------------------------------------------------
the Java generated code is:
--------------------------------------------------------------
import java.util.*;
/**
* Class Class1
*/
public class Class1 {
//
// Fields
//
public Class2 m_roleA;
//
// Constructors
//
public Class1 () { };
//
// Methods
//
//
// Accessor methods
//
/**
* Set the value of m_roleA
* @param newVar the new value of m_roleA
*/
public void setRoleA ( Class2 newVar ) {
m_roleA = newVar;
}
/**
* Get the value of m_roleA
* @return the value of m_roleA
*/
public Class2 getRoleA ( ) {
return m_roleA;
}
//
// Other methods
//
}
Created attachment 19796 [details]
patch for #77042
This patch fixes (for C++ and Java) the problem that the code generation
ignored unidirectional association.
For the other languages, I am not very sure. I don't promise anything but I
will try to have a look.
The patch try to create nothing when there is already a attribute with the same
name that the role name (the role name to consider is the role A name).
But, in trunk, I wasn't able to add an attribute ?
In the dialog window, I can only see the Help, OK and Cancel button ?
The patch also fixes another bug in the java code generator.
The name used for the declaration of the attribute (for any kind of
association) and the name used in the body of the getter and the setter were
not equal.
Thanks
> The patch try to create nothing when there is already a attribute > with the same name that the role name That's a very good idea and I think we need that for the other association types too (aggregations, compositions) > (the role name to consider is the role A name). Here is a UniAssociation in Umbrello (I hope whitespace is preserved): +--------+ roleB +--------+ | Class1 |-------------->| Class2 | +--------+ +--------+ The role A is at Class1 and the role B is at Class2. Now the UML standard says the member name in Class1 should be the role B name. So it's the role name "farther away" from the referencing class - in the case of UniAssociation, the name at the arrow head. > But, in trunk, I wasn't able to add an attribute ? Trunk still needs a lot of work. SVN commit 636790 by okellogg: Attachment 19796 [details] from Antoine Dopffer adds code generation for UniAssociation in C++and Java. I modified the patch for role B as described in comment #8. Many thanks Antoine for your work. BUG:72042 M +1 -0 ChangeLog M +29 -0 umbrello/classifier.cpp M +5 -0 umbrello/classifier.h M +4 -1 umbrello/codegenerators/classifierinfo.cpp M +1 -0 umbrello/codegenerators/classifierinfo.h M +10 -0 umbrello/codegenerators/cppwriter.cpp M +7 -3 umbrello/codegenerators/javawriter.cpp --- branches/KDE/3.5/kdesdk/umbrello/ChangeLog #636789:636790 @@ -4,6 +4,7 @@ * C# Code Generation and export (53368) * Java interface inheritance, abstract classes and generics in code generation (53376) +* Code generation ignores unidirectional association (72042) * %date% and %time% not being parsed (96612) * Operations of the Interface are not implemented in the class automatically (111593) --- branches/KDE/3.5/kdesdk/umbrello/umbrello/classifier.cpp #636789:636790 @@ -833,6 +833,33 @@ return m_isRef; } +UMLAssociationList UMLClassifier::getUniAssociationToBeImplemented() { + UMLAssociationList associations = getSpecificAssocs(Uml::at_UniAssociation); + UMLAssociationList uniAssocListToBeImplemented; + + for(UMLAssociation *a = associations.first(); a; a = associations.next()) { + if (a->getObjectId(Uml::B) == getID()) + continue; // we need to be at the A side + + QString roleNameB = a->getRoleName(Uml::B); + if (!roleNameB.isEmpty()) { + UMLAttributeList atl = getAttributeList(); + bool found = false; + //make sure that an attribute with the same name doesn't already exist + for (UMLAttribute *at = atl.first(); at ; at = atl.next()) { + if (at->getName() == roleNameB) { + found = true; + break; + } + } + if (!found) { + uniAssocListToBeImplemented.append(a); + } + } + } + return uniAssocListToBeImplemented; +} + void UMLClassifier::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) { QString tag; switch (m_BaseType) { @@ -986,4 +1013,6 @@ return totalSuccess; } + + #include "classifier.moc" --- branches/KDE/3.5/kdesdk/umbrello/umbrello/classifier.h #636789:636790 @@ -436,6 +436,11 @@ */ UMLClassifierListItem* makeChildObject(const QString& xmiTag); + /** + * Return the list of unidirectional association that should show up in the code + */ + virtual UMLAssociationList getUniAssociationToBeImplemented(); + signals: /** Signals that a new UMLOperation has been added to the classifer. */ --- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/classifierinfo.cpp #636789:636790 @@ -85,6 +85,9 @@ plainAssociations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations. plainAssociations.setAutoDelete(false); + uniAssociations = c->getUniAssociationToBeImplemented(); + uniAssociations.setAutoDelete(false); + aggregations = c->getAggregations(); aggregations.setAutoDelete(false); @@ -92,7 +95,7 @@ compositions.setAutoDelete(false); // set some summary information about the classifier now - hasAssociations = plainAssociations.count() > 0 || aggregations.count() > 0 || compositions.count() > 0; + hasAssociations = plainAssociations.count() > 0 || aggregations.count() > 0 || compositions.count() > 0 || uniAssociations.count() > 0; hasAttributes = atpub.count() > 0 || atprot.count() > 0 || atpriv.count() > 0 || static_atpub.count() > 0 || static_atprot.count() > 0 --- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/classifierinfo.h #636789:636790 @@ -65,6 +65,7 @@ * Lists of types of associations this classifier has */ UMLAssociationList plainAssociations; + UMLAssociationList uniAssociations; UMLAssociationList aggregations; UMLAssociationList compositions; --- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/cppwriter.cpp #636789:636790 @@ -183,6 +183,8 @@ // associations writeAssociationMethods(m_classifierInfo->plainAssociations, permitScope, true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream); + writeAssociationMethods(m_classifierInfo->uniAssociations, permitScope, + true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream); writeAssociationMethods(m_classifierInfo->aggregations, permitScope, true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream); writeAssociationMethods(m_classifierInfo->compositions, permitScope, @@ -200,6 +202,7 @@ // associations writeAssociationDecls(m_classifierInfo->plainAssociations, permitScope, c->getID(), stream); + writeAssociationDecls(m_classifierInfo->uniAssociations, permitScope, c->getID(), stream); writeAssociationDecls(m_classifierInfo->aggregations, permitScope, c->getID(), stream); writeAssociationDecls(m_classifierInfo->compositions, permitScope, c->getID(), stream); @@ -279,6 +282,8 @@ // public writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Public, false, !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp); + writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Public, false, + !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp); writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Public, false, !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp); writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Public, false, @@ -287,6 +292,8 @@ // protected writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Protected, false, !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp); + writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Protected, false, + !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp); writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Protected, false, !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp); writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Protected, false, @@ -296,6 +303,8 @@ // private writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Private, false, !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp); + writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Private, false, + !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp); writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Private, false, !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp); writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Private, false, @@ -349,6 +358,7 @@ { // write all includes we need to include other classes, that arent us. printAssociationIncludeDecl (m_classifierInfo->plainAssociations, c->getID(), cpp); + printAssociationIncludeDecl (m_classifierInfo->uniAssociations, c->getID(), cpp); printAssociationIncludeDecl (m_classifierInfo->aggregations, c->getID(), cpp); printAssociationIncludeDecl (m_classifierInfo->compositions, c->getID(), cpp); --- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/javawriter.cpp #636789:636790 @@ -115,10 +115,12 @@ // another preparation, determine what we have UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations. + UMLAssociationList uniAssociations = c->getUniAssociationToBeImplemented(); + UMLAssociationList aggregations = c->getAggregations(); UMLAssociationList compositions = c->getCompositions(); - bool hasAssociations = aggregations.count() > 0 || associations.count() > 0 || compositions.count() > 0; + bool hasAssociations = aggregations.count() > 0 || associations.count() > 0 || compositions.count() > 0 || uniAssociations.count() > 0; bool hasAttributes = (atl.count() > 0); bool hasAccessorMethods = hasAttributes || hasAssociations; bool hasOperationMethods = (c->getOpList().count() > 0); @@ -188,6 +190,7 @@ writeAttributeDecls(atpub, atprot, atpriv, java); writeAssociationDecls(associations, c->getID(), java); + writeAssociationDecls(uniAssociations, c->getID(), java); writeAssociationDecls(aggregations, c->getID(), java); writeAssociationDecls(compositions, c->getID(), java); @@ -232,6 +235,7 @@ // first: determine the name of the other class writeAssociationMethods(associations, c, java); + writeAssociationMethods(uniAssociations, c, java); writeAssociationMethods(aggregations, c, java); writeAssociationMethods(compositions, c, java); @@ -527,7 +531,7 @@ // multiplicity object that we don't have to figure out what it means via regex. if(multi.isEmpty() || multi.contains(QRegExp("^[01]$"))) { - QString fieldVarName = roleName.replace(0, 1, roleName.left(1).lower()); + QString fieldVarName = "m_" + roleName.replace(0, 1, roleName.left(1).lower()); java<<startline<<scope<<" "<<fieldClassName<<" "<<fieldVarName<<";"; } else @@ -586,7 +590,7 @@ { if(multi.isEmpty() || multi.contains(QRegExp("^[01]$"))) { - QString fieldVarName = "m_" + roleName.lower(); + QString fieldVarName = "m_" + roleName.replace(0, 1, roleName.left(1).lower()); writeSingleAttributeAccessorMethods(fieldClassName, fieldVarName, roleName, description, visib, change, false, java); } In comment #8, I wrote: > That's a very good idea and I think we need that for the other > association types too (aggregations, compositions) but I was referring to: > the role name to consider is the role B name I.e. it would be great to have the role B filtering methods like UMLClassifier::get{Aggregation,Composition}ToBeImplemented() BTW, the check against attributes is not needed because UMLAssocation is never tied to UMLAttribute. The class that ties to UMLAttribute is AssociationWidget, and that class is not used for generating code. Ok, sorry for I took the wrong way of the arrow. I think I am kind of UML dyslexiac. The check against attributes was created because I was affraid that attributes could be generated twice in this situation: +---------------+ roleB +--------+ | Class1 |-------------->| Class2 | |---------------| | | | -roleB: Class2| | | +---------------+ +--------+ roleB (declaration, getter, setter) could be generated because roleB is the role B name of the unidirectional association roleB (declaration, getter, setter) could be also generated once again because roleB is an attribute of Class1 To get this kind of diagram with Umbrello, you have to delete the agregation that is automatically generated when you add attribute roleB in C1 |