@GettersAndSetters annotation

294 views
Skip to first unread message

MattH

unread,
Dec 9, 2009, 4:11:45 PM12/9/09
to Project Lombok
A have forked lombok and added a new @GettersAndSetters annotation. It
is a crude copy of HandleData but it solves my larger issue with how
we deal with equals and hash code in an abstract class. I also did not
want to stray too far from the main lombok classes for easy updates.
It would be nice to see this in the main lombok source. I would be
happy to send the code if you are interested. If this were introduced,
a small refactor of HandleData would be in order.

-Matt

Reinier Zwitserloot

unread,
Dec 10, 2009, 11:32:10 AM12/10/09
to Project Lombok
Exactly what does @GettersAndSetters do differently from @Data?

Roel Spilker

unread,
Dec 10, 2009, 11:50:12 AM12/10/09
to Project Lombok
Is the only difference is a different implementation for equals and
hashcode, you could also consider creating an annotation to generate
those two methods. If the user then places that annotation before the
@Data annotation, @Data will see the generated methods and skip them.

Matt Higgins

unread,
Dec 10, 2009, 12:36:09 PM12/10/09
to project...@googlegroups.com
The difference is I do not generate the equals and hash code methods as the abstract class implements them. This annotation only produces getters and setters. I know with @Data I could create equals/hashcode methods in each subclass to exclude the auto generated equals/hashcode. I am also ware you can have the generated method call the super class equals. In my case I don't want either of these. My current use case is an abstract class has the ability to determine equality/identity of subclasses. If I use @Data i would be putting more boiler plate code back into each sub class to override the auto generated equals / hash code or use many individual @Getter / @Setter annotations. 

-Matt

--
You received this message because you are subscribed to the Google
Groups group for http://projectlombok.org/

To post to this group, send email to project...@googlegroups.com
To unsubscribe from this group, send email to
project-lombo...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/project-lombok?hl=en

Reinier Zwitserloot

unread,
Dec 10, 2009, 1:37:32 PM12/10/09
to project...@googlegroups.com
Lombok busts boilerplate. Perhaps we should clarify this; we're talking about common code that is effectively meaningless, _that is common for your average java programmer_.

Hence, your need doesn't qualify. If we did add @GettersAndSetters, who, other than you, would use it?

Lombok has an alternative mechanism for your use case: Lombok extensions. So, no, we won't be adding this to the Lombok distribution itself, but we will put in all due effort to make sure you can write and use @GettersAndSetters as an extension.

 --Reinier Zwitserloot

Reinier Zwitserloot

unread,
Dec 10, 2009, 2:47:43 PM12/10/09
to Project Lombok
For your specific case, I have two alternative suggestions:

1. Move away from an abstract superclass that handles equality and
hashCodes. This approach just doesn't work very well. For example,
this precludes you from subclassing anything else, and it also doesn't
fit with java design aesthetic; superclasses are not supposed to know
about any non-public state of subclasses, and equality and hashCode
should be decided by the most specific subclass in a hierarchical
chain, as otherwise you can't properly guarantee transitivity.

2. Use @Data, and add the very much NON boilerplate aspect of: "I take
my equals and hashcode from my superclass" as an explicit aspect to
your source:

@Override public int hashCode() {
return super.hashCode();
}

@Override public boolean equals(Object o) {
return super.equals(o);
}

Lombok's @Data will not overwrite such explicit hashCode and equals
methods.

