Best way to initialise fields in a Class without boilerplate code - java

I have a PivotModel class which I will initialise using the new keyword.
PivotModel pivotModel = new PivotModel()
When pivotModel gets initialised, all the dependant fields(model1, model2,cell1,cell2) should get initialised with new object but not to null.
I wanted to initialise all the fields and the fields of dependant classes without using new constructor. I don't want to have boilerplate code.
If you have any standard practice of way doing it, post it here. I am also using lombok in my project.
public class PivotModel {
#Getter
#Setter
private Model1 model1;
#Getter
#Setter
private Model2 model2;
private Model3 model3 = new Model3() -----> Dont want to initialise this way for these fields
}
public class Model1 {
private Map<String,Cell> cell1;
private Map<String,Cell> cell2;
private Map<String,Cell> cell3;
------ will have some 10 fields here
}

It seems that you are using Lombok project in your java project you can add #Getter #Setter above your class Scope, Lombok also provides Constructor Annotation, so Just type above your class Scope #AllArgsConstructor
so you class Should be like this
#Getter
#Setter
#AllArgsConstructor
public class PivotModel {
private Model1 model1;
private Model2 model2;
}
#Getter
#Setter
#AllArgsConstructor
public class Model1 {
private Map<String,Cell> cell1;
private Map<String,Cell> cell2;
private Map<String,Cell> cell3;
}

For initialization, I would recommended Builder Pattern.
//keep your initialization logic in builder class and use build()/create() wherever required. Let's say:
Class Pivot{
// Note: this have only getters for members
//inner builder class
PivotModelBuilder{
//Note: all setter will be part of builder class
/**
* method which return instantiated required object.
*/
public PivotModel build(){
return new PivotModel(this);
}
}
}
//access initilization code as:
PivotModel pivot = new Pivot.PivotModelBuilder().build()
Adding referral link: https://www.javaworld.com/article/2074938/core-java/too-many-parameters-in-java-methods-part-3-builder-pattern.html
(You can search more about builder pattern and it's implementation online)
Limitations:
However, it's good way to initialize/create bean, but, you might find duplication of member fields in both Parent and builder class.

Related

Assign custom lombok builder method as singular handler

I have the following table class which makes usage of #Builder Lombok annotation with a custom builder class:
#Builder
public class MyTable {
...
public static class MyTableBuilder {
public void entry(final MyEntry myEntry) {
...
}
}
}
In another class that is composed by MyTable I would like to make usage of #Builder + #Singular annotations so that I can build TableOwner instances specifying entry by entry.
#Builder
public class TableOwner {
#Singular("entry")
private final MyTable entries;
}
TableOwner.builder()
.entry(...)
.entry(...)
.entry(...)
.build()
However the #Singular annotation on entries results the error "Lombok does not know how to create the singular-form builder methods for type 'MyTable'; they won't be generated.".
Is there a way I can point to MyTableBuilder#entry method as the singular handler for entries?

Is it ok to initialize a #Component object as a private final property in a data class?

Is it ok to initialize a property as part of a data class like in the code below, when the property is defined as a #Component?
#SuperBuilder
#Data
public class DataClass{
private final RandomUUIDGenerator generator = new RandomUUIDGenerator();
#Builder.Default
String uuid = generator.generate();
}
The RandomUUIDGenerator is defined like this:
#Component
public class RandomUUIDGenerator implements UUIDGenerator {
public UUID generate() {
return UUID.randomUUID().toString();
}
}
You can do it, however it is not recommended as you are not utilising the benefits of dependency injection. You should autowire RandomUUIDGenerator using #Autowired annotation.

Lombok #SuperBuilder is not initializing my class objects

I have a parent class and a child class and I am using #SuperBuilder to build the child object, but seemingly it is not initializing at all.
My parent class looks like this:
#Getter
#Setter
#Component
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
#SuperBuilder
public class MessageResponse {
String responseMessage;
}
My child class looks like this:
#Getter
#Setter
#Component
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
#SuperBuilder
public class ListResponse extends MessageResponse {
List<Item> itemList;
int itemCount;
}
Where Item is a Serializable class.
Initially the ListResponse is
itemList = null
itemCount = 0
responseMessage = null
When I try to build ListResponse using builder, it does not change the ListResponse object at all. I am trying to build as
//listResponse is #Autowired from Spring and is initially as shown above.
List<Item> itemList = getItems(); // It returns a list of 15 items, i have checked in debugger, It does.
listResponse.builder()
.bucketList(itemList)
.responseMessage("Item List.")
.bucketCount(itemList.size())
.build();
Even after execution of .build() the contents of this listResponse object is still (null, 0 , null).
I tried to search other references regarding #SuperBuilder and #Builder but got no result. Can someone please point out what is going wrong here?
A builder always creates a new instance. This is the purpose of the builder pattern, and it is how builders work, whether you use Lombok's #SuperBuilder, #Builder, or a manual builder implementation.
You can see that the builder() method is a static method, so it has no access to the instance (typically your IDE should give you a warning here, advising to write ListResponse.builder() instead).
If you want to create a new instance using a builder that is pre-filled with the fields from an existing instance, you can use toBuilder = true as annotation parameter on #(Super)Builder. Then call listResponse.toBuilder().
If you want to modify an instance, the builder pattern is not the right choice. Use setters instead. Those can be generated by Lombok also in a fluent, chainable style; see #Accessors for details.

Spring Data MongoDB does not see accessor for private field from parent class

#Getter
#Setter
#Wither
class A {
protected final List<String> list;
//constructors
}
#Document
#Getter
#Setter
#Wither
class B extends A{
}
In this case, class B gets persisted but when I try to read the document from the Mongo database, i'm getting the following exception: "No accessor to set private final A list"
How to fix this?
Without masses of knowledge of Spring Data MongoDB, I would assume that the list field probably needs to be marked as protected rather than private for it to be visible to the subclass.
protected makes a field visible to its enclosing class's subclasses, whereas private means that only the class itself can see it.

Problem persisting inheritance tree

I have a problem trying to map an inheritance tree. A simplified version of my model is like this:
#MappedSuperclass
#Embeddable
public class BaseEmbedded implements Serializable {
#Column(name="BE_FIELD")
private String beField;
// Getters and setters follow
}
#MappedSuperclass
#Embeddable
public class DerivedEmbedded extends BaseEmbedded {
#Column(name="DE_FIELD")
private String deField;
// Getters and setters follow
}
#MappedSuperclass
public abstract class BaseClass implements Serializable {
#Embedded
protected BaseEmbedded embedded;
public BaseClass() {
this.embedded = new BaseEmbedded();
}
// Getters and setters follow
}
#Entity
#Table(name="MYTABLE")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE", discriminatorType=DiscriminatorType.STRING)
public class DerivedClass extends BaseClass {
#Id
#Column(name="ID", nullable=false)
private Long id;
#Column(name="TYPE", nullable=false, insertable=false, updatable=false)
private String type;
public DerivedClass() {
this.embedded = new DerivedClass();
}
// Getters and setters follow
}
#Entity
#DiscriminatorValue("A")
public class DerivedClassA extends DerivedClass {
#Embeddable
public static NestedClassA extends DerivedEmbedded {
#Column(name="FIELD_CLASS_A")
private String fieldClassA;
}
public DerivedClassA() {
this.embedded = new NestedClassA();
}
// Getters and setters follow
}
#Entity
#DiscriminatorValue("B")
public class DerivedClassB extends DerivedClass {
#Embeddable
public static NestedClassB extends DerivedEmbedded {
#Column(name="FIELD_CLASS_B")
private String fieldClassB;
}
public DerivedClassB() {
this.embedded = new NestedClassB();
}
// Getters and setters follow
}
At Java level, this model is working fine, and I believe is the appropriate one. My problem comes up when it's time to persist an object.
At runtime, I can create an object which could be an instance of DerivedClass, DerivedClassA or DerivedClassB. As you can see, each one of the derived classes introduces a new field which only makes sense for that specific derived class. All the classes share the same physical table in the database. If I persist an object of type DerivedClass, I expect fields BE_FIELD, DE_FIELD, ID and TYPE to be persisted with their values and the remaining fields to be null. If I persist an object of type DerivedClass A, I expect those same fields plus the FIELD_CLASS_A field to be persisted with their values and field FIELD_CLASS_B to be null. Something equivalent for an object of type DerivedClassB.
Since the #Embedded annotation is at the BaseClass only, Hibernate is only persisting the fields up to that level in the tree. I don't know how to tell Hibernate that I want to persist up to the appropriate level in the tree, depending on the actual type of the embedded property.
I cannot have another #Embedded property in the subclasses since this would duplicate data that is already present in the superclass and would also break the Java model.
I cannot declare the embedded property to be of a more specific type either, since it's only at runtime when the actual object is created and I don't have a single branch in the hierarchy.
Is it possible to solve my problem? Or should I resignate myself to accept that there is no way to persist the Java model as it is?
Any help will be greatly appreciated.
Wow. This is the simplified version? I assume that the behavior that you are seeing is that BaseEmbedded field is persisted but not the FIELD_CLASS_A or B?
The problem is that when Hibernate maps the DerivedClassA and B classes, it reflects and sees the embedded field as a BaseEmbedded class. Just because you then persist an object with the embedded field being a NestedClass, the mapping has already been done and the FIELD_CLASS_A and B are never referenced.
What you need to do is to get rid of the NestedClass* and embedded field and instead have the fieldClassA and B be normal members of DerivedClassA and B. Then add add a name field to the #Entity which will put them both in the same table I believe. This will allow you to collapse/simplify your class hierarchy a lot further.
See: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e1168
#Entity(name = "DerivedClass")
#DiscriminatorValue("A")
public class DerivedClassA extends DerivedClass {
#Column(name="FIELD_CLASS_A")
private String fieldClassA;
...
#Entity(name = "DerivedClass")
#DiscriminatorValue("B")
public class DerivedClassB extends DerivedClass {
#Column(name="FIELD_CLASS_B")
private String fieldClassB;
...

Categories

Resources