@Builder in derived classes

2,115 views
Skip to first unread message

pcouton

unread,
Jan 28, 2015, 5:55:01 AM1/28/15
to project...@googlegroups.com
Hello,

I am trying to use @Builder in derived classes, but  I have compilation errors in Eclipse.

I start with this base class:
@Getter @Builder public class Point {
   
private double x;
   
private double y;
}

Then, I create this derived class:
@Getter @Builder public class NamedPoint extends Point {
   
private String name;
}

In this case, Eclipse shows a compilation error on @Buider in the derived class: Implicit super constructor Point() is undefined. Must explicitly invoke another constructor.

So, I added explicit constructors in the base class as follow:
@Getter @Builder public class Point {
   
private double x;
   
private double y;

   
public Point() { }

   
public Point(double x, double y) {
       
this.x = x;
       
this.y = y;
   
}

}

Now, the implicit constructor error is gone, but it is replaced by another compilation error in the derived class: The return type is incompatible with Point.builder().

Is there something wrong in my code?
How can I get rid of this problem?

Thanks in advance for your help

Reinier Zwitserloot

unread,
Jan 29, 2015, 8:17:39 AM1/29/15
to project-lombok
Lombok can't tell what your supertype looks like. Both Point and NamedPoint have their own builder which ignores the other, and they both try to create a public static (Named)PointBuilder builder() {} method which is where the conflict comes from.

You cannot solve this problem; builder cannot be used if you construct type hierarchies.

Separate from that, this is just a bad idea in general. For example, is a NamedPoint("foo", 5, 10) compatible with a Point(5, 10)? Seems obvious to say yes to that question, it would be very surprising, and breaks the rule that a NamedPoint ought to act exactly like a Point if you use it that way.

But if that's true, then NamedPoint("bar", 5, 10) must also be equal to Point(5, 10), and if the "foo" point is equal to that, and the "bar" point is equal to that, then NamedPoint("foo", 5, 10) and NamedPoint("bar", 5, 10) must also be equal to each other!

There's no way out of this mess. This is why type hierarchies that add properties is not something you should do in java code.

Instead, make 'pointyness' an interface if you really need that functionality, and make 2 classes that both just extend j.l.Object that are both pointy. It is now clear that a NamedPoint will not ever be equal to a Point, and you won't have builder conflicts.



 --Reinier Zwitserloot

--
You received this message because you are subscribed to the Google Groups "Project Lombok" group.
To unsubscribe from this group and stop receiving emails from it, send an email to project-lombo...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Marco Servetto

unread,
Feb 1, 2015, 4:04:58 AM2/1/15
to project...@googlegroups.com
Instead, make 'pointyness' an interface if you really need that functionality, and make 2 classes that both just extend j.l.Object that are both pointy. It is now clear that a NamedPoint will not ever be equal to a Point, and you won't have builder conflicts.
+1 to reiner programming style. 
(a)Is there some text when some big name suggest this kind of style, so I can flush it in the face of a couple of lectures I know?
(b)Is not this against the canEqual method generated by lombock?

Martin Grajcar

unread,
Feb 1, 2015, 10:14:49 AM2/1/15
to project...@googlegroups.com
(b)Is not this against the canEqual method generated by lombock?

No.  As Reinier wrote "NamedPoint will not ever be equal to a Point" and this is what you usually (should) want. `canEqual` gets generated for non-final classes and can be used in order to be able to make instances of different classes equal, in case you really need it. It does not interfere in case of a common superclass without @EqualsAndHashCode like here.

Reinier Zwitserloot

unread,
Feb 1, 2015, 6:45:21 PM2/1/15
to project-lombok
canEqual is a way to support subclassing something without adding any new identity to it.

There is no way out of this problem when you DO add identity, such as, in this case, a name. You can't have sane equality implementations and a hierarchy where a subtype adds identity-relevant state, period.

There's nothing to point at. Just explain the problem to your lecturer. We did go through the motions in one of our devoxx presentations. I believe the second one. It shold be on on parleys.com.

 --Reinier Zwitserloot

On Sun, Feb 1, 2015 at 4:14 PM, Martin Grajcar <maaar...@gmail.com> wrote:
(b)Is not this against the canEqual method generated by lombock?

No.  As Reinier wrote "NamedPoint will not ever be equal to a Point" and this is what you usually (should) want. `canEqual` gets generated for non-final classes and can be used in order to be able to make instances of different classes equal, in case you really need it. It does not interfere in case of a common superclass without @EqualsAndHashCode like here.

Michael

unread,
Nov 17, 2016, 2:57:23 AM11/17/16
to Project Lombok
I should point out that regardless of whether this is a good idea or not, it is possible to "fix" the issue by renaming the builder() method. You do this by specifying a type element:

@Builder(builderMethodName="uniqueBuilderName")
Reply all
Reply to author
Forward
0 new messages