On Dec 10, 7:37 pm, Reinier Zwitserloot <rein...@zwitserloot.com>
wrote:
> Lombok busts boilerplate. Perhaps we should clarify this; we're  
> talking about common code that is effectively meaningless, _that is  
> common for your average java programmer_.
>
> Hence, your need doesn't qualify. If we did add @GettersAndSetters,  
> who, other than you, would use it?
>
> Lombok has an alternative mechanism for your use case: Lombok  
> extensions. So, no, we won't be adding this to the Lombok distribution  
> itself, but we will put in all due effort to make sure you can write  
> and use @GettersAndSetters as an extension.
>
>   --Reinier Zwitserloot
>
> On 10 dec 2009, at 18:36, Matt Higgins <matt.higg...@gmail.com> wrote:
>
>
>
> > The difference is I do not generate the equals and hash code methods  
> > as the abstract class implements them. This annotation only produces  
> > getters and setters. I know with @Data I could create equals/
> > hashcode methods in each subclass to exclude the auto generated  
> > equals/hashcode. I am also ware you can have the generated method  
> > call the super class equals. In my case I don't want either of  
> > these. My current use case is an abstract class has the ability to  
> > determine equality/identity of subclasses. If I use @Data i would be  
> > putting more boiler plate code back into each sub class to override  
> > the auto generated equals / hash code or use many individual  
> > @Getter / @Setter annotations.
>
> > -Matt
>
> > On Thu, Dec 10, 2009 at 11:32 AM, Reinier Zwitserloot <reini...@gmail.com
> > > wrote:
> > Exactly what does @GettersAndSetters do differently from @Data?
>
> > On Dec 9, 10:11 pm, MattH <matt.higg...@gmail.com> wrote:
> > > A have forked lombok and added a new @GettersAndSetters  
> > annotation. It
> > > is a crude copy of HandleData but it solves my larger issue with how
> > > we deal with equals and hash code in an abstract class. I also did  
> > not
> > > want to stray too far from the main lombok classes for easy updates.
> > > It would be nice to see this in the main lombok source. I would be
> > > happy to send the code if you are interested. If this were  
> > introduced,
> > > a small refactor of HandleData would be in order.
>
> > > -Matt
>
> > --
> > You received this message because you are subscribed to the Google
> > Groups group forhttp://projectlombok.org/
>
> > To post to this group, send email to project...@googlegroups.com
> > To unsubscribe from this group, send email to
> > project-lombo...@googlegroups.com
> > For more options, visit this group at
> >http://groups.google.com/group/project-lombok?hl=en
>
> > --
> > You received this message because you are subscribed to the Google
> > Groups group forhttp://projectlombok.org/

Matt Higgins

unread,
Dec 10, 2009, 4:13:56 PM12/10/09
to project...@googlegroups.com
This is quite a common use case in fact when using JPA, where an abstract entity determines identity via the equals method of a super class . Further more equals and hashcode are hardly meaningless and have much deeper implications then setting a simple field or getting a value. These methods are often domain specific and in many cases out side of my jpa example can not be simplified, so either write one per class, or abstract if possible. I am not asking for this to be introduced into lombok merely a suggestion for you to take or leave, where a touch of flexibility can go a long way. In the JPA case equality is very difficult to define and the community at large debates over this all the time. The JPA debate does not need to be continued here but a simple out where equals and hashcode are excluded from the class level annotation allows developers the ability to solve the problem on their terms with their business needs in mind. The obvious benefit is less code, no getters and setters, and only one annotation.

I looked around your site and could not find anything about extensions. Is this a forthcoming feature ?   This sounds very interesting could you point me to some documentation? Since you are not interested in this approach it would be convenient to keep it on it own.  

-Matt

Reinier Zwitserloot

unread,
Dec 10, 2009, 11:04:05 PM12/10/09
to Project Lombok
As far as I'm aware, the only practical arguments in JPA world
regarding equality/hashCode is this:

1. Should we define equality based on a POJO's nature (so, the actual
fields that comprise the meat of the POJO; let's say for a person,
name, birthdate, social security number, etc).

-or-

2. Should we define equality based on a POJO's primary key (so,
whatever fields comprise that POJO's primary key. Usually a numeric
'unid' field that is on auto-increment in the db).


Lombok supports both of these cases via the use of the 'of' or
'exclude' parameter to @EqualsAndHashCode (which you can also stick on
a @Data annotated class to set specific properties for equals and
hashCode).


The rarer alternative case involves handrolling an equals and hashCode
method, which is also supported by lombok (just do it; lombok does not
overwrite existing methods).


Your case is exceedingly rare (or I could be mistaken, of course. A
pointer at 'proof' that this is quite common would help here), and can
be fixed quite easily by one of three methods:

method A: Forego @Data, as your class isn't really a straight up no-
frills struct class. Instead, add @Getter and @Setter where needed, as
well as @ToString.

method B: Use @Data, and put in expicit equals and hashCode methods
(even if they do just call super.hashCode and super.equals).

method C: Use an extension.


Extensions aren't completely documented just yet - we're planning on
adding some videos to give people a walkthrough on how to do it,
instead of reams of documentation, which is harder to write, and for
you harder to grok, than video. Nevertheless, just grab the lombok
sources and check out the existing handlers (HandleData for example).
All you need to do is replicate that kind of class, give it the
appropriate @ProviderFor annotation, and add your classes to
lombok.jar, or have them in a separate jar that's also on the
classpath (though the installer isn't quite ready to handle that case
properly just yet, so rolling your own lombok.jar would probably be
easier for now), and voila.

The biggest issue in writing your own is the same issue we face when
writing transformers: You need to write 1 for javac, and 1 for
eclipse, and in both cases you have to use the internal AST API, which
is not documented very well.


@Data intentionally has no flexibility whatsoever. The flexibility
aspect of @Data is arranged by way of its constituent annotations: If
@Data is too much, then just pick-and-mix from @ToString,
@EqualsAndHashCode, @Getter and @Setter.

On Dec 10, 10:13 pm, Matt Higgins <matt.higg...@gmail.com> wrote:
> This is quite a common use case in fact when using JPA, where an abstract
> entity determines identity via the equals method of a super class . Further
> more equals and hashcode are hardly meaningless and have much deeper
> implications then setting a simple field or getting a value. These methods
> are often domain specific and in many cases out side of my jpa example can
> not be simplified, so either write one per class, or abstract if possible. I
> am not asking for this to be introduced into lombok merely a suggestion for
> you to take or leave, where a touch of flexibility can go a long way. In the
> JPA case equality is very difficult to define and the community at large
> debates over this all the time. The JPA debate does not need to be continued
> here but a simple out where equals and hashcode are excluded from the class
> level annotation allows developers the ability to solve the problem on their
> terms with their business needs in mind. The obvious benefit is less code,
> no getters and setters, and only one annotation.
>
> I looked around your site and could not find anything about extensions. Is
> this a forthcoming feature ?   This sounds very interesting could you point
> me to some documentation? Since you are not interested in this approach it
> would be convenient to keep it on it own.
>
> -Matt
>
> On Thu, Dec 10, 2009 at 12:36 PM, Matt Higgins <matt.higg...@gmail.com>wrote:
>
>
>
> > The difference is I do not generate the equals and hash code methods as the
> > abstract class implements them. This annotation only produces getters and
> > setters. I know with @Data I could create equals/hashcode methods in each
> > subclass to exclude the auto generated equals/hashcode. I am also ware you
> > can have the generated method call the super class equals. In my case I
> > don't want either of these. My current use case is an abstract class has the
> > ability to determine equality/identity of subclasses. If I use @Data i would
> > be putting more boiler plate code back into each sub class to override the
> > auto generated equals / hash code or use many individual @Getter / @Setter
> > annotations.
>
> > -Matt
>
> > On Thu, Dec 10, 2009 at 11:32 AM, Reinier Zwitserloot <reini...@gmail.com>wrote:
>
> >> Exactly what does @GettersAndSetters do differently from @Data?
>
> >> On Dec 9, 10:11 pm, MattH <matt.higg...@gmail.com> wrote:
> >> > A have forked lombok and added a new @GettersAndSetters annotation. It
> >> > is a crude copy of HandleData but it solves my larger issue with how
> >> > we deal with equals and hash code in an abstract class. I also did not
> >> > want to stray too far from the main lombok classes for easy updates.
> >> > It would be nice to see this in the main lombok source. I would be
> >> > happy to send the code if you are interested. If this were introduced,
> >> > a small refactor of HandleData would be in order.
>
> >> > -Matt
>
> >> --
> >> You received this message because you are subscribed to the Google
> >> Groups group forhttp://projectlombok.org/
>
> >> To post to this group, send email to project...@googlegroups.com
> >> To unsubscribe from this group, send email to
> >> project-lombo...@googlegroups.com<project-lombok%2Bunsubscribe@go­oglegroups.com>

Matt Higgins

unread,
Dec 11, 2009, 9:21:41 AM12/11/09
to project...@googlegroups.com
Extensions sound very interesting I look forward to watching the video! Just to clear things up on the JPA.

1. This method breaks frequently, here are some examples;
    -Really only works with simple objects .. a circle with a radius.
    -Spares object retrieval. This is a very common case when retrieving large graphs, native queries, searches etc..
    -If the fields are not db keys this method is not reliable.
    -Unexpected behaviors. Take your person example, my wife changed her name but I think she is still the same person.

2. This is much worse then the above issues. The id is not assigned until the object is persisted which causes lots of issues
    when dealing with sets / hash sets etc.. You can't mix persisted and transient objects etc.. This issue tends to be more
    sneaky!

3. This is my solution which is quite common in the ORM world. I use a UUID assigned at object creation time and is persisted with the object.
    The abstract class takes care of the UUID creation and I use this identifier to help with equals and hashcode. Countless variations of this
    pattern exist in the wild. 

This is a long thread but take a look here at all the issues. I am over simplifying the issues with 1, and 2. You need to really read through the comments as the original authors
approach is debunked.

https://www.hibernate.org/109.html

Their are many more threads like this but this is the first one to come to mind. In the end this discussion really has nothing to do with your project but its still interesting ;). Thanks for you feed back. In the mean time I will keep @GettersAndSetters going for my project, the beauty of opensource at work!

-Matt

Groups group for http://projectlombok.org/


To post to this group, send email to project...@googlegroups.com
To unsubscribe from this group, send email to
project-lombo...@googlegroups.com

Moandji Ezana

unread,
Dec 11, 2009, 11:42:14 AM12/11/09
to project...@googlegroups.com

On Fri, Dec 11, 2009 at 3:21 PM, Matt Higgins <matt.h...@gmail.com> wrote:
3. This is my solution which is quite common in the ORM world. I use a UUID assigned at object creation time and is persisted with the object.
    The abstract class takes care of the UUID creation and I use this identifier to help with equals and hashcode. Countless variations of this
    pattern exist in the wild. 

I'd never heard of this solution, interesting. In a typical one-entity-manager-per-http-request scenario, is it really different from not having equals/hashcode at all?

Moandji

Reinier Zwitserloot

unread,
Dec 11, 2009, 4:12:12 PM12/11/09
to Project Lombok
Sounds like a decent solution. Either way though, the sheer complexity
of the issue automatically means equality with ORM objects is no
longer an issue of the simplest possible form of boilerplate. Either
@Data or an alternative form of that simply no longer apply.

Your current superclass solution is still no good, in my opinion: It
precludes your classes from extending anything else, and it's also
hierarchically broken; your "Person" object is now a subclass of
"OrmyEqualityImpl", which is a silly 'is-a' relation. This kind of
stuff should be a mixin and have no relation whatsoever to the
hierarchy. Person should be a subclass of Object, or possibly
something abstract like "Entity".

So, what about combining @Data with @EqualsAndHashCode, except for
this UUID based equality we use a different annotation instead of
@EqualsAndHashCode? As data yields to all other annotations and does
not overwrite their additions, this should work fine.

We could add something like:

@UuidEquality
@Data
@Entity
public class Person {
private String name;
private int age;
private double height;
}


Which would do:

1. Creates a private final field named 'uuid' (probably configurable
as (field='uuid') on the annotation, and if the field already exists,
lombok will not complain and simply use that)

2. In all created constructors, it will be filled with a new UUID.

3. equals and hashCode key solely off this UUID field, ignoring every
other field.


There are some open issues here though:

- UUID is an acronym. This is problematic. This is common:

private URL url; //pick any acronym
public URL getURL() { return url; }

but isn't actually supported by lombok; if you put a @Getter on the
url field, you get "getUrl" and not "getURL". Turns out lombok's
choice of casing is in fact correct; while there is no note in the
official java code conventions guide (it does not mention casing of
acronyms), newer code in rt.jar tends to use getUrl and not the getURL
form. Still, UUID is NOT one of those classes; the call is
"UUID.randomUUID()" for example. Therefore, what are we going to call
a getter that would be associated with the uuid field? special case
the name to 'getUUID'? That'd be mean to the folks that actually
capitalize correctly and wanted 'getUuid'. Make it an option in the
annotation? That's not a good idea - that's such a seemingly frivolous
silly thing to bother the coder with.


I therefore propose to do an endrun around the entire issue and call
the field "$uuid", make it private, final, and NOT (intended to be)
accessed by the other code in the class. Just like $LOCK and $lock
from the @Synchronized annotation. If you need to interact with the
uuid field in any way (including making a getter for it), the right
strategy is to (A) explicitly add the uuid field to your class, (B)
Stick a @Getter on that (or let @Data take care of it, of course), and
(C) mention this field name in the @UuidEquality annotation.
(field="uniqueId").

Matt, do you have a getter for your UUID field? another way out is if
the field is not called uuid, but something else, such as 'uniqueId',
or 'equalityId', but that significantly increases the risk of a name
collision.

- Is UUID.randomUUID() the implementation used to assign the UUID in
95%+ of all cases, or, if not, will the set: "already using
UUID.randomUUID" + "not using that now but I'm okay with switching to
that" exceed 95%? If not, I'm not sure if this qualifies as
boilerplate.

Peter Becker

unread,
Dec 11, 2009, 5:19:58 PM12/11/09
to project...@googlegroups.com
I've once worked on an EAM system where there were long-lasting user
transactions in the web layer. People could add a new information
system, then create a couple of interfaces for it, then commit the whole
change at once. This process can take many minutes, possibly hours to
complete.

Identity management is a major issue in such an architecture and the
approach above is probably close to what we did in the end (honestly: I
don't remember). It's one of these things you'd rather avoid, though.
Not only due to the identity management issue, but even more since your
HTTP session objects become way too big and important -- not RESTful,
not easily or efficiently run on a cluster. Modeling these transactions
in the database layer isn't fun either, though.

Peter
Reply all
Reply to author
Forward
0 new messages