Discussions

News: Gemini 1.0 released: bidirectional relationships for POJOs

  1. Gemini 1.0, an annotation-based framework that enables bidirectional relationships for POJOs, has been released. Gemini has no requirement for a container or specific APIs outside of the annotation capability.

    Gemini has been designed to maintain relationships between objects. The examples the project pages provide is for a Company-to-Employee relationship, where the Company has many Employees and the Employees have one company. Through the use of the two annotations provided (@BidirectionalOne and @BidirectionalMany), the object relationships can be maintained by modifying one object instead of having to manually set the relationships.

    For example, an Employee being added to a company might require two method calls:
    // assume company and employee have been instantiated

    // does the equivalent of company.getEmployees().add(employee);
    company.addEmployee(employee);
    employee.setCompany(company);

    However, with Gemini, only the first or the second method call is required. The synchronicity is maintained by the annotation code, rather than mandating that the programmer call both mutators. The code for this is expressed as follows:
    class CompanyBean implements Company {

      @BidirectionalMany(oppositeName="company")
      List employees = new LinkedList();

      public List getEmployees() {return this.employees;}
      public void addEmployee(Employee e) { getEmployees().add(e);
      public void setEmployees(List employees) {this.employees = employees;}
    }

    class EmployeeBean implements Employee {

      @BidirectionalOne(oppositeName="employees",
              oppositeType=BidirectionalMany.class)
      private Company company;
      
      public Company getCompany() {return this.company;}
      public void setCompany(Company company) {this.company = company;}
    }

    Gemini is dual-licensed, under the GPL and under a commercial license (which costs $23 USD). Building with Gemini requires AspectJ at build time, but not at runtime.

    Do you think functionality like this might be useful?

    Threaded Messages (29)

  2. dual license?[ Go to top ]

    I am surprised to see dual license here for such a small little feature but why not..
    Nick Lesiecky wrote about how to implement such a feature for Hibernate 2.x POJO for AOSD 2005 conference, based on his experience at VMS as far as I remember. I don't know if his paper is available somewhere.

    Don't EJB 3, Hibernate (and SDO?) have that already within the persistence domain?
    If so couldn't you reuse the EJB 3 annotations instead?
  3. EJB 3 and Hibernate[ Go to top ]

    No, EJB3 and Hibernate do not support managed relationships. They support bidirectional relationships only when it comes to the storage in the database, so you don't get two redundant database updates (inverse="true"). You still have to set both sides manually in your Java code.
    Additionaly, if EJB/Hibernate annotations were used, it would tie users to use these frameworks/specs if they want bidirectional relationships.
    Gemini does this in a more general way - you can have bidirectional relationships with simple POJOs, AND you can use it as a supplement to EJB3/Hibernate/some other O/R framework.
  4. Not really[ Go to top ]

    I don't think saving two lines of code will make me use an extra annotation. Given that I still think annotations are hard to read (syntax wise), I would only use such a tool if it gives me a clear advantage. The only thing this annotation gives me to start with is confusion. Like, why is it called bidirectional instead of unidirectional to start with :-).
  5. Not really[ Go to top ]

    Can the same not be achieved by using a custom collection (*-directional collection). In the add method the relations can be set. No config no annotations, plain old java. Or am i missing something here?
  6. Not really[ Go to top ]



    import java.util.ArrayList;
    public class Organisation {
    public class Contact
    {
    private Organisation organisation;
    public void setOrganisation(Organisation organisation) {
    this.organisation = organisation;
    }
    public Organisation getOrganisation() {
    return organisation;
    }
    }
    public class ContactList extends DirectionalCollection<Contact>
    {
    public void add(Contact c){
    c.setOrganisation(Organisation.this);
    list.add(c);
    }
    }
    public class DirectionalCollection <T> {
    public ArrayList<T> list;
    public void add(T obj){
    list.add(obj);
    }
    }
    }

  7. I think you are missing something[ Go to top ]

    Regarding custom collections:
    1. What would you do with simple fields?
    2. For Collections, lists. etc:
    a) You have to write a new DirectionalList subclass for every property that you want to be bidirectional
    b) Each of these subclasses must deal with a lot more than just adding new elements (addingAll, removing, iterating, handling exceptions, etc.) AND each of these functionalities must be tested again and again (if you want to rely on these lists)
    That means that if you write these collections, you end up with several times more classes in your domain model just to achive bidirectionality.
    The point is NOT whether this functionality (but only with collections, not simple fields) can be achieved with bidirectional collections (Gemini internally use its generic bidirectional collections), but how complicated is it. With Gemini, you use only one annotation per field, you do not need any configuration. I can't see a simpler way to do this. The only simpler way (regarding the code) would be that this is the default and that you write no single piece of code...
  8. I think you are missing something[ Go to top ]

    1. What would you do with simple fields?
    I dont know what you mean here. Can you please explain.
    2. For Collections, lists. etc:a) You have to write a new DirectionalList subclass for every property that you want to be bidirectionalb)

    You also have to write a annotation for every property. But as i think of it with custom collections you cannot see what the name of the property is when the type only comes in so there is something missing.
    Each of these subclasses must deal with a lot more than just adding new elements (addingAll, removing, iterating, handling exceptions, etc.)
    That can also be done in one place with custom collections.
    That means that if you write these collections, you end up with several times more classes in your domain model just to achive bidirectionality.
    I end up with more classes anyway because i dont like my java to look like html;-) Anyway, I am kind of convinced but i am also afraid that this whole annotation thing will end up like xml ended up. Every framework will come with it's annotations. Eventually there will be more annotatins than code (maybe not such a problem when folded by the editor). And how refactorable are path expressions?
  9. I think you are missing something[ Go to top ]

    1. What would you do with simple
    fields?
    I dont know what you mean here. Can you please
    explain.
    An example is Employee.company. When you set a new value of company
    you have to remove the old value (and update its opposite, which can
    involve some more checking), then update the opposite of a new value
    etc. At least several lines of code (if you are lucky and do not want
    to go too deep) which have to be written for EVERY field, and tested
    for every field.
    2. For Collections, lists. etc:a) You have to
    write a new DirectionalList subclass for every property that you want
    to be bidirectionalb)
    You also have to write a annotation
    for every property. But as i think of it with custom collections you
    cannot see what the name of the property is when the type only comes
    in so there is something missing.
    You do NOT have to write a NEW annotation, you just have to USE
    @BidirectionalOne or @BidirectionalMany. It is something like writing
    "class" or "public". In my opinion, a lot easier than writing any real
    code...
    I end up with more classes anyway because i dont like my
    java to look like html;-)
    Well, annotations are a part of Java language, so you don't have to
    worry about that :)
    Anyway, I am kind of convinced but i am also afraid that this whole
    annotation thing will end up like xml ended up. Every framework will
    come with it's annotations. Eventually there will be more annotatins
    than code (maybe not such a problem when folded by the editor). And
    how refactorable are path expressions?
    As every new thing, annotations still have a task of convincing
    enterprise developers to use it. It is better that every framework
    come up with its annotations, than that every framework come up with
    its classes that you must extend and stuck up with. In the end - you
    need a right for the task - annotations are a poor tool for some tasks
    but an excellent tool for some other tasks. The same goes for XML -
    sometimes it is good, sometimes it is not that good.
    As for editor cappability - I wouldn't worry about that, it is handled
    by editors just well (i.e. Eclipse supports code completion,
    refactoring etc.)
    I think the best move (if you need this kind of functionality) is to
    try this approach - compare it to other approaches and see if it suits
    you :)
  10. Annotations vs Classes[ Go to top ]

    ...It is better that every framework come up with its annotations, than that every framework come up with its classes that you must extend and stuck up with.

    While I am trying to keep an open mind about Annotations (and AOP as well for that matter), and this code has got me intrigued about the various possibilities...

    I'm not sure that tying my application to a set of required annotations that may not be supported by a different framework is any better than using a set of classes provided by a different framework.

    rob.
  11. Not the point[ Go to top ]

    I don't think saving 1 line of code is the point. I would imagine enforcing consistency is the benefit. With the 2-line method, you could easily forget one of the method calls, leaving your model in an inconsistent state. The annotation approach would ensure that doesn't happen. That's not to say I'm sold on it - it's just the one benefit that seemed most clear to me.
  12. Not the point[ Go to top ]

    I don't think saving 1 line of code is the point. I would imagine enforcing consistency is the benefit.
    +1
    That is the idea.
  13. Not Really[ Go to top ]

    I think to save two lines of code, I am not going to change all my POJOs. There is no extra benefit by using such annotation.
    In Hibernate, the relationship is maintained in DB.
  14. Interesting[ Go to top ]

    class CompanyBean implements Company {

      @BidirectionalMany(oppositeName="company")
      List employees = new LinkedList();

      public List getEmployees() {return this.employees;}
      public void addEmployee(Employee e) { getEmployees().add(e);
      public void setEmployees(List employees) {this.employees = employees;}
    }

    Does setEmployees(List employees) method should not be protected or even private ?

    I mean, being it public, any client could easily corrupt employees list. I usually prefeer to have addEmployee and removeEmployee (to apply the business rules) but not the mutator for the employees List.

    Humm, may be this is because it is JavaBeans compliant, right ? What about JavaBean default empty constructor, it is necessary too or just the get/set are required ?
  15. Interesting[ Go to top ]

    Let's not overanalyze sample code written in haste :)
  16. Interesting[ Go to top ]

    Does setEmployees(List employees) method should not be protected or even private ? I mean, being it public, any client could easily corrupt employees list. I usually prefeer to have addEmployee and removeEmployee (to apply the business rules) but not the mutator for the employees List.
    You can do whatever you prefer. Your setters can be public/private/protected, or you could remove them and initialize the new List in the constructor.
    Gemini does not care about that nor it is affected by your choice.
    The point of this example is to be SIMPLE.
  17. Db4o ?[ Go to top ]

    Hmm, very interesting. How about to use gemini with db4o ? :) As I remember, it was always uncomfortable to use relations within this database. Anyone tested it ? :)
  18. Test methods?[ Go to top ]

    This could be beneficial if the framework supported the specification of test methods to see if the potential relationship violates business rules. For those who aren't aware, the book "Streamlined Object Modeling" by Nicola et al discusses this very thoroughly.

    In the Company/Employee example, a complete implementation would be:
    <code>
    // Company.java
    public class Company {

        protected Collection employees = new ArrayList();

        public void addEmployee(Employee e) {
            if (e == null) {
                throw new IllegalArgumentException("no employee given");
            }

            e.setCompany(this);
        }

        protected void testAddEmployee(Employee e) {
            // Check business rules here; throw exception if violated.
        }

        protected void doAddEmployee(Employee e) {
            // Actually add Employee, bypassing business rule checking
            employees.add(e);
        }
    }

    // Employee.java
    public class Employee {

        protected Company company;

        public void setCompany(Company c) {
            if (c == null) {
                throw new IllegalArgumentException("no company given");
            }

            // An Employee is more specific than a Company,
            // so Employee directs the establishment of the bidi relationship
            // (see book "Streamlined Object Modeling").

            // Check business rules first.
            testSetCompany(c);
            c.testAddEmployee(this);

            // If we get this far, business rules have been checked;
            // actually create the bidi relationship now.
            doSetCompany(c);
            c.doAddEmployee(this);
        }

        protected void testSetCompany(Company c) {
            // Check business rules here; throw exception if violated.
        }

        protected void doSetCompany(Company c) {
            // Actually set the Company, bypassing business rule checking.
            company = c;
        }
    }
    </code>

    If Gemini would allow me to specify the test methods and generate the setXXX/addXXX/removeXXX methods, it would save a lot of code. The end result of this code would be to generate the public setXXX/addXXX/removeXXX & protected doSetXXX/doAddXXX/doRemoveXXX method. Scopes could also be provided to the annotation. The resultant annotated code would look something like the following:
    <code>
    // Company.java
    public class Company {

        @BidiCollection(
            targetClass=Employee.class,
            targetField="company",
            targetTestMethod="testSetCompany",
            thisTestMethod="testAddEmployee"
        )
        Collection employees = new ArrayList();

        protected void testAddEmployee(Employee e) {
            // Check business rules here; throw exception if violated.
        }
    }

    // Employee.java
    public class Employee2 {

        protected Company company;
        
        protected void testSetCompany(Company c) {
            // Check business rules here; throw exception if violated.
        }
    }
    </code>

    This annotation would be for a one-many bidi relationship manifested as a Collection. Other annotations would include @Bidi (for one-one), @BidiMap (for one-many map).

    Alternatively, instead of one big annotation, the annotations could be on each piece involved.

    I think its interesting.

    --matthew
  19. Test methods?[ Go to top ]

    @Matthew

    No, Gemini does not handle test methods, because it is a framework for bidirectional relationships. Addin such thing would just overcomplicate the framework, which aims to be extremly focused and easy to use.

    But, I am aware of such approach of building strong domain models. In fact, I will soon publish an annotation-based framework (Ananke) that does constraint checking on relationships, an it is much easier to use (and requires a way less coding) than the example you have shown. You would need to annotate a field and tell the framework which constraint to use (and you could write custom constraints or combine some already made, like commons-predicates, predicates from commons collections etc.). Of course, its functionality fits perfectly with Gemini...
  20. Streamlined Object Modeling[ Go to top ]

    Hi Matthew

    After waiting some months, I finally received my copy and have been reading SOM book last week. It is simply amazing.

    I agree Gemini could be much more interesting by supporting SOM test methods. Actually it is a brilliant idea !

    In fact, I also was investigating on how to hack the "DIAPER" process SOM authors presents to eventually simplify the boilerplate (but also bulletproof) code of both Profile and Conduct Business interfaces and related implementations, probally using new Java features like annotations or even a totally new JVM based language like Nice.

    Nice has things like value dispacth and abstract interfaces and I guess SOM collaboration patterns implementations could leverage these features.

    Would be very nice to see Jill Nicola et al writing may be an article with some update for DIAPER process by using some new Java features or even some JVM language like Nice or Scala. Then we could keep with JVM but perhaps writing even less code than these Ruby guys ;-)
  21. "Do you think functionality like this might be useful?"

    No.
  22. Simple Principle - Roll Your Own[ Go to top ]

    I like the idea of using annotations to enforce the principle, but the notion of removing the 'code couplet' is easily achieved with your own code.

    I wrote a paper on this quite a while back. I have it available on my website at

    http://http://www.javaguy.org/papers/

    scroll down to the 'Maintaining bi-directional relationships in Java' PDF file.

    -db
  23. Towards a more domain focused code[ Go to top ]

    As a tool it seems to be quite limited in scope but at the price point it still seems quite useful.

    However if I was to consider this to be one of the relatively early commercial offerings which offered a combination of aspects and annotations in a non-intrusive way, I think a broader array of such tools will allow us to focus on more domain focused programming since the combination of aspects/annotations will reduce our development efforts one line at a time.

    Small steps but important ones I think.
    +1.

    Dhananjay
  24. I think a broader array of such tools will allow us to focus on more domain focused programming since the combination of aspects/annotations will reduce our development efforts one line at a time.

    I very much agree about more domain focused code, and that annotations and (maybe) aspects will be very important in achieving it.

    However, I think the problem being solved by Gemini could be more cleanly solved using a couple generic classes and letting them maintain the integrity of the relationship.

    Personally, I think aspects smell bad. I understand their utility, but I think they are a workaround to the lack of metaprogramming facilities in Java.
  25. For the code saving part: how about just creating a couple of code templates (in your fav IDE/ editor) for things like this? If you are worried about lines of code, well... that's the way to go imho (or use plain old OO techniques).
  26. For the code saving part: how about just creating a couple of code templates (in your fav IDE/ editor) for things like this? If you are worried about lines of code, well... that's the way to go imho (or use plain old OO techniques).
    Although the way to solve this problem can be discussed, I don't see how template from an IDE could help, even with line saving?
    That would be like implementing OO techniques with pure procedural code using IDE code templates (just with diferent level of complexity).
    One more time - it is not just about saving lines of code (especially on the client part), but in creating simpler, more consistent and domain focused code.
  27. I think this is another AOP - it looks like there might be some mileage in it with simple examples, but if you use it in any real way you end up six months down the line with an unholy mess that you just can't trust.

    I wonder too about binary compatibility, with annotations being interfaces. Just another factor to add to the dependency soup.

    And seeing comments like 'at this price point' - if it were completely free it wouldn't have gotten the interest it did. A sad indictment? On them or you?
  28. but if you use it in any real way you end up six months down the line with an unholy mess that you just can't trust.
    Do you have some real reasons to think that , or you just guess?
    if it were completely free
    It IS completely free - General Public License.
  29. hi!

    Some time ago i've created a small helper library for exactly the same purpose because i've found myself coding the same pattern in accessors again and again. There is hardly any project now where I don't need that functionality. So i actually do think that Gemini solves an important (little) problem, because getting the necessary checks for correct bi-directional relationships correct is not completely trivial and certainly annoyingly repetitive.

    (Sorry if this is a FAQ:)

    Without having looked into how Gemini does it's trick: do you see any problems with using it on fields that are managed by Hibernate using field access (as opposed to property (getter/setter) access), also considering that Hibernate substitutes it's own Collection classes on-the-fly?!

      cheers,
      gerald

    http://www.gerald-loeffler.net
  30. Without having looked into how Gemini does it's trick: do you see any problems with using it on fields that are managed by Hibernate using field access (as opposed to property (getter/setter) access)
    Gemini handles it! In fact, you could set a field directly (bypassing the setter) and it will still work, because Gemini is "guarding" fields, not set/get methods.
    , also considering that Hibernate substitutes it's own Collection classes on-the-fly?!
    The answer is, again: YES, it does work.
    Hibernate substitutes the original collections with its own and in fact does not like anyone to change them once they are set! Gemini is designed with that in mind. See this page for the reference if you want to use Gemini with Hibernate, especially look at BidirectionalMany().initOnlyFirstTime(), which should be set to true (the default is false): http://www.e-nspire.com/portal/content/view/19/36/1/2/