> The problem is that you can alter the objects state from the outside
> by keeping a reference to the Date that you passed in or got out, and
> set the time on that date. It is recommended to use clone() here, for
> example.
>
> It’s a small hassle to write getter and setter. Unfortunately, also
> all generated constructors suffer from this, and since they set all
> the other fields as well, that’s a bit of work.
>
> I would wish for a way to specify that clone() shall be used. Or
> perhaps a ‘copy constructor’ or some other specified function.
I second this. The problem is that there are a lot of different details.
In some cases you have copy constructors (e.g. new Date(date)); in other
cases you don't, and wish clone(); in others you could wanting to do
something entirely different (such as returning a CopyOnWriteArrayList).
But I think that we can figure out a strategy for dealing with the most
frequent cases.
--
Fabrizio Giudici - Java Architect, Project Manager
Tidalwave s.a.s. - "We make Java work. Everywhere."
fabrizio...@tidalwave.it
http://tidalwave.it - http://fabriziogiudici.it
> I can't think of a sound way to actually fix this; how do we know that
> Date
> needs defensive copying and Integer doesn't? Coding in specific logic for
> stuff in java.util.* does not sound like a winning strategy because the
> number of possible java classes is infinite.
I'm really not thinking of auto-detecting by class. I'm thinking of adding
attributes to the annotations to explicitly let the programmer choose.
E.g.
@Getter(variant=CLONE)
@Getter(variant=COPY_CONST)
@Getter(variant=COPY_CONST, clazz=CopyOnWriteArrayList.class)
etc...
'variant', 'clazz' are not good attribute names, just the idea.
If its part of getter and setter, you can specify separate strategies for read and write. For example, Date needs defensive copying on both edges, but if you copy a list into CopyOnWriteList on create/set, no defensive cloning is needed on read.
But, that does mean that the constructor either needs to call the setter, or, read the copy strategy from @Setter.
The alternative is that you put a @CopyStrategy on the field, but that would need a way to specify both the read and write strategy which is annoying.
I'm leaning towards:
@Getter(copying=@CopyStrategy(COPY_CONSTRUCTOR, using=CopyOnWriteList.class))
Thoughts?
Browsing Lombok’s issue database today I saw that the concrete problem I was facing actually resulted in reported issues: See #77 and #347, both could easily be handled by using clone().
--
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
If its part of getter and setter, you can specify separate strategies for read and write. For example, Date needs defensive copying on both edges, but if you copy a list into CopyOnWriteList on create/set, no defensive cloning is needed on read.
But, that does mean that the constructor either needs to call the setter, or, read the copy strategy from @Setter.
The alternative is that you put a @CopyStrategy on the field, but that would need a way to specify both the read and write strategy which is annoying.
I'm leaning towards:
@Getter(copying=@CopyStrategy(COPY_CONSTRUCTOR, using=CopyOnWriteList.class))
On Tuesday, June 5, 2012 9:48:53 AM UTC+2, Reinier Zwitserloot wrote:If its part of getter and setter, you can specify separate strategies for read and write. For example, Date needs defensive copying on both edges, but if you copy a list into CopyOnWriteList on create/set, no defensive cloning is needed on read.
I don't see why it's not needed, unless you really want to allow the reader to modify the owned list.
But, that does mean that the constructor either needs to call the setter, or, read the copy strategy from @Setter.
Quite often you want to do the copying in the setter (since it's public) but avoid it in a (package) private constructor, since you own the incoming object.
The alternative is that you put a @CopyStrategy on the field, but that would need a way to specify both the read and write strategy which is annoying.
I'd say that in most cases you need the same CopyStrategy for both reads and writes. In the few cases you do not, you just want to omit the copying.
I'm leaning towards:
@Getter(copying=@CopyStrategy(COPY_CONSTRUCTOR, using=CopyOnWriteList.class))
I'm not sure if I understand this example.For the case you want a copy in the getter but not in the setter, I'd suggest@CopyStrategy(COPY_CONSTRUCTOR, using=CopyOnWriteList.class)// @Getter - may be omitted if given on the whole class@Setter(noCopy=true)
On Tuesday, June 5, 2012 4:39:05 PM UTC+2, Maaartin G wrote:On Tuesday, June 5, 2012 9:48:53 AM UTC+2, Reinier Zwitserloot wrote:If its part of getter and setter, you can specify separate strategies for read and write. For example, Date needs defensive copying on both edges, but if you copy a list into CopyOnWriteList on create/set, no defensive cloning is needed on read.
I don't see why it's not needed, unless you really want to allow the reader to modify the owned list.Right, nevermind, brainfart. Consider using some sort of ImmutableList arrangement. You want to copy the incoming list into that on write, but you don't need a copy at all on read.
That would imply we need noCopy on each of the 3 generative things (@XArgsConstructor, @Setter, @Getter), which all default to useCopyStrategy=true. @CopyStrategy would be its own annotation which you stick on a field, similar to your example.
What strategies do we need? I have identified at least these 3, which are IMO must-haves:(A) copy constructor, using either its own class or an optional alternate class: @ConstructorCopyStrategy(type=HashMap.class)
(B) static method, which requires the name of a class and the name of a static method. This is quite ugly, but guava's ImmutableList needs it, and that's a very important use case: @StaticMethodCopyStrategy(type=ImmutableList.class, method="copyOf").
(C) clone(): @CloneCopyStrategy()Then some optional ones which are much more complicated and may, hopefully, not be necessary(D) @ConstructorByFieldCopyStrategy(type=?) - this strategy will not pass 'this', but instead it passes each field in the order listed in the class.
(E) A similar thing but for static methods.(F) Expand @CloneCopyStrategy to allow an optional method name; there are a few classes out there which opted out of the wonky API particulars of Object.clone(); these usually have a method named 'copy()'.