Kevin Brightwell edited this page Aug 26, 2015 · 1 revision

Each UCOSP participant is asked to log all their accomplishments as well as the difficulties they have getting set up to understand Umple and other experiences they have. Difficulties might include understanding how to model in Umple, using UmpleOnline, code that is difficult to figure out, and development tools that are hard to figure out, or don't seem to work properly. The more log entries added the more we can better get a grip on the usability issues with Umple, and the more we can help future new contributors come up to speed. Mention issue numbers and revision numbers in your log to help create hyperlinks.

Log entries in reverse chronological order

December 5th, 2014

I recently committed for Issue 417 (on Google Code).

See the bottom of this post for implementation details.


My issue this term revolved around the specialization of associations. Associations are fairly simple, for example, the following is a valid Many to Optional One association:

class Wheel {}
class Vehicle {}

association { * Wheel wheels -- 0..1 Vehicle vehicle; }

So in this situation, we have a simple abstraction of a Vehicle object, where the Vehicle has an arbitrary number of wheels and a Wheel can only belong to one Vehicle. Say, though, that we wanted to define a few new kinds of vehicles using inheritance. We could then have:

class Sedan { isA Vehicle; }
class Bicycle { isA Vehicle; }

This is all nice and fine, however, there is one thing. Recall that Vehicle and Wheel are associated. It makes sense for an abstract Vehicle to have an arbitrary number of wheels, since we could (perhaps infeasibly) invent a Vehicle that has 27 wheels. However, Sedans and Bicycles do not have a random number of wheels -- we know full well that Sedans have 4 wheels and Bicycles have 2. In that case, we'd be tempted to do:

association { 0..2 Wheel wheels -- 0..1 Bicycle vehicle; }
association { 0..4 Wheel wheels -- 0..1 Sedan vehicle; }

The idea is that the Wheel would still have a vehicle, and the Vehicles would still have wheels, only we specified how they should work with more detail. This construct previously resulted in an error: a class could not have two associations with the same name. Now, as per Issue 417 (on Google Code), this is possible with specializations.

The idea of a specialization is that we extend the functionality of the association in the super class (i.e. Vehicle) to instances of the subclasses (i.e. Bicycle and Sedan) without generating code we could do without. Why have a Wheel list in each of the subclasses of Vehicle when we could just have one list in Vehicle and make use of that data field in each of the subclasses?


I will admit that I ran into quite a few unforeseen problems while implementing this feature. I'll briefly go over what I did here.

  • I first had to make sense of the parsing and generation of associations, which was a task in itself.

  • I added a section in the parser that looks at associations before they are checked for duplicate names (the createSpecializedLinks() method in UmpleInternalParser_CodeClass.ump) and checked if they were specializations.

  • I then added a section to Generator_CodeJava.ump to extend the links created in the previous point to AssociationVariables, which are used by the Generators to generate code.

  • I added logic into the _All.jet files to check if the AssociationVariable it was dealing with was a specialization, since different code needs to be generated.

  • I created the necessary .jet files for the specialization code; I considered creating logical blocks in the original .jet files and dealing with specializations there, but I feel as though they would quickly have become unintelligible with sweeping if/else statements and code that wasn't quite relevant to the original association code.

  • Creating all of the new .jet files turned out to be a good thing when I ran into the dreaded "code too large" error in the JavaClassGenerator. It actually turns out that the constructor code is already nearly too large to fit in one file. To solve this, I created a new generator skeleton and offloaded most of the specialization method set and get code generation to the other generator. The biggest difference between the two generator skeletons is that spec_generator.skeleton does not need getCode() and therefore it doesn't implement ILang.

  • After that, it was mostly bug fixes. I had overlooked a number of situations while writing up the .jet files originally, namely:

  1. sometimes there is no set code in the super class -- this was perhaps the biggest issue I had. See Issue 646 (on Google Code) for more details
  2. method signatures were not always unique (this is a direct extension of the distinction between the "super" case and the "common" case; if you refer to the example in the overview, when wheels -- vehicle is specialized, Wheel needs "common" code and Bicycle/Sedan need "super" code. Common code refers to the case when you can't call the super class' methods since there is not forcibly an association in the super class.)
  3. since I needed to work the method signatures in the common case, I decided to make everything consistent and change it in the super case also
  4. getMany code was problematic -- in Java 7, there is no automatic casting of Lists of the super type into Lists of the sub type
  5. there are quite a few other method signatures that needed a little bit of work, namely the maximumNumberOf, minimumNumberOf, requiredNumberOf, etc...
  • Bringing everything together, I wrote testbed tests to touch upon each multiplicity to make sure that if there was no set code the methods were still working (using clears and adds)

  • Finally, running the existing template tests revealed a few other problems, namely with Traits and Interfaces, which I had previously thought could not be associated -- there were some null pointer exceptions since I assumed that everything related to associations was class related

And so there it is! If there are ever issues with the generated code, it should be fairly straightforward to change: one would need to find the appropriate multiplicity file and make the change in there.

