On Monday, April 23, 2012 1:57:08 PM UTC+2, Mat Jaggard wrote:
> I'm not sure how common a design pattern this is, but I've just had to > implement a cloning constructor (see below) could Lombok create this for me?
> @Data > public class Blah > { > private int field1; > private int field2; > private int field3;
Thanks Reiner. I guess my reservation is that this is the first time I've wanted one in my current project, and I don't remember wanting loads before. It just seemed like a lots of typing for a fairly simple concept. Have other people come across this? It's not worth putting in if it's not at all common.
I guess @CloningConstructor would be a reasonable name? I would also assume that it would only make shallow copies of things, but that would have to be documented (so that if you have a Collection in your object, you don't expect the contents of the new one to remain static when you update the original).
On 23 April 2012 22:50, Reinier Zwitserloot <reini...@gmail.com> wrote:
> We could make an annotation that would make one for you, certainly. Lombok > does not currently ship with such an annotation + handler, though.
> On Monday, April 23, 2012 1:57:08 PM UTC+2, Mat Jaggard wrote:
>> I'm not sure how common a design pattern this is, but I've just had to >> implement a cloning constructor (see below) could Lombok create this for me?
>> @Data >> public class Blah >> { >> private int field1; >> private int field2; >> private int field3;
>> -- > 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-lombok@googlegroups.com > To unsubscribe from this group, send email to > project-lombok+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/project-lombok?hl=en
> Thanks Reiner. > I guess my reservation is that this is the first time I've wanted one in > my current project, and I don't remember wanting loads before. It just > seemed like a lots of typing for a fairly simple concept. Have other people > come across this? It's not worth putting in if it's not at all common.
> I guess @CloningConstructor would be a reasonable name? I would also > assume that it would only make shallow copies of things, but that would > have to be documented (so that if you have a Collection in your object, you > don't expect the contents of the new one to remain static when you update > the original).
> On 23 April 2012 22:50, Reinier Zwitserloot <reini...@gmail.com> wrote:
>> We could make an annotation that would make one for you, certainly. >> Lombok does not currently ship with such an annotation + handler, though.
>> On Monday, April 23, 2012 1:57:08 PM UTC+2, Mat Jaggard wrote:
>>> I'm not sure how common a design pattern this is, but I've just had to >>> implement a cloning constructor (see below) could Lombok create this for me?
>>> @Data >>> public class Blah >>> { >>> private int field1; >>> private int field2; >>> private int field3;
>>> -- >> 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-lombok@googlegroups.com >> To unsubscribe from this group, send email to >> project-lombok+unsubscribe@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 for http://projectlombok.org/
> To post to this group, send email to project-lombok@googlegroups.com > To unsubscribe from this group, send email to > project-lombok+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/project-lombok?hl=en
> Yes, but the native Object.clone implementation can be 800% or 1000%
> slower than this way...
> Regards
> On Apr 24, 12:54 am, Kevin Ludwig <kevin.lud...@gmail.com> wrote:
> > maybe I'm missing something but can't you just implement cloneable?
> Doesn't
> > that automatically provide a clone() method that does shallow copies?
> --
> 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-lombok@googlegroups.com
> To unsubscribe from this group, send email to
> project-lombok+unsubscribe@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/project-lombok?hl=en
Yeah, the 'is this actually common boilerplate' issue stuck us too. Also, usually a copy constructor does a little more than 'just' copy fields, so how do we let you add some code? That's harder than it looks, at least if we want to do it in a way that makes it easy to understand and does not require you to dig through a lot of documentation to figure out how it works (i.e. no 'magic methods' which are called at the end).
--Reinier Zwitserloot
On Tue, Apr 24, 2012 at 12:14, Matthew Jaggard <matt...@jaggard.org.uk>wrote:
> On 24 April 2012 11:37, Tumi <elbailedelmil...@gmail.com> wrote:
>> Yes, but the native Object.clone implementation can be 800% or 1000% >> slower than this way... >> Regards
>> On Apr 24, 12:54 am, Kevin Ludwig <kevin.lud...@gmail.com> wrote: >> > maybe I'm missing something but can't you just implement cloneable? >> Doesn't >> > that automatically provide a clone() method that does shallow copies?
>> -- >> 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-lombok@googlegroups.com >> To unsubscribe from this group, send email to >> project-lombok+unsubscribe@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 for http://projectlombok.org/
> To post to this group, send email to project-lombok@googlegroups.com > To unsubscribe from this group, send email to > project-lombok+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/project-lombok?hl=en
In my particular case, I don't actually want to do any more than copy the
fields. If you did, could you have a parameter to the annotation like this?
@Data
@CopyConstructor(after="postCopy")
public class MyObject
{
private int field1;
private void postCopy()
{
field1 = 23;
}
}
Obviously this creates nasty issues like what to do if the method doesn't
exist? (Error at compile time)
The other option I see (again, I'm not sure if this is possible?) is to
have a separate annotation like @AfterCopyConstructor
@Data
@CopyConstructor
public class MyObject
{
private int field1;
In this case, what happens if @AfterCopyConstructor is defined on a method
but @CopyConstructor is not defined? (Fail to create the constructor
silently?)
On 24 April 2012 12:31, Reinier Zwitserloot <rein...@zwitserloot.com> wrote:
> Yeah, the 'is this actually common boilerplate' issue stuck us too. Also,
> usually a copy constructor does a little more than 'just' copy fields, so
> how do we let you add some code? That's harder than it looks, at least if
> we want to do it in a way that makes it easy to understand and does not
> require you to dig through a lot of documentation to figure out how it
> works (i.e. no 'magic methods' which are called at the end).
> --Reinier Zwitserloot
> On Tue, Apr 24, 2012 at 12:14, Matthew Jaggard <matt...@jaggard.org.uk>wrote:
>> This page lists quite a lot of problems with clone()
>> On 24 April 2012 11:37, Tumi <elbailedelmil...@gmail.com> wrote:
>>> Yes, but the native Object.clone implementation can be 800% or 1000%
>>> slower than this way...
>>> Regards
>>> On Apr 24, 12:54 am, Kevin Ludwig <kevin.lud...@gmail.com> wrote:
>>> > maybe I'm missing something but can't you just implement cloneable?
>>> Doesn't
>>> > that automatically provide a clone() method that does shallow copies?
>>> --
>>> 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-lombok@googlegroups.com
>>> To unsubscribe from this group, send email to
>>> project-lombok+unsubscribe@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 for http://projectlombok.org/
>> To post to this group, send email to project-lombok@googlegroups.com
>> To unsubscribe from this group, send email to
>> project-lombok+unsubscribe@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 for http://projectlombok.org/
> To post to this group, send email to project-lombok@googlegroups.com
> To unsubscribe from this group, send email to
> project-lombok+unsubscribe@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/project-lombok?hl=en
I like to use final fields a lot, so I having a postCopy method is no solution is I would like to clone/modify the contents of the fields in the constructor.
> In my particular case, I don't actually want to do any more than copy > the fields. If you did, could you have a parameter to the annotation > like this?
> @Data > @CopyConstructor(after="postCopy") > public class MyObject > { > private int field1;
> Obviously this creates nasty issues like what to do if the method > doesn't exist? (Error at compile time) > The other option I see (again, I'm not sure if this is possible?) is > to have a separate annotation like @AfterCopyConstructor
> @Data > @CopyConstructor > public class MyObject > { > private int field1;
> In this case, what happens if @AfterCopyConstructor is defined on a > method but @CopyConstructor is not defined? (Fail to create the > constructor silently?)
> On 24 April 2012 12:31, Reinier Zwitserloot <rein...@zwitserloot.com > <mailto:rein...@zwitserloot.com>> wrote:
> Yeah, the 'is this actually common boilerplate' issue stuck us > too. Also, usually a copy constructor does a little more than > 'just' copy fields, so how do we let you add some code? That's > harder than it looks, at least if we want to do it in a way that > makes it easy to understand and does not require you to dig > through a lot of documentation to figure out how it works (i.e. no > 'magic methods' which are called at the end).
> --Reinier Zwitserloot
> On Tue, Apr 24, 2012 at 12:14, Matthew Jaggard > <matt...@jaggard.org.uk <mailto:matt...@jaggard.org.uk>> wrote:
> This page lists quite a lot of problems with clone()
> On 24 April 2012 11:37, Tumi <elbailedelmil...@gmail.com > <mailto:elbailedelmil...@gmail.com>> wrote:
> Yes, but the native Object.clone implementation can be > 800% or 1000% > slower than this way... > Regards
> On Apr 24, 12:54 am, Kevin Ludwig <kevin.lud...@gmail.com > <mailto:kevin.lud...@gmail.com>> wrote: > > maybe I'm missing something but can't you just implement > cloneable? Doesn't > > that automatically provide a clone() method that does > shallow copies?
> -- > 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-lombok@googlegroups.com > <mailto:project-lombok@googlegroups.com> > To unsubscribe from this group, send email to > project-lombok+unsubscribe@googlegroups.com > <mailto:project-lombok%2Bunsubscribe@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 for http://projectlombok.org/
> To post to this group, send email to > project-lombok@googlegroups.com > <mailto:project-lombok@googlegroups.com> > To unsubscribe from this group, send email to > project-lombok+unsubscribe@googlegroups.com > <mailto:project-lombok%2Bunsubscribe@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 for http://projectlombok.org/
> To post to this group, send email to > project-lombok@googlegroups.com > <mailto:project-lombok@googlegroups.com> > To unsubscribe from this group, send email to > project-lombok+unsubscribe@googlegroups.com > <mailto:project-lombok%2Bunsubscribe@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 for http://projectlombok.org/
> To post to this group, send email to project-lombok@googlegroups.com > To unsubscribe from this group, send email to > project-lombok+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/project-lombok?hl=en
Hmm. I'm guessing the IDE / javac wouldn't be clever enough to work out
that the following is technically OK...
public class MyClass
{
private final int i;
public MyClass(MyClass copyOf)
{
afterCopy();
}
private void afterCopy()
{
i = 23;
}
//afterCopy is never called in the rest of the class.
}
Although actually, this is kind of irrelevant because the constructor has
to NOT initialise the final variable "i" - and we have no way of knowing
that's the case, unless you had YET ANOTHER annotation called
@CopyNonFinalConstructor or something?!
It's getting too complicated. Maybe it's just not worth adding at all?
On 25 April 2012 10:26, Roel Spilker <r.spil...@topdesk.com> wrote:
> I like to use final fields a lot, so I having a postCopy method is no
> solution is I would like to clone/modify the contents of the fields in the
> constructor.
> On 24-4-2012 14:06, Matthew Jaggard wrote:
> In my particular case, I don't actually want to do any more than copy the
> fields. If you did, could you have a parameter to the annotation like this?
> @Data
> @CopyConstructor(after="postCopy")
> public class MyObject
> {
> private int field1;
> Obviously this creates nasty issues like what to do if the method
> doesn't exist? (Error at compile time)
> The other option I see (again, I'm not sure if this is possible?) is to
> have a separate annotation like @AfterCopyConstructor
> @Data
> @CopyConstructor
> public class MyObject
> {
> private int field1;
> In this case, what happens if @AfterCopyConstructor is defined on a
> method but @CopyConstructor is not defined? (Fail to create the constructor
> silently?)
> On 24 April 2012 12:31, Reinier Zwitserloot <rein...@zwitserloot.com>wrote:
>> Yeah, the 'is this actually common boilerplate' issue stuck us too. Also,
>> usually a copy constructor does a little more than 'just' copy fields, so
>> how do we let you add some code? That's harder than it looks, at least if
>> we want to do it in a way that makes it easy to understand and does not
>> require you to dig through a lot of documentation to figure out how it
>> works (i.e. no 'magic methods' which are called at the end).
>> --Reinier Zwitserloot
>> On Tue, Apr 24, 2012 at 12:14, Matthew Jaggard <matt...@jaggard.org.uk>wrote:
>>> This page lists quite a lot of problems with clone()
>>> On 24 April 2012 11:37, Tumi <elbailedelmil...@gmail.com> wrote:
>>>> Yes, but the native Object.clone implementation can be 800% or 1000%
>>>> slower than this way...
>>>> Regards
>>>> On Apr 24, 12:54 am, Kevin Ludwig <kevin.lud...@gmail.com> wrote:
>>>> > maybe I'm missing something but can't you just implement cloneable?
>>>> Doesn't
>>>> > that automatically provide a clone() method that does shallow copies?
>>>> --
>>>> 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-lombok@googlegroups.com
>>>> To unsubscribe from this group, send email to
>>>> project-lombok+unsubscribe@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 for http://projectlombok.org/
>>> To post to this group, send email to project-lombok@googlegroups.com
>>> To unsubscribe from this group, send email to
>>> project-lombok+unsubscribe@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 for http://projectlombok.org/
>> To post to this group, send email to project-lombok@googlegroups.com
>> To unsubscribe from this group, send email to
>> project-lombok+unsubscribe@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 for http://projectlombok.org/
> To post to this group, send email to project-lombok@googlegroups.com
> To unsubscribe from this group, send email to
> project-lombok+unsubscribe@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 for http://projectlombok.org/
> To post to this group, send email to project-lombok@googlegroups.com
> To unsubscribe from this group, send email to
> project-lombok+unsubscribe@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/project-lombok?hl=en
On Wednesday, April 25, 2012 11:26:28 AM UTC+2, Roel Spilker wrote: > I like to use final fields a lot, so I having a postCopy method is no
solution is I would like to clone/modify the contents of the fields in the constructor.
Exactly. This is my major problem both with the proposed CloningConstructor and the clone() method. My second largest problem is the need to "unshare" some members via something like list = new ArrayList(original.list). I intentionally don't write "deep copy", since it goes just one level deep (in fact I don't think I ever needed a real deep copy).
What I needed is something like
@lombok.RequiredArgsConstructor class Something {
private final Date date; private final int x, y, z; private final List list;
@lombok.Complete public Something(Something original) { // here Lombok inserts missing assignments for x, y, and z list = new ArrayList(original.list); date = new Date(original.date.getTime()); }
}
This could be brought a bit further like
@lombok.Complete public Something(Something original, int x) { // here Lombok inserts missing assignments for x, y, and z this.x = x; list = new ArrayList(original.list); date = new Date(original.date.getTime()); }
In a anemic data object generator before our time, we had copy() methods which generated copy() methods on the source objects to produce a new object. That way, you could access private target fields with
1. assignments on simple values: newObject.a = a; 2. produce copies on complex values: newObject.b = b.copy(); 3. optionally create deep copies on arrays: newObject.c = new XXX[c.length]; System.arraycopy(c, 0, d, 0, c.length); 4. optionally create deep copies on collections: newObject.d.addAll(d); // where newObject.d was initialized as some Collection in the constructor. 5. newObject = (XXX) this.clone() if everything else failed.
We missed out the special java.util.Date case. Date should be considered immutable by convention. I guess that lombok could not distinguish between cases 1 or 2 and the option in 3/4 would need a switch as well.
Is anyone still interested in lombok annotations for this? I've written a javac handler that does some of the things described here and would be happy to contribute that and more. However most of my use cases center around interfaces, so I'm primarily interested in generating conversion constructors that assign fields based on calling getters in an implemented interface or superclass.
I still have plenty of work to do, but I have implemented the following so far:
1. Copying a basic data contract. If two classes implement the same interface and have fields defined such that an @Data annotation generates implementations of the interface, annotating the classes with @CopyConstructor(TheSharedInterface.class) will generate a conversion constructor with an argument of TheSharedInterface. Some customization would be useful here. 2. Deep copying of any class whose members all have a deep copy constructor. Whether to try deep or shallow copying is a configuration option. The trouble with deep copying is of course all of the iterables. 3. Deciding when to call super and throwing errors if we can't handle anything super likely didn't handle for us. 4. Determining type parameters for generics (including for deep copying and when inheritance and generics are involved).
The parts I have not yet implemented (but plan to) include:
5. Handle iterables. If the result of a getter is an iterable, the field type might hint at which iterable to use (i.e. List<T> field1 or LinkedList<T> field2). If no implementation class is specified, I will probably end up picking a default per collection type. 6. Enable constructor extensibility. I have currently defined an @CopyConstructor annotation at the class level, with an optional class argument telling it what type to copy from. I like the idea of having a class-level annotation, since requiring a constructor would mean requiring unnecessary boilerplate. Perhaps I could change the annotation to be definable at the class or constructor level: if it's at the class level, generate the constructor; if it's on a constructor, inject the generated code into the start of the constructor.
I've toyed with generating multiple constructors, compositing constructors, and static factory methods, but I didn't like where I got with any of that. (Example: constructors on a class are obvious, but how do you know a static method is a factory method if it's already been compiled and your annotation has a source retention policy? That makes it nigh impossible to do deep copying.)
If there is any interest in including something like this in lombok, I would be happy to share it and keep plugging away on it. Of course the biggest thing missing, by far, is the entire Eclipse implementation, but there are some other features that might be desirable to a broader audience, such as support for fluent getters or direct field access.
On Wednesday, April 25, 2012 5:52:31 PM UTC-4, Karsten Tinnefeld wrote:
> In a anemic data object generator before our time, we had copy() methods > which generated copy() methods on the source objects to produce a new > object. That way, you could access private target fields with
> 1. assignments on simple values: newObject.a = a; > 2. produce copies on complex values: newObject.b = b.copy(); > 3. optionally create deep copies on arrays: newObject.c = new > XXX[c.length]; System.arraycopy(c, 0, d, 0, c.length); > 4. optionally create deep copies on collections: > newObject.d.addAll(d); // where newObject.d was initialized as some > Collection in the constructor. > 5. newObject = (XXX) this.clone() if everything else failed.
> We missed out the special java.util.Date case. Date should be considered > immutable by convention. > I guess that lombok could not distinguish between cases 1 or 2 and the > option in 3/4 would need a switch as well.
I think its cool but I worry that it becomes a feature that sees very little use and becomes a pain to maintain. There is so much that can be configured about this sort of thing, so do we make it as simple as possible and simply resort to: "Well, if this simplest case does not work for you, then don't use lombok for it and write it out longhand", or make it configurable (which makes the feature much more complicated).
On Thursday, October 4, 2012 10:04:47 PM UTC+2, Peter Grant wrote:
> Is anyone still interested in lombok annotations for this? I've written a > javac handler that does some of the things described here and would be > happy to contribute that and more. However most of my use cases center > around interfaces, so I'm primarily interested in generating conversion > constructors that assign fields based on calling getters in an implemented > interface or superclass.
> I still have plenty of work to do, but I have implemented the following so > far:
> 1. Copying a basic data contract. If two classes implement the same > interface and have fields defined such that an @Data annotation generates > implementations of the interface, annotating the classes with > @CopyConstructor(TheSharedInterface.class) will generate a conversion > constructor with an argument of TheSharedInterface. Some customization > would be useful here. > 2. Deep copying of any class whose members all have a deep copy > constructor. Whether to try deep or shallow copying is a configuration > option. The trouble with deep copying is of course all of the iterables. > 3. Deciding when to call super and throwing errors if we can't handle > anything super likely didn't handle for us. > 4. Determining type parameters for generics (including for deep copying > and when inheritance and generics are involved).
> The parts I have not yet implemented (but plan to) include:
> 5. Handle iterables. If the result of a getter is an iterable, the field > type might hint at which iterable to use (i.e. List<T> field1 or > LinkedList<T> field2). If no implementation class is specified, I will > probably end up picking a default per collection type. > 6. Enable constructor extensibility. I have currently defined an > @CopyConstructor annotation at the class level, with an optional class > argument telling it what type to copy from. I like the idea of having a > class-level annotation, since requiring a constructor would mean requiring > unnecessary boilerplate. Perhaps I could change the annotation to be > definable at the class or constructor level: if it's at the class level, > generate the constructor; if it's on a constructor, inject the generated > code into the start of the constructor.
> I've toyed with generating multiple constructors, compositing > constructors, and static factory methods, but I didn't like where I got > with any of that. (Example: constructors on a class are obvious, but how do > you know a static method is a factory method if it's already been compiled > and your annotation has a source retention policy? That makes it nigh > impossible to do deep copying.)
> If there is any interest in including something like this in lombok, I > would be happy to share it and keep plugging away on it. Of course the > biggest thing missing, by far, is the entire Eclipse implementation, but > there are some other features that might be desirable to a broader > audience, such as support for fluent getters or direct field access.
> Anyway, it's a start. Thoughts?
> On Wednesday, April 25, 2012 5:52:31 PM UTC-4, Karsten Tinnefeld wrote:
>> In a anemic data object generator before our time, we had copy() methods >> which generated copy() methods on the source objects to produce a new >> object. That way, you could access private target fields with
>> 1. assignments on simple values: newObject.a = a; >> 2. produce copies on complex values: newObject.b = b.copy(); >> 3. optionally create deep copies on arrays: newObject.c = new >> XXX[c.length]; System.arraycopy(c, 0, d, 0, c.length); >> 4. optionally create deep copies on collections: >> newObject.d.addAll(d); // where newObject.d was initialized as some >> Collection in the constructor. >> 5. newObject = (XXX) this.clone() if everything else failed.
>> We missed out the special java.util.Date case. Date should be considered >> immutable by convention. >> I guess that lombok could not distinguish between cases 1 or 2 and the >> option in 3/4 would need a switch as well.