Lombok's #With annotation on concrete class does not apply on abstract parent's class fields - spring

Using Java spring boot, I'm trying to inherit from a super class and implement Lombok's #With annotation on child classes
However, I am not able to use Lombok's .with(property) methods on the abstract's class fields in order to get a new object of the child's instance.
#Getter
#EqualsAndHashCode
#ToString
#With
#SuperBuilder
public class Child extends Parent {
private float a;
private int b;
public Child(float a,int b, int c) {
super(c);
this.a = a;
this.b = b;
}
#AllArgsConstructor
#Getter
#SuperBuilder
#With
public abstract class Parent {
protected int c;
}
What am I missing?

Lombok can only automatically implement the #Width methods for fields of concrete classes, since part of the implementation is the instantiation of the class. This only works for specific classes. For fields of abstract classes you have to implement the method manually. Did you take that into account?
The following works and can be generated automatically, therefore lombok can use the constructor of the class directly to instantiate:
public Child withA(float a) {
return this.a == a ? this : new Child(a, this.b, this.c);
}
The following does not work because the class is abstract:
public Parent withC(int c) {
return this.c == c ? this : /* WHAT TO DO HERE?!; new Parent(...) IS WRONG */;
}

Related

Using Lombok's #SuperBuilder concept on a class extended from a 3rd party library

I have a class hierarchy as below.
Child --> Parent --> SuperParent
Since the Child class has extended the Parent class I have to use Lombok's #SuperBuilder annotation instead of the #Builder. Also, as far as I know, all the superclasses need to have the #SuperBuilder annotation. But in my case, the SuperParent class comes from an external library, where I cannot add the #SuperBuilder annotation. I am getting the below compilation error.
The constructor SuperParent(DocumentUploadedResponseDto.DocumentUploadedResponseDtoBuilder<capture#1-of ?,capture#2-of ?>) is undefined.
Any solution or an alternative for this? Thank you.
It's a bit ugly, but it's possible. You have to insert a helper class into your inheritance chain between Parent and SuperParent; let's call it SuperParentBuilderEnabler. In this class, you have to manually implement all neccessary builder elements. Especially, you have to write all setter methods for the fields from SuperParent.
This will allow the Parent and Child classes to simply use a #SuperBuilder annotation without any further modifications.
I assume that SuperParent has an int superParentField field, just to demonstrate how you can write such a setter method in the builder class. Furthermore, I assume that this field can be set via constructor argument. Here is what you have to do:
public abstract class SuperParentBuilderEnabler extends SuperParent {
public static abstract class SuperParentBuilderEnablerBuilder<C extends SuperParentBuilderEnabler, B extends SuperParentBuilderEnablerBuilder<C, B>> {
private int superParentField;
public B superParentField(int superParentField) {
this.superParentField = superParentField;
return self();
}
protected abstract B self();
public abstract C build();
}
protected SuperParentBuilderEnabler(SuperParentBuilderEnablerBuilder<?, ?> b) {
super(b.superParentField);
}
}
Now let Parent extend SuperParentBuilderEnabler and you're done.
I'm sharing how I applied the accepted answer for RepresentationModel.
abstract class BaseTypeParent<T extends BaseTypeParent<T>>
extends RepresentationModel<T> {
protected abstract static class BaseTypeParentBuilder<
T extends BaseTypeParent<T>,
C extends BaseTypeParent<T>,
B extends BaseTypeParentBuilder<T, C, B>
> {
protected abstract B self();
public abstract C build();
}
protected BaseTypeParent(final BaseTypeParentBuilder<T, ?, ?> b) {
super();
}
}

spring-data-envers -2.0.0.RELEASE

Right now we are using 0.3.0.RELEASE to get the revision data and noticed that the revisions are fetched in ascending order.
the existing code
#EnableJpaRepositories( value = "org.xxx.xxx.xxx.repository", repositoryFactoryBeanClass = RevisionRepositoryFactoryBean.class )
#EnableJpaAuditing( auditorAwareRef = "springSecurityAuditorAware" )
#EnableTransactionManagement
public class DatabaseConfiguration {
.......
}
public class RevisionRepositoryFactoryBean extends EnversRevisionRepositoryFactoryBean {
public RevisionRepositoryFactoryBean() {
setRevisionEntityClass( Revision.class );
}
}
Found that the newer version 2.0.0.RELEASE has functionality to sort based on sort in pageable object. So wanted to use 2.0.0.RELEASE.
the following is the modifications
public class RevisionRepositoryFactoryBean<T extends RevisionRepository<S, ID, N>, S, ID extends Serializable, N extends Number & Comparable<N>> extends EnversRevisionRepositoryFactoryBean<T, S, ID,N> {
public RevisionRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
setRevisionEntityClass( Revision.class );
// TODO Auto-generated constructor stub
}
}
but did not work...
compile error in DatabaseConfiguration file
No constructor with 0 arguments defined in class
'org.xxx.xxx.xxx.config.RevisionRepositoryFactoryBean'
Do anyone has an example how to use spring-data-envers -2.0.0.RELEASE in spring boot application.
Thanks
Srini

How to pass dynamic values to a constructor from another class which is injected as autowired object

How to pass dynamic values to a constructor from another class which is injected as autowired object?
#Service
Class Test {
int a;
String b;
public Test(int a, String b) {
this.a = a;
this.b = b;
}
}
Class Sample {
#Autowired
Test test;
}
How can I pass values to Test class constructor from Sample class?
Spring beans are immutable by idea.
If your Test instance is different for every instance of Sample class, it don't have to be a spring bean, especially if some fileds on the Test instance depend on values from the Sample instance.
Maybe a solution would be to change your Test class scope so you can create multiple instances, but you have to explain more what you mean by dynamic values.

Use another bean as parameter for constructor injection

I there any posibility to inject bean member into constructor of another bean member? Something like code below:
class Config {
#Resource("${root-service}")
IServiceRoot root;
#Resource("${child-service}")
IServiceChild child;
}
#Component("root1")
class ServiceRoot1 implements IServiceRoot {
}
#Component("root2")
class ServiceRoot2 implements IServiceRoot {
}
#Component("child1")
class ServiceChild1 implements IServiceChild {
public ServiceChild1(IServiceRoot r) {
root = r;
}
}
#Component("child2")
class ServiceChild2 implements IServiceChild {
public ServiceChild2(IServiceRoot r) {
root = r;
}
}
child-service and root-service props are set to "child1/child2" and "root1/root2" respectively. Now I want to be able to construct child member using root member.
#Resource(${child-service})
#ConstructorArg(member="root")
ServiceChild child;
So after constructing root by spring it will be used to construct child. How can I achieve behaviour like #ConstructorArg?

Java - Generic class extended by concrete class

I have a number of classes, POJO style, that shares a single functionality, say readCSV method. So I want to use a single parent (or maybe abstract, not sure if it should be) class that these POJOs can extend. Here's a pseudo-code:
(abstract) class CSVUtil {
private String[] fileHeader = null;
protected void setFileHeader(fileHeader) {
this.fileHeader = fileHeader;
}
protected List<WhateverChildClass> readCSV(String fileName) {
// read CSV using Apache Commons CSV
// and return a List of child type
List<WhateverChildClass> list = null;
// some declarations
try {
list = new ArrayList<WhateverChildClass>();
csvParser = new CSVParser(fileReader, csvFormat);
List csvRecords = csvParser.getRecords();
for (...) {
CSVRecord record = (CSVRecord) csvRecords.get(i);
WhateverChildClass childClass = new WhateverChildClass();
// loop through fields of childClass using reflection and assign
for (// all fields of childClass) {
childClass.setWhateverField(record.get(fileHeader[i]));
}
list.add(childClass);
System.out.println(p);
ps.add(p);
}
}
...
return list;
}
}
on one of the child classes, say ChildA
class ChildA extends CSVUtil {
// fields, getters, setters
}
How do I code the CSVUtil such that I can determine in runtime the child class in readCSV defined in the parent class?
Is it possible to make this method static and still be inherited?
As an alternative, is there API in Apache Commons CSV that can generally read a CSV, determine its schema, and wrap it as a generic Object (I don't know if I make sense here), and return a list of whatever that Object is ?
You want that readCSV to be a static method ?
Then, i would say that ChildA class shouldn't inherit from CSVUtil, but implement an Interface ... something like that :
public final class CSVUtil {
private CSVUtil() {
}
public static <T extends ICSV> List<T> readCSV(String filename) {
...
}
class ChildA implements ICSV

Resources