I'm working on a user manual page and an example that I should have committed sometime soon, possibly on the weekend.

December 4th, 2014

I'm just about ready to commit, I'm just working through a last minute problem that I ran into with traits. For some reason, it appears that in certain cases, classes have more association variables then they have associations, which is causing some problems with the Class Generator as I have it implemented.

December 3rd, 2014

Today I finished writing the tests for the remaining multiplicities, as well as writing tests for the composition code. I also cleaned up some of the failing template tests and encountered some very strange errors while doing so... The template tests reported back as failures (i.e. the result of a given parse was true as opposed to the expected false), so I fixed the parser code accordingly. However, the tests continued to fail, so I spent a while looking around though the code to see if there was anything I missed. Strangely enough, if I copy the code from the test into a new Umple file and attempt to compile it, the file would not compile while the test was still claiming that it was parsing!

Either way, that doesn't appear to be a problem now that I ported everything over to the latest version of Umple. Tomorrow morning I'll get everything ready to make a commit. I don't foresee there being many issues with the commit, I just need to make sure I include all of my files (and there are indeed quite a few).

December 2nd, 2014

So I'm not exactly 100% finished, I had to spend a little while with fixing the names for the get methods. I just have a few other multiplicities to check and I should be good to go! I think there are only finishing touches left.

December 1st, 2014

I'm entering the final stages of the testbed now. Nearly all the tests I write are compiling and I've just run into a few minor issues. Right now, I'm working on a way to make the get method calls more intuitive for the user, as well as fixing some little bugs that found their way into the generated code. I basically want to make sure I touch upon each multiplicity when the two cases of JET I created (super and common) so that there are the least amount of hidden bugs when I finally commit.

I don't know if I'll be 100% done by tomorrow, but it's looking more and more presentable each day. Who knows, after this fix everything may work! I have a few good examples in mind (that I have tested, of course) for the manual page as well.

November 30th, 2014

The testbed tests are coming along. They have revealed a slew of minor issues which I've been able to address in a semi-reasonable fashion. I've made some blanket improvements to my implementation which has reduced the time to get through a test, which is nice.

One thing I do lament is Issue 646 (on Google Code) -- the lack of set code being generated has really affected my progress. When I could have easily called the super class set method or another relevant set method I've had to put a for loop that adds to the list in the super class, or worse, use the private set method that I've seen used to circumvent this problem. In all honesty I think that each association should have a set method, if only to make implementing specializations more straightforward. In retrospect I should have tried to solve the issue (had I noticed it earlier), but I hadn't realized the depth of the implication it would have on my code. Live and learn, I guess!

Anyway, just a small update. I'm still writing more tests for the different multiplicities, and bar Issue 646 (on Google Code) things are ok. One problem I foresee is when someone gets around to addressing the Issue -- they'll have to go through my jet files and change some of the generation. I've tried to make it a point to be as clear as possible with my boolean names, so it shouldn't be too too bad, but either way. I'll update with progress tomorrow.

November 29th, 2014

Everything seems to be working! Earlier, I discovered a little issue with my implementation: there was a significant amount of work that needed to be done to make sure that everything still worked with an association that previously did not have any "One" sides suddenly had a "One" side (think of it as a Vehicle -- Wheel into Vehicle -- Bicycle into Vehicle -- Unicycle set of associations). This particular case posed some interesting problems (particularly with the definition of method signatures), so it took a little time to work through.

The good news is, though, I've gotten through it and of all the multiplicities I checked, they work! I'm still writing testbed tests... I'm not entirely sure how many to include, but I've already added a few for the case where the multiplicities change to one and some other problem cases I was having earlier. I even made up a few and they are coming along nicely.

In other news, I'm still trying to think of a reasonable name for the new generator skeleton. "Offload Generator" is definitely lacking, and I don't think "Code Too Large Generator" is any better. I'm sure something sensible will come to me soon.

If the testbed tests go well, I'll run through my code one last time to clean up some redundancy.

One last thing; I've spent quite some time over the semester trying to find the best place to comb over all of the association variables within the model -- currently I have a few pretty elaborate calls to elements in the model that could be solved by simply saving the relevant information on the association variables. Hopefully I'll catch it when I run through my code again.

Anyway, I'll report back tomorrow evening with progress. I don't foresee many more issues, I'm fairly sure I've covered every special case with respect to specializations by now.

November 27th, 2014

While bringing my changes together for my commit, I ran into a slightly unexpected roadblock. The bulk of the functionality I'm working on goes into the GetAssociationCode method of the JavaClassGenerator, and when I included all the JET files I created and made the necessary changes ... the method code became "too large", and thus uncompilable. I heard whispers of this a few times over the term, and I believe it's why the Class and Interface generators were separated. At first, I took the code that I had added and created new methods to contain it (I talked earlier about the two cases for specializations, so there is one method for each case). That, however, revealed the real problem: the constructor for the JavaClassGenerator had become too large (since there were too many TEXTs).

The solution to this problem was inspired from the separation of the Class and Interface generators. I talked it over with Ellen and we figured that there may be a way to offload the specialization generation to another, new Generator altogether. Creating the new generator (and its skeleton) proved to be interesting, since there are properties (such as the getCode method) that were not required for the specialization generator; essentially what the new generator does is contain the code that was uncontainable in the JavaClassGenerator.

And so the problem was solved! It did take a little while to fix, though. I think it's a reasonable solution; eventually, if people keep adding code that needs to be generated, there's a chance that the class generator would be pushed over its limit. With the new skeleton, one could easily create a new mini-generator to include their code and simply instantiate one and call its methods while passing the stringBuffer and anything else that's required to go and get their code.

I really was not expecting the footprint of new JET files and the amount of code it would require be stored in the generators. In retrospect, I should have payed more attention to the scale of the changes, but I got caught up in the minute testing of specific instances of my changes (i.e. testing individual templates and not bringing everything together to see if it actually fits).

Either way, now I'm working on some minor bugfixes to my code as well as the testbed tests. All that's left really is to test the cases that I didn't get around to yet, and so far it's been going well.

November 25th, 2014

So I've been hard at work finishing up the specialization code. I ran into a snag earlier with the delete code (to my surprise), and I've been working through it. Essentially, the problem is that, if left as is with minimal tweaking, the delete code in the subclass would create null references that would be processed by the super class when the super.delete() line was reached: basically, you can't clear the list of elements from the subclass involved in a specialization, and the problem arises with the fact that the subclass needs to delete references to itself with respect to the multiplicity defined by the specialization (just using the super delete code would cause some aspects of the multiplicity to be ignored). The least invasive solution I found was to create a protected clear method to clear the list from the subclass -- the method is only generated once, in the parent association (based on whether or not it's ever specialized) and it's only ever used in the delete methods for the subclasses.

Now I'm just working though the last bit for the common class case. The small issue here is how the delete code figures out if it should delete the Object that currently contains the one being deleted (i.e. if A -- B, and we delete B, we need to know if we need to delete A). The complication is with the fact that there is only one delete method in B, and it needs to know which lower bound to check before deleting the A (i.e. if A -- B and A2 -- B, and we delete B, we don't know if B's list has As or A2s, so calling A.minNumberOfB(), for example, won't cut it since we're not sure which case we're dealing with). So I'm going to change the call from a general static call (so the ClassName.staticMethodName) to an instanced call so to speak (so InstanceOfClass.staticMethodName), and this should solve the problem.

I've been testing as I go along, and I will keep testing as I wrap up with the delete code. I'll report back with progress later.

November 23rd, 2014

I'm nearly done. I have all of the add, remove and set code finished, I just have to fix an issue I'm having with how I implemented the translation of the specialization functionality over to the AssociationVariables.

Previously, for debugging purposes, I had both the AssociationVariables (for a given Association) store whether or not the Association was a specialization. Yet there's actually a much easier solution: I'm currently implementing a way for the AssociationVariables to know if they need to invoke superClass methods (in the case of A2 if A1 and B1 are associated, and so are A2 and B1, A2 will need to use code from A1) or if they need to re-implement methods already implemented in their class (in the case of B1 from earlier -- it will need to know the maximum and minimum for it's A1s and A2s, and implement get and set methods accordingly). After this fix, it'll boil down to a little logic in the Set_All jet file and a few other files and we'll be golden. I have a solution in the works, and I'll be reporting back throughout the week with progress.

The beauty is it will all revolve around whether it's a superClass call or a method re-implementation. I'll need to find a schema for renaming the maximum, minimum, number of and required number of methods for the common class case (since B1 needs to know how many A1s and how many A2s it needs at the same time), and I think it will look something like maximumNumberOfA1_A2(), at least for the time being. That way, it's easy to encode it into the jet files, and it's guaranteed to be different for each specialization.

November 20th, 2014

I fixed the issue I was having with the get method that was returning a List. I also managed to do it without iterating through the entire list of Associations again. After some digging and tinkering, I saved into the associationVariables the end of the association they represent that is relevant to them, so that I can actually use the structures I put in place in the Association when using the association variables. This effectively solved the issue I was running into with passing the correct name that we need for the List< extends > syntax.

Now I'll be finishing up the code for the other methods. As I mentioned previously, there shouldn't be too many more hurdles -- most of the issue was with the casting of the list.

November 17th, 2014

Over the weekend I did some more work with the jet template files. I am currently testing out a way to save the super-association's class name in the specializee, since in order to properly use the List<? extends Something> syntax we need the superclass' class name. It's not very complicated, the only problem is that the sequence in which associations and association variables are managed it the UmpleInternalParser didn't quite work out too well for some of the other solutions I tried -- the association variables are created before the duplicate association names are checked, and I built my specialization detection method based on the duplicate name checking method, meaning that I can't really move my implementation up past the association variable creation.

What I -think- I'll have to do is go over each AssociationVariable in a class, get its appropriate association, get the appropriate end from that association, and then save the superClass name from there. The primary issue is that the code generator makes use of association variables, and not the associations directly, and to do half of the work I have to do I need to use the associations, and to get the other half working I need to use the association variables. As of right now, getting them to reference each other elegantly has eluded me. Besides, the current implementation will be irrelevant once Umple is updated to the next version of Java -- at that point, casting Lists becomes possible without having to go through the <? extends > syntax.

In other news, progress has been fair. As soon as I work out this little issue, the rest of the code gen should be pretty simple. It isn't difficult per se to get the code generating, it's little situations like these where we need an awkward solution that really are causing headaches. I don't foresee any more such scenarios, this one is the one that gave me the hardest time while I was testing various possibilities. I'll report back with an update on the legitimacy of my solution.

November 13th, 2014

I did some more work today on the jet files. I'm currently dealing with a fun little issue, though. Since Java 7 doesn't support the casting of Lists, we needed to use List<? extends Whatever>. The only issue now is having that code actually generated. The rest of the get many method is fine, the only thing is getting a reference to the appropriate class. I'm currently finding a way to add the name of the specializee's "super" association's class so that I can have it generated.

Otherwise things are going swimmingly. Let me just say that gen.translate is a lifesaver!

> Edit 1

I've been doing most of my work on the command line, until lately where I've had to alter the jet files to implement my changes. I had run into a wonderful issue where Eclipse was most likely creating files it had no permission to delete/execute, so doing a chmod -R 777 on all the files worked ... for the post part, bootstrapping was always an issue permissions-wise. Well, I've just solved my problem and it's pretty silly.

If you're on Unix and Eclipse's permissions don't make sense, you can solve it by going to the appropriate directory (to fine Eclipse Luna, or whatever the current Eclipse is) and perform the following:

sudo ./eclipse

and voila! Now Eclipse has all the permission in the world (well, in the system. But anyway...). There's a good chance this won't be a problem, but if ever it is, here is your answer.

November 12th, 2014

Today I started writing up the jet files. What the specialization code boils down to is a slight variation of the original specialization code, so as it stands I'm going to write new jet templates for each method that needs some attention (get, getMany, addOne, addMany, etc.), and to do that I'm going to use the already existing template file for the old code. More often then not it'll amount to inserting a few super calls, which can be done within the template file. I foresee the add and remove methods requiring the most work, so I've started with the get methods, as they needed the least invasive changes.

November 11th, 2014

So actually gen.translate() doesn't generate an entire method -- there's a lot more to the code in JavaClassGenerator than I thought. I took a look at the jet files (the source of the gigantic list of text variables at the beginning of JavaClassGenerator) and all translate really does is get the appropriate part of the association (in our case) and formats it to be used by Java (as I'm sure it does for the other languages).

Given that, my previous idea still does hold in part. I'll make use of translate to get the bits and pieces that I need from the AssociationVariables, and bar that I'll just have the code generated mimic the working code I have now. I'll make sure to check that I'm using gen.translate() to its fullest, though.

November 10th, 2014

So the gen.translate() methods don't look so bad. Looking at them in more detail has clarified a lot. I'm glad I decided to build the specialization functionality directly into the associations -- as I see it currently, translate is called with a method name as a string as it's first argument, and an AssociationVariable as the second argument (in our case, anyway).

See, if we do gen.translate("getMethod", someAssociationVariable), we will have the code appropriate to an association generated -- this is perfect. All I need to do is add a small check to see if the association in question is a specialization. If it is, we generate the code with the call to the superclass (or skip it entirely). The case where no code should be generated is already handled by the ClassGenerator. I could move the functionality over to .translate(), but we'll see about that one. It's essentially what I wanted to do, but instead of having it call or not call gen.translate(), or just generating the method by hand, it's actually a lot more elegant and reasonable to have it this way.

I've started tinkering with it and it looks promising! I'll report back during the week with updates.

November 5th, 2014

So I've been looking at the jet files in more detail. I ported over a good part of the code I had previously put only in the JavaClassGenerator to the jet format, but I'm having a permissions issue with Eclipse where it doesn't want to compile Umple properly -- I have a feeling this is because it is creating files that it doesn't have permission to change. I'm getting around it with a simple chmod 777 (excessive, I know) for now.

Now, the changes I need to make to code gen are going to need to be in jet files (as well as in the java) near as I can tell. It shouldn't be too bad, I'll create the code in the Class Generator, see if it works, and if it does I'll throw it into it's own jet file and move along from there. I saw that this was a solution people had used earlier (given the format of some jet files, e.g. <% java code here %>). Besides, I know the code that I want generated, and there are even situations where it's just better to not generate anything. I've been maintaining tests of all of my work, so no worries there. So far the changes I have been making have been working out quite well.

I should have more details tomorrow as I progress.

November 4th, 2014

So, after having worked on some more of my take on the generated code, I've started looking at the Jet files. I know that ultimately they will need to be changed in order for my changes to show. I think I'm getting a pretty good feel for them, so I'll just keep at it for a little longer and I'll start getting those changes implemented.

Speaking of, I'll include some of the code I'm planning to implement.

// The following examples are done using classes A and B, as well as subclasses
// Aa and Bb.

// Accessors
// 0..1 multiplicity case
public Bb getB(int index)
  Bb aB = (Bb)super.getB(index);
  return aB;

// 0..n multiplicy case
// (*) please see note following the code for details
public List<Bb> getB()
  List<? extends B> newB = super.getB();
  return (List<Bb>)newB;

// the following could probably be omitted -- the call to the superclass' method 
// would be implicit
public int numberOfB()
  int number = super.numberOfB();
  return number;

// Add method
public boolean addB(Bb aB)
  boolean wasAdded = false;
  if (indexOfB(aB) == -1) { return false; }
  if (numberOfB() >= maximumNumberOfB())
    return wasAdded; 

  wasAdded = super.addB(aB);
  return wasAdded;

* I added the Suppress Warning bit because there's a small issue with JDK 7 with respect to casting List<T> to a List.

I'll keep you all posted with updates as I continue working.

October 31st, 2014

Yesterday I finished porting the code over into a new method (from checkDuplicateAssociationNames) and, as near as I can tell, each of my test cases work. I'm still running some tests to make sure that there are no unforeseen problems, but so far so good. At this point I've also worked on and am still working on touching up the specialized methods to make use of the superclass' methods, so I'll report back with progress/problems as they occur. I'll be starting with the add method, and I feel like it'll look something like this:

public void add(Obj aA)
   // if list.length() < maxListSize() -- make sure we're not out of bounds
   // super.add(aA);

> Edit 1:

So I've discovered an interesting tidbit regarding JDK 7. There appears to be a bug where you cannot cast a List<? extends something> to a List<something>. In fact, I get the following error if I attempt to cast as such:

Aa.java:40: error: incompatible types
  List<Bb> newB = super.getB();
  required: List<Bb>
  found:    List<CAP#1>
  where CAP#1 is a fresh type-variable:
    CAP#1 extends B from capture of ? extends B
1 error

where super.getB() should return a List<? extends B>, of course with Bb extending B. I'm working on a workaround... as it stands, until they fix the bug, we may have to try an element-wise cast of the list. I'll be sure to be careful of runtime exceptions, though I have a feeling they may occur regardless with improper use of the associations.

> Edit 2:

It's working! I have a valid syntactic solution for the add(), get(index), getList(), numberOf(), has() and indexOf(). I'll work on the others shortly.

The solution for the the aforementioned problem was to make an unchecked cast down to the subclass, which I will test extensively.

October 29th, 2014

I recently discovered the source of the issue I'd been having. Originally, I had intended to hop on with the checkDuplicateAssociationNames method in order to discover specialized associations. One thing I did not realize, however, was that in said method, we're not looking for duplicate names globally, we're only looking on a class by class basis (which absolutely makes sense, we can have a variable A in as many different classes as we want). This, however, posed a problem.

The troublesome situation was that specialized associations weren't being detected in the both-ends-are-subclasses case. This is due to the fact that the specialized association's parent would not appear in the class' association list (and rightly so, an Aa -- Bb association has no business in class A or B).

What I'm going to do to solve this is port most of the link-building code over to a new method that parses through every association in the model itself, and then I'll make use of the functionality I added to associations to track their specializations in order to fix the code gen.

October 28th, 2014

I've been working on some more of the specialized code gen, but I've run into an interesting bug where specialized associations whose types are both subclasses of the association they are specializing are misbehaving. Consider the following:

  class A {}
  class Aa { isA A; }
  class B {}
  class Bb { isA B; }

  // given
  association { 0..5 A a -- 0..5 B b; }

  // the following work
  association { 0..3 Aa a -- 0..2 B b; }

  association { 0..4 A a -- 0..2 Bb b; }
  // this however does not generate the proper code
  association { 0..3 Aa a -- 0..2 Bb b; }

There's an issue with how the double specialized associations are being recognized. The more I think about it (and the more I write out the post), the more I feel like the problem stems from the fact that "parent" associations aren't being flagged properly. I included some code to flag them as such but I didn't end up needing it for what I was doing, and now I'm starting to think it needs a bit of work.

In other news, the code generated for the other cases compiles and works as expected. I could feasibly make a commit (when I get this particular case bug-free) with non-optimal, but working code (without the more technical overriding that we're looking for) and make commits as I include better code, but that's a discussion reserved for when I figure out this small bug.

October 24th, 2014

So I've fixed the bug I had run into with respect to restricting code generation. Originally, when I had stopped the parser from entering an error state if it saw what is now a specialized association, there was a ton of code being generated twice. Now I have all that duplicate code fully suppressed, I'm ready to get to the code generation.

The plan now is to come up with a solution that makes the most use of superclass method code. Since, in a specialization, we're dealing primarily with subclasses, we're going to have to intelligently use the superclass' methods -- this is going to be accomplished by polishing up the generated code in the subclasses. The nature of a specialization is that it's essentially the same as the association it's specializing, except that there are tighter restrictions to keep in mind. That being said, we don't want to reinvent the wheel in each specialized association, that would be a big waste of code, so in most cases generating an appropriate check with respect to the new multiplicity of the specialized association and then calling the superclass' methods should work.

Either way, I'll report back on my progress with the code generation as I go.

> Edit 1:

Speaking of progress, I've found an interesting issue... subclass accessors overriding superclass accessors works so long as the return type in the subclass is a subclass of the return type in the superclass, right? Well, it turns out that:

  class A {}
  class A2 { isA A; }

  public List<A> getAs() { ... }
  // the following is not a valid override
  public List<A2> getAs() { ... }

So I'm working on a fix for that now.

> Edit 2:

Fixed the problem!

The solutions is as follows:

//Old code in A:
public List<A> getAs() { ... }

//New code in A:
public List<? extends A> getAs() { ... }

This solutions solves all the overriding problems in the subclasses.

October 21st, 2014

I'm taking a moment to reconsider my strategy for Issue 417 (on Google Code). I'm almost at the point where I'll need to deal more thoroughly with the generated code, and I've been taking some time to think of what exactly we should do. Consider the following:

class Wheel {}
class Vehicle {}
class Bicycle { isA vehicle; }

association { * Wheel wheels -- 0..1 Vehicle vehicle; }

association { 0..2 Wheel wheels -- 0..1 Bicycle vehicle; }

In this case, without any constraints on code generation we would have the following generated in the Wheel class:

Vehicle vehicle;
Bicycle vehicle;

...which is incorrect. In fact, skipping out on the code generation for the Bicycle related code is a feasible solution here, given that a Bicycle is a Vehicle, so we could make use of typecasting. However, in a situation such as:

class X {}
class Y {}
class X2 { isA X; }

association { * Y y -- 0..2 X x; }

association { 0..2 Y y -- 0..1 X2 x; }

... ignoring the generated code for X2 would be incorrect, since the constraints are different. So what I'm looking to do is to generate something to the effect of:

X x;
X2 xX2;  //or xA or something.

Then, we could make use of method overloading to deal with a lot of the other conflicts. You would still be able to do something like someObject.getX(), but depending on if you're trying to save it into an X or an X2 it could use the appropriate method. I think this is fair, but I'm all ears otherwise. I'm not totally sure how easy just changing the name of the variable in a few cases will work, since we don't want to have to do .getX2() to get the X2, we should be able to do .getX() and then the correct method would be called. I may have to save a special name into the specialized associations, but I'll have to look into that to be sure.

October 16th, 2014

Another update for Issue 417 (on Google Code)!

After some testing, I ran into a few more bugs today. After spending time stopping the duplicate code generation issue, I (inadvertently) caused a bug where if you specialize an association with only one end being a subclass (and the other end's class being identical to its "parent" association), none of the relevant code is generated in the subclass. I have a pretty good feeling about what is causing this issue; it's either that the association variable is not properly added to the list of association variables, or there is a problem with how I am restricting the code generation. Either way, I have a potential fix in the works right now that I'll be trying.

Other than the bugs, things are going fairly well. When the code is actually generated, I'm able to actually use it (I've made up some test scenarios). I'm thinking that after the specialization functionality is implemented, I'd like to write a few examples to showcase the new stuff. All things in due time, though. I'll get these bugs sorted out as soon as I can.

October 15th, 2014

Update for Issue 417 (on Google Code)!

So, I opted for a more general solution. Instead of actually removing the offending associations from the list, I added functionality to the associations themselves to deal with the underlying structure of specialization, that is to say I added variables to the association class to keep track of whether or not it's specialized, whether or not it's a specialization, and finally a link to its "parent" association -- so a link to the association the current association is tightening. I felt like removing the associations from the list (the list in the appropriate class) could/would cause problems down the road, so this was preferable.

After adding the functionality, I had to make some modifications to the UmpleInternalParser -- particularly to the checkDuplicateAssociationNames function -- to actually make use of said functionality. When an association whose names matched a previously parsed association, the method treats it as a redefinition and deals with it differently. In particular, it creates the appropriate link between the association and its parent and checks if any class names match (as in, if the parent's classes matched the child's classes) and adds it to the child (so that the children can know if they are liable to generate duplicate code).

I ran into a bit of a roadblock here. It took quite a while to track down the most appropriate place to make use of my code. I even "wasted" a few hours trying to extend the functionality I added to the Association class into the AssociationVariable class, realizing finally that there was a way to return to the Association format from the AssociationVariables.

So the solution I went with was to implement some checks in the JavaClassGenerator. Each time the AssociationVariable list was worked through, I implemented a "call back" to the association version of the variable and made a check to see if the current AssociationVariable's class name matched the association's saved name -- this allows the code generator to make sure that the association it's dealing with is going to generate duplicate code. If the class names match, the code generator effectively ignores this AssociationVariable.

Finally, I compiled all of my changes and ran a few tests to see if my solution worked. As it stands, the code generated from my initial testing compiles and I'm read to write some tests! There are a few details to iron out first, but I should have a patch ready shortly.

October 13th, 2014

I've been looking into how associations are dealt with internally lately. I think the most direct way to deal with the extra code generation will be to actually remove the problematic end, i.e. take it out so that the code generator doesn't want to generate code for it. This may end up causing unforeseen issues with the usage of the classes, but I think typecasting should be able to handle it all. It's either that or we'll need to change the way specialized methods are named internally.

I have an idea in mind on how to remove the attributes, and bar that, I'll find the place where they are added and make sure that they are not.

October 9th, 2014

Aha. So today, I realized that things didn't magically work out.

After looking at some generated code, I have found an understandable and foreseeable issue. Specialized associations, left as is, generate the desired code... unfortunately, if one end of the association is shared with another (e.g. the Wheel -- Vehicle vs Wheel -- Bicycle scenario), the code is generated twice in the Wheel class. What ends up happening is all of the code that is required for the association's List implementation is generated as many times as the association is specialized.

One solution I'm going to look into is to find a way to let the code generator know if the list it's trying to generate is a specialization of another list. That, or I may have to find a way to deal with multiple lists internally (maybe by adding modifiers to the list names inside the classes). I think flagging the associations as either "specialized" or not may be the most ideal solution, but we'll have to see. There may also be a way to preemptively remove what would cause the duplicate code from the intermediate form, and that actually might be a lot cleaner. We'll see.

October 8th, 2014

This week, I realized my approach had some issues. After some testing, I found that I needed to add a serious bit of functionality to the association scanner (at least, the part that checks for duplicate names).

Previously, duplicate names were being checked on an "is contained" basis. So, there was really no way to just change the error message or edit that part of the code given what it accomplished, and besides, that bit still is relevant; if one end of an association has the same name as the same end of another association, we don't want that, since it's not a specialization. I needed to add the ability for the parser to recognize pairs of names, so I added 2 lists, one for each end, to keep track of the association pairs -- just the names currently (I may yet just change this to an array of associations).

Given that, I added a check to see if the left hand side's name matched a name in the appropriate list. If it did match, I check if the right hand side's name also matches the appropriate name in the appropriate list (i.e. at the same index, but in the right hand side's list). So basically we're checking for a pairwise match. In the case of such a match, the association is being redefined with the same names on each side, which is what we're looking for in a specialization.

The funny part is that, from that, the rest of the project just falls into place. After running a few little tests (simple ones, mind you), I found that the code generated if we consider the new association as-is is totally fine, the correct bounds are in place with the appropriate checks. It's not like the specialized association requires the code generator to generate substantially different code, it's just an association but it happens to share a name with another one.

The plan now is to write a lot of tests to make sure the code is properly generated in all cases (I have a few issues in mind that I'm looking out for, like if code is generated twice). If I run into any issues, the functionality is all in place within the parser to deal with the details, all we'll have to do is add more checks in the section I added to the parser. I should have an update on this before the hangout Friday.

October 4th, 2014

I've made some progress on Issue 417 (on Google Code). As per our hangout on Friday, I had mentioned that I found out where in the code the redefinition of an association was being caught. I was able to implement a check and an appropriate error message that detected the specialization of an association.

Now, instead of an error, the following code generates a little warning letting the user know they are trying to specialize an association:

class Wheel {}
class Vehicle {}

association { * Wheel wheels -- 0..1 Vehicle vehicle; }

class Bicycle { isA Vehicle; }

association { 0..2 Wheel wheels -- 0..1 Bicycle vehicle; }

The plan now is to, instead of abort with an error message, guide the code generator through the process of specializing the association. I'm hoping that I'll be able to edit the parameters of the association for the child class by changing them to the specialized parameters, and bar that, I may have to touch upon the code generator a little bit more (maybe by adding an appropriate flag) to make sure it checks for the specialized parameters, and not the general ones.

September 27th, 2014

A little late on the log post this week, sorry!

I've been working this week on Issue 429 (on Google Code). I almost have a solution, I just need to get it in place and test it out. I feel that Issue 417 (on Google Code) (a little bit of a larger project) will follow naturally from 429 -- they both seem to deal with essentially the same part of the code. So as a larger short term project, I will definitely be looking into 417.

I also just found Issue 444 (on Google Code), and I have a potential solution in mind. We could feasibly add a feature to how exceptions are handled in Interfaces, and give them a separate clause to detect actual method code. This would lead to slightly better documentation and organization of the Interface code. At a glance I have a few ideas for this one, so I'll get to work.

The Code Sprint really helped put all the Umple compiler code into perspective, I have a much better handle on where things fit in and where to find relevant code to a given issue I'm having. Working on new issues has been a lot less daunting (and more productive) since then.

September 22nd, 2014

Code Sprint Recap

So the code sprint was this weekend. It was an amazing experience and everyone was great and very helpful.

Concerning Issue 451 (on Google Code), the solution we devised had us make use of the Class' Exception functionality, except I had to make some changes to the functionality so that it worked for Interfaces. I realized on Saturday that the classes rarely (I say rarely because I haven't seen it happen yet) get to the point where they need to use extra code, and so most of the errors were being tokenized as Exceptions. After that, it was pretty clear, and I modified the parser and the grammar accordingly. At this point, given the robustness of the Exception token, we may be able to implement better error messages (like warning the user that they can't have non-constant data or any method code in an interface), so I'll look into that too.

Concerning the testing environment, I committed some changes to the testing functionality so that tests properly fail (instead of ending in an error state) when the tester attempts to access an array element that doesn't exist. If I ever find myself with nothing better do work on, I'll run through the other tests and make updates as necessary.

Moving forward, I might like to try my hand at Issue 76 (on Google Code) and Issue 429 (on Google Code). I'm still very interested in the parsing and code generation aspect of Umple, and I'm still looking for a bigger project to work on during the term. In the meantime I'll keep busy with bug fixes.

September 19th, 2014

So, a few things today. Firstly, the fact that the definition of a class in the grammar includes a semicolon (and the interface does not) was not the fix we were looking for. I've been able to prove that the changes I was making were effecting the generated code so that's definitely not the problem. At this point, there's a chance that the problem is with the parser throwing out tokens when it's dealing with an interface, but again the key will be to find where the parsing is different with interfaces vs classes.

In terms of progress, Andrew helped me create test cases (for test-driven development) so that should make things a lot easier to pinpoint. Previously I had been rebuilding Umple each time I made a change and was using my own test file to figure it out.

In terms of a term plan, after I figure out the extra code problem for interfaces, I'd like to work on the Aggregation-Association problem (I mentioned the implementation of deep copies). I'm also interested in projects involving the syntax/semantics of Umple (Issue 127 (on Google Code)), or just adding a syntactical feature in general. I'll iron out my plan over the rest of the weekend as I work toward fixing my current issue.

September 15th, 2014

Today I spent some time with the Umple grammars. I had to fix up my directory because of some issues I may have been having (the curly brace error most of us were having is a potential source) so I have moved fully to the command line.

Now, in the grammars I discovered something. For the typical Class grammar, a semicolon is included in the definition of the components. For the interfaces, this is not the case. I tried testing, but due to aforementioned issues, I'll have to test it a little more and post tomorrow about the results.

September 12th, 2014

Just a small update today, in particular for Issue 451 (on Google Code). I'm still looking into where exactly the parser decides that everything after an error in an Interface is extra code. I've walked backwards through the JavaInterfaceGenerator and the methods/functions that are called to look for answers. On the bright side I'm getting a fairly good feel for the structure as a whole!

After our Hangout, I looked into how JavaClassGenerator deals with the extra code as opposed to JavaInterfaceGenerator. For the class generator, extra code is treated as developer code, which is fine, since then the programmer could put his target language code right into the Umple code. For interfaces, as soon as there is an Umple syntax error, all subsequent code is treated as extra code (as per Issue 451 (on Google Code)). The warning message that is displayed for classes is exactly what we need for interfaces, so I'll be perusing the JavaClassGenerator to see where it differs from the JavaInterfaceGenerator (of course with regards to extra code).

One more thing I noticed; the following code generates a warning (Warning 1007) when compiled:

class Constantinople
	int int int int;

... but the following does not:

class Constantinople
	int int int int

In both cases the "int int int int" (with or without semicolon) is considered as extra code. I'm fairly sure the warning isn't generated on account of the parser not knowing what to do with the missing semicolon.

September 9th, 2014

To better understand the code generation process, I've been looking into better understanding the UmpleModel. Currently I'm interested in working on the problems with Interface generation (Issue 451 (on Google Code) and Issue 442 (on Google Code)), and as such I've been spending most of my time reading through the various Interface generation files.

I had a little issue with an extra curly brace that was getting generated in DocumenterMain.java (line 72 in particular). I'm still not entirely sure what caused the curly brace but I'll definitely look into it. Ellen also ran into this issue. It cropped up after we compiled Master.ump.

I have a feeling UmpleModel will take a little bit of time to work through, as it is a pretty enormous file.

On the subject of interfaces, I think it would be a good idea to generate a warning of sorts if the .ump file does not explicitly declare the data fields to be constant (for Java at least, this is detailed in http://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html). It's a little silly though, because if you don't declare the data to be "final" in an interface (in Java), there isn't an error at compilation time, but there is a runtime error if you try to change it.

September 5th, 2014

Earlier this week I finished setting up the development environment for my Windows 7 partition (so I configured Eclipse, downloaded ant and svn, etc.). I learned that Windows has some drawbacks when developing for Umple, so I'll be setting up a Linux partition later this evening.

On the subject of Umple itself, I played around quite a bit with the online tool, and discovered that, at least in the Java generated code, aggregation wasn't fully implemented and associations produced shallow copies when dealing with what essentially amounts to Object data fields. This is a known issue that I'd love to work on once I have a few more commits under my belt.

I didn't have all too much trouble installing everything (the directions provided on the wiki for those looking to contribute are very clear). This weekend I'd like to get familiar with command line Umple (and also set up my Linux partition). I'll also familiarize myself with how to patch, and I'll browse the issues to find something to work on.

Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.