murat8505 / projectlombok

Automatically exported from code.google.com/p/projectlombok
0 stars 1 forks source link

Enhancement: @Getter, support non-final lazy=true and @Setter #556

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
I understand the reasoning behind the final, lazy = true requirement on the 
@Getter annotation.  However, I have a few problems with it.

1. The known issue of Context lookup in Eclipse. (slightly off topic here)
2. The inability to serialize the field without custom serialization.
3. The inability to override the automatically created object with a setter or 
even through a constructor.

I have several use cases where I would like to use lazy=true, not to create a 
final object, but to create a default value if one is not provided.  I also 
like to use the lazy pattern to modularize my code creation.  IE, I don't have 
to create something in the constructor, I create it in a lazy getter instead 
with the pattern:

private transitive T t;
private static final Object createLock = new Object();

T getT() {
  if (T == null) {
      synchronized(createLock) {
           if (t == null) {
               t = createT();
           }
      }
  }
}

T createT() {
  return new T();
}

public void setT(T newT) {
   if (this.t != newT || (this.t!=null && !this.t.equals(newT)) {
      synchronized(createLock) {
         if (this.t != newT || (this.t!=null && !this.t.equals(newT)) {
             this.t = newT;
         }
      }
   }
}

I thought that @Getter(lazy=true) was my dream come true when I first saw it, 
but with the issues from eclipse context lookup and inability to serialize the 
value, I have had to abandon the usage of lazy=true on my getters in most cases.

I would like to see the ability to specify:
@Getter(lazyNonFinal=true) @Setter T t;

and generate something similar to the above template, which would resolve the 
issues with the current version of lazy=true.

Original issue reported on code.google.com by j...@percsolutions.com on 8 Aug 2013 at 5:55

GoogleCodeExporter commented 9 years ago
> I also like to use the lazy pattern to modularize my code creation.

Are you aware of DI, especially Guice? In case you're doing what I think, you 
should consider switching soon.

The test in your setter makes little sense. I guess you're trying something like

!com.google.common.base.Objects(this.t, newT)

but the right part of your condition comes in play only for an object not equal 
to itself.

I'm curious why your setter shouldn't overwrite the field in case it's equal???

Original comment by Maaarti...@gmail.com on 10 Aug 2013 at 3:33

GoogleCodeExporter commented 9 years ago
I am aware of DI and Guice, and there could be usages where Guice and the lazy 
design pattern would work and they would overlap, however there are reasons not 
to use Guice or where Guice wouldn't make sense.  Perhaps when JSR-330 is 
incorporated into the core java SDK any need for this pattern will go away, but 
then again, maybe not.

As for the test, yea that would be what I intended.

As for why it shouldn't overwrite itself in case it's equal?  Why should it, 
what's the point of making a non-operative assignment?  If you add additional 
functionality down the road to support say, Property change support or a 
notification only when the object changes, then you would need that type of 
equality check.  I have seen at least one request in here to add Property 
Change support into the core lombok functionality, so I probably had that in 
mind when writing the test.

Original comment by j...@percsolutions.com on 10 Aug 2013 at 8:58

GoogleCodeExporter commented 9 years ago
The point of making a non-operative assignment is that:

(A) It might still be operative; equal objects may still operate differently. 
In particular, the premise of: "If the new value is .equals to the old value 
then your set call is a no-op, but, if they are not .equals(), then T is 
overwritten" is at least as weird.

(B) .equals isn't free. Why waste a call on it?

The above snippet has all sorts of really weird semantics:

* 'null' is magic value for the field which means: Actually, the next time 
someone calls getT(), go calculate the 'lazy expression'. This is not just true 
after constructing a new object, it's also true after calling .setT(null).

* 'null', being a magic value, is not something you can return as a 'lazy 
expression'. Well, you can, but if you do that, the lazy expression will be 
re-evaluated every time you invoke getT().

Was that intentional? In which case, I'm not sure I understand the underlying 
use case.

Original comment by reini...@gmail.com on 12 Aug 2013 at 7:50

GoogleCodeExporter commented 9 years ago
As for the operative, no-operative assignment and the "weird behavior", a good 
example of where this type of behavior happens is in the PropertyChangeSupport 
of java swing. I would say though, that for any code generation by lombok, such 
wouldn't be necessary in the setter, unless the user wrote the setter 
themselves, as you would really only need it if you invoke other functionality 
from the setter.  For arguments sake, I would say that if "equals" objects 
operate differently, then they aren't really "equals", but that's a design 
choice.

This kind of pattern can be used when creating base classes with common 
functionality.  IE take Apples UIViewController class as an example, it uses 
this pattern to create the view;

the "get"View operation returns the existing view.  If no view is assigned, 
then it calls the following operations in succession(simplified):

viewWillLoad
view = loadView
viewDidLoad

then returns the view created from load view.

This pattern provides for a reusable and extendable class.  IE UIViewController 
can be extended in functionality by overriding viewWillLoad, loadView and 
viewDidLoad.  A custom UIViewController that deals with a specific view type 
can also be reused by swapping in and out of views via the setView operation.

Original comment by j...@percsolutions.com on 13 Aug 2013 at 8:40