Lombok #Builder does not create immutable objects? - java

In many sites, I saw lombok #Builder can be used to create immutable objects here(https://www.baeldung.com/lombok-builder-singular) and also many sites say Builder pattern is mainly used to create immutable objects.
TimeIntervalData td = TimeIntervalData.builder().endTime("12:00").startTime("10:00").build();
td.setEndTime("14:00");
System.out.println(td.getEndTime());
I am not sure how I can use setters on objects built using builders. Is there something I am missing here?

Yes lombok builder will not create immutable instances util user define the parameters in class as final, As per the docs from lombok.builder #Builder lets you automatically produce the code required to have your class be instantiable with code such as:
Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();
As per the docs it just creates inner static class with the same properties in the same way that mentioned in outer class
A method annotated with #Builder (from now on called the target) causes the following 7 things to be generated:
An inner static class named FooBuilder, with the same type arguments as the static method (called the builder).
In the builder: One private non-static non-final field for each parameter of the target.
In the builder: A package private no-args empty constructor.
In the builder: A 'setter'-like method for each parameter of the target: It has the same type as that parameter and the same name. It returns the builder itself, so that the setter calls can be chained
In the builder: A build() method which calls the method, passing in each field. It returns the same type that the target returns
In the builder: A sensible toString() implementation.
In the class containing the target: A builder() method, which creates a new instance of the builder.
But using #Singular with #Builder annotation for collection properties makes them singleton
By annotating one of the parameters (if annotating a method or constructor with #Builder) or fields (if annotating a class with #Builder) with the #Singular annotation, lombok will treat that builder node as a collection, and it generates 2 'adder' methods instead of a 'setter' method. One which adds a single element to the collection, and one which adds all elements of another collection to the collection. No setter to just set the collection (replacing whatever was already added) will be generated.
#Singular can only be applied to collection types known to lombok.

is mainly used to create immutable objects
This statement is not correct. The main purpose is to reduce boiler plate code. Creation of object using builder is compacter, it is easier to write and is easier to read.
When you have 1-2 attributes, builder can be disadvantage and can make the code less readable compared to passing parameters via constructor.
So when to use or not to use builder is a matter of taste.
To setters: If you need setters, you can generate them by #Data annotation.

Related

Different effect when using plural method on Collection field with and without #Singular annotation

I want to have immutable myClass objects. Good solution seams to be using #Singular annotation.
The problem is when I use this annotation the method elements() appends elements to existing list, instead of creating the new one:
Let's assume that that we have:
#Value
#Builder(toBuilder = true)
public class MyClass {
#Singular
private List<String> elemets;
}
and
MyClass.builder()
.elemets(Arrays.asList("elem1"))
.elemets(Arrays.asList("elem2"))
.build();
Without #Singular annotation we have elem2 on the list
with #Singular annotation we have both elem1 and elem2, if I want to have elem2 only I have to use clearElements() before.
Why implementation is different? Is it possible to use #Singular with my own implementation?
With #Singular annotation I cannot implement elemets(List elemets) method in MyClassBuilder class because I get: "Manually adding a method that #Singular #Builder would generate is not supported. If you want to manually manage the builder aspect for this field/parameter, don't use #Singular."
First let me say that using #Singular isn't necessarily the best solution -- it depends on your use case.
However, in most cases where you want to ensure immutability on classes that use collections, it is a good choice.
#Singular behaves the way it does because the Lombok designers decided that it's a good choice to do so. And I agree: It makes the two setter methods behave similarly; and in those rare cases where you want to reset the elements in a builder, you have the clear method.
#Singular generates pretty complex code (see https://projectlombok.org/features/BuilderSingular for an example). This is to ensure properties like efficiency and immutability (also when reusing builders to produce several objects). When you mess around with that code, you can easily violate these properties. Lombok prevents you from doing that.
If you really want to modify this aspect, you have three choices:
delombok the builder code, copy it into your class, and modify it.
Add another differently named method, like clearAndSetElements(List<String>). But that's probably even more confusing.
Remove #Singular and implement the setter methods on your own. You will have to put some effort in the implementation if you want the properties of Lombok's implementation; you can use the delomboked code as inspiration.

Should custom annotations be used to store information about an object?

After searching online for the use of custom Java annotations, it's still not 100% clear to me where I should and should not be using them.
Let's say we have an abstract class called Paperwork that is being extended by several subclasses like Taxes or Homework. Each of these subclasses gets annotated with #Paperwork that includes 1 or 2 required parameters and a wide variety of parameters with a certain default value.
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface Paperwork {
String name();
boolean important() default false;
int dueBy() default Calendar.MONDAY;
// more variables...
}
Paperwork now does some internal work in a method getSummary(). It looks for all the classes that are annotated with #Paperwork, and creates a general summary/overview of all paperwork. Any classes not annotated with it are still in development, and get simply ignored.
So far, this could have been realized by a constructor or builder pattern.
But now you want the summary itself to be treated as a type of Paperwork aswell, so you create a Summary class annotated with #Paperwork that now creates the summary view. The annotation processing, however, stays in the superclass. This allows the superclass to supply information about the summary to the summary itself without the need of any getters.
Now my question is: Is this a good use of custom annotations?
With the annotation, the superclass can fetch each classes data and store it in a single variable, instead of 20 fields for 20 possible parameters, and 20 more getters if you want to keep them private.
It just seems a bit odd to me to rely on an annotation to provide data that is only really relevant to a single subclass.
Any input is appreciated.

Why to use nested class in builder design pattern, why can't use setters to build the object in the same class

I've visited few sites regarding java builder design pattern. Most of them are showing, to build the class we need to add static nested class by calling the respective setters, then triggering object creation. But query is, why can't we use those setters in the same class without the static nested class.
Due to following reasons:
a. It might happen that you exposed your instance and you are still in middle of object creation via setter method.
b. You would like to make your outer instance immutable.
c. You are separating construction of object with its representation.
d. You would need more control over its construction then representation.

builder pattern and limiting implicit object creation

If I use builder pattern that create some PRODUCT, i would, probably should want to limit the ability to create this PRODUCT by explicit way?
Because it is probably not good of users of my code would create PRODUCT like new PRODUCT().
I mean the users of my code my do not know about some builder.
So, should I make constructor of PRODUCT with as private? And then in the Builder I would use reflection to create the initial instance of the PRODUCT?
Does this approach make sense? Is it ok?
Or you set the constructor as protected, and create a builder in the same package, so it has access to it, or create static methods that might even use your builder implicitly.
If your ProductBuilder is able to create an instance of Product through reflection, then any other class can do the same.
I think, it's easier to add builder and product to the same namespace (package) and make the constructor package private. It has the same effect (invisible for classes outside the package) and keeps the code clean.
What you seem to be describing is called the Factory Pattern (rather than the builder pattern).
The simplest way to implement this is to make your constructor private and provide static factory methods on the Product class. This is the bare minimum implementation:
public class Product {
private Product() {}
public static Product create() {
return new Product();
}
}
There are plenty of classes in the JDK that follow this pattern, for example Integer.parseInt is static factory method the creates as Integer (although the constructor is not private)
Alternatively, you could create a separate Factory class in the same package as Product and give the Product constructor the default visibility.
You should avoid using reflection in general, unless you really need it. In this case you don't need it - keep things as simple as possible (but no simpler).

Creating immutable objects from javabean

I am involved in this project where we are building on good bit of legacy code. I have a particular situation about one big java bean object which has to be transferred over wire. So my first thought was to make it immutable and serializable to do the trick .At this point I am faced with a few difficult choices :-
Ideally I want some way to
automatically generate an immutable,
serializable version of this class.
I dont have the scope to refactor or
alter this class in any way and i
would really really hate to have to
copy paste the class with a
different name ?
Assuming that i gave up on 1 i.e i
actually chose to duplicate code of
the HUGE javabean class , i still
will be in the unsavoury situation
of having to write a constructor
with some 20-25 parameters to make
this class immutable. what is a
better way to make a class immutable
other than constructor injection ?
Thanks and Regards,
To make it truly immutable, you need to initialize the members at construction time.
One way (and I ain't sayin' it's pretty!) to do this and avoid a huge parameter list in the constructor is to have a mutable type that has the same properties. Set the the properties on the mutable type one at a time, through "setters", then pass the mutable object to the constructor of the immutable type as a single argument. The immutable object then copies the properties from the mutable source to it's own (final) members.
You might also consider "effective immutability". That is, even though immutability is not enforced by the system, you use coding practices that clearly separate the initialization phase from the usage phase. After all, immutability is not required for serialization.
You can take this a step further, creating an implementation-hiding wrapper for the interface that doesn't expose the properties of the implementation. The wrapper only implements the methods in the interface, by delegating to the "real" implementation. The setters and getters from the implementation are not present in the wrapper. This will stop clients from simply down-casting from the interface to the implementation class and manipulating the properties.
Joshua Bloch's "Effective Java" illustrates the Builder pattern, where simple Builder objects are used to construct a complex object with a long constructor argument list. I'd recommend it.
http://www.drdobbs.com/java/208403883;jsessionid=PJWS41F5DJ4QRQE1GHRSKH4ATMY32JVN?pgno=2
20-25 properties is not huge for a one off, particularly if you are using a half-decent editor.
If you already have a mutable instance when constructing the immutable version, just pass that to the constructor.
If you want to be really evil hacky, use java.beans to create a serialisable Map for the mutable class or subclass implementing Externalizable. Alternatively you could use java.beans XML serialisation (the XML than can be sent over Java serialisation...).
What about a simple read only interface cotaining the getters?
If the bean class is your own, let it simpley implement the interface and use just the interface after creation.
If you have no control over the bean class, you can also create a getter interface and implement it by creating a proxy for the getter interface with an invokation handler delegating all method calls to the bean.
Step 1: Create a new class and give it instance variables with the exact same names as the instance variables of your 'big java bean object'. That new class should not have setters (but getters only) to make it immutable.
Step 2: Use Apache Commons BeanUtils.copyProperties to copy all the properties (i.e. instance variables) from your 'big java bean object' to your new object.
A few ideas:
Protected setters and factory methods
You can define beans with protected setter methods and in the same package, a factory class that takes all the parameters and calls those setters. The bean is immutable outside that package. To enforce this, be sure to seal your jar so end users cannot create new classes in the same package.
Note: You can use my JavaDude Bean annotations to make the creation simpler:
http://code.google.com/p/javadude/wiki/Annotations
For example:
#Bean(writer=Access.PROTECTED, // all setXXX methods will be protected
properties={
#Property(name="name"),
#Property(name="age", type=int.class)
})
public class Person extends PersonGen {
}
Creating getters and a constructor in eclipse
Eclipse has some nice tools to make this fast:
Create the bean class
Add the fields you want
Right-click in the editor window
Choose Source->Generate Getters and Setters
Press the "Select getters" button
Press ok
Right-click in the editor window
Choose Source->Generate Constructors from fields
Pick and order the fields you want in the constructor
Press ok
Immutability Decorator
Another idea is to define your bean with getters and setters (you can use the above technique but include setters), then you can create a wrapper class for it that only has the getters.

Categories

Resources