Add the Annotation @CopyConstructor
This helps with the inheritance, where we build sub-classes with certain additional fields as needed.
@Builder does not work here.
Usage demo:
@NoArgsConstructor
@CopyConstructor
@Getter
@Setter
public class Parent {
private String field1;
private String field2;
}
@NoArgsConstructor
@Getter
@Setter
public class Child extends Parent {
public Child(Parent parent, String field3) {
super(parent);
this.field3 = field3;
}
private String field3;
}
Here is a live example:
I have a Parent Class called "GameState" which would return (in serialized) form as the response to a GET call. To avoid taxing the GET call too much, I want to implement the ~If-Not-Match~ If-None-Match header with an etag. To carry around the etag info within the code, I want to create a Child Class "GameStateWithETag". Now I know I can just create a wrapper class with 2 fields (1 for parent object, and 1 for etag) but for specific reasons I need to do it this way. The @CopyConstructor becomes very handy in this case. @Builder does not work since I need it to set parent class attributes, not construct an actual object of the parent class.
The current way to do this is by using @AllArgsConstructor and manually copying over fields, which becomes an overhead if a new field is added to Parent.
That one has been requested before, and rejected.
Because lombok can't do this, unfortunately.
See https://github.com/rzwitserloot/lombok/wiki/LOMBOK-CONCEPT:-Resolution
On Tue, May 26, 2020, 01:21 Pratik notifications@github.com wrote:
Add the Annotation @CopyConstructor
This helps with the inheritance, where we build sub-classes with certain
additional fields as needed.
@Builder does not work here.Usage demo:
@NoArgsConstructor@CopyConstructor@Getter@Setterpublic class Parent {
private String field1;
private String field2;
}
@NoArgsConstructor@Getter@Setterpublic class Child extends Parent {
public Child(Parent parent, String field3) {
super(parent);
this.field3 = field3;
}private String field3;
}Here is a live example:
I have a Parent Class called "GameState" which would return (in
serialized) form as the response to a GET call. To avoid taxing the GET
call too much, I want to implement the If-Not-Match header with an etag.
To carry around the etag info within the code, I want to create a Child
Class "GameStateWithETag". Now I know I can just create a wrapper class
with 2 fields (1 for parent object, and 1 for etag) but for specific
reasons I need to do it this way. The @CopyConstructor becomes very handy
in this case. @Builder does not work since I need it to set parent class
attributes, not construct an actual object of the parent class.The current way to do this is by using @AllArgsConstructor and manually
copying over fields, which becomes an overhead if a new field is added to
Parent.—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/rzwitserloot/lombok/issues/2474, or unsubscribe
https://github.com/notifications/unsubscribe-auth/AABIERJ5RDRQZNPRKNRPEJDRTL4P7ANCNFSM4NJ2WCJA
.
Thanks @randakar, I went through the wiki doc you pointed me to, but I don't seem to understand the problem in its entirity. From the little knowledge I have, this looks like an evolution to the @AllArgsConstructor. Could you point me to the code for the generation logic of AllArgsConstructor?
From what I understand, in AllArgsConstructor, you already discovered all the fields in the class (since you are assigning them from
It would be great if you could point me to the relevant section in the code. I'll learn something new :D
It's possible, but requires every class in the hierarchy above Parent to have that annotation, too.
This could also be solved if #2374 would be implemented.
It's possible, but requires every class in the hierarchy above Parent to have that annotation, too.
@janrieke I'm not sure I understood what you meant by this. If I understand you right, I think you are assuming we need deep copies? This is unnecessary IMO. Copy constructors are usually shallow copies of the object... essentially a better and more reliable version of Object.clone()
Example:
class A {
MyCustomClass a;
}
@CopyConstructor
class B extends A {
MyCustomClass b;
}
class C extends B {
MyCustomCass c;
C(B b, MyCustomClass c) {
super(b);
this.c = c;
}
}
Generated Code would effectively be the following constructor in B.
class B extends A {
MyCustomClass b;
public B(B that) { // Effective Generated Code
super(); // Effective Generated Code
this.b = that.b; // Effective Generated Code
} // Effective Generated Code
}
The AllArgsConstructor would've created the following:
class B extends A {
MyCustomClass b;
public B(MyCustomClass b) { // Effective Generated Code
super(); // Effective Generated Code
this.b = b; // Effective Generated Code
} // Effective Generated Code
}
Hence, the difference is not too much.
The AllArgsConstructor is unable to use the AllArgsConstructor in the parent class as a known limitation. It always uses the default constructor (super()). The same restriction can apply here too.
Though maybe limited a bit, this would be a good feature to add.
Builder pattern. It's somewhat of a superset to the CopyConstructor feature and would need a more robust solution. IMO CopyConstructor is a smaller step in the forward direction which can meet some of the needs of the folks on that feature request as well.No, you cannot seriously provide a copy-constructor that only copies the fields of that class, without considering the fields of superclasses. That @AllArgsConstructor has this limitation is not a good reason if you can solve the issue easily like in this case. Furthermore, you have to assume that a certain constructor exists in the superclass. Why should it be the no-args constructor? Then better require a copy-constructor for all superclasses, IMHO.
Disclaimer: I'm not a Lombok team member.
@janrieke Now that I go back and think about it, what you say makes sense. Also, not knowing the access modifiers of the parent class makes it an even bigger mess. We won't know what to use to set inherted fields...
In that sense, even the @AllArgsConstructor is not "inheritance-ready".... I guess its behavior is only present to provide _some_ result rather than failing the build.
If this ever does get implemented, maybe the approach that can be taken is to have the generated copy-constructor use the parent class' copy constructor as well if available, and the default constructor if not. This would leave the decision to the consumer. Then again, this seems like it won't be possible to implement, or else we would've already have the AllArgsConstructor which would use the AllArgsConstructor of the parent class when available, rather than using the default constructor.
You should explore wither and @Builder with builder set to true which returns a separate copy ( though not deep copy ).
Then again, this seems like it won't be possible to implement, or else we would've already have the AllArgsConstructor which would use the AllArgsConstructor of the parent class when available, rather than using the default constructor.
Exactly.
In theory, the @CopyConstructor could work exactly like the @AllArgsConstructor, but it looks like nobody would be really happy with it. Some wants deep cloning, others want to call non-trivial super, etc. A simple @CopyConstructor without these features wouldn't be very useful. And all these features are pretty complicated. So I'm afraid, we won't get it anytime soon.
Especially as there are usable workarounds like mentioned by @charvakcpatel007 (o.toBuilder().build() and o.withSomeInt(o.someInt()+1).withSomeInt(o.someInt())).
I personally mostly switched to immutable classes, so I can't remember when I wanted to clone something last. This is not always possible, but then I usually need to copy all fields from one object to another already existing object (this together with any constructor would make @CopyConstructor, too).
Disclaimer: I'm not a Lombok team member.