Lombok: Annotation that generates only few paramteres in Constructor - spring

I want to know if there's an annotation that generates a constructor which contains only, for example, two attributes of my choice. The annotation #AllArgsConstructor generates a constructor but with all parameters.
Edit: The solution was found but what if for example, I want a constructor for (String age, string D) and one for (String age, String F)?

Currently, there is no such feature and the only way to generate a constructor for the selected fields is by using #RequiredArgsConstructor and labeling only and only such fields as final.
#RequiredArgsConstructor
class Foo {
private final String a;
private final double b;
private int c;
}
new Foo("String", 1.0);
However, you don't want to design the class and its fields to satisfy the needs that Lombok doesn't provide.

Related

Lombok: Generate 2 constructors with specified fields

So I want to generate two constructors using the
#RequiredArgsConstructor
class Foo {
#NonNull
private String a;
#NonNull
private double b;
private int c;
}
My class would be generating a constructer with a & b. But what If I also want to generate a second contructor with b & c? Is there any solution using annnotations?
Due to Lombok documentation, you can't do this. in another language you can not have different constructors with combinations of some fields. a better solution is to use #Builder

EqualsVerifier in SpringBoot

I am creating the tests for two classes that share a list of data. When I use EqualsVerifier I get an error because it is asking me for a list with data shared by these two classes.
This is the error:
Recursive datastructure. Add prefab values for one of the following types: CustomerView, List<YearConfigView>, YearConfigView
This is the #Test class:
#Test
public void CustomerViewTest() {
EqualsVerifier.forClass(CustomerView.class).withRedefinedSuperclass().withGenericPrefabValues(CustomerView.class).verify();
}
#Test
public void YearConfigViewTest() {
EqualsVerifier.forClass(YearConfigView.class).suppress(Warning.ALL_FIELDS_SHOULD_BE_USED).verify();
}
CustomerView.java:
public class CustomerView extends EntityBase<Integer> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private List<YearConfigView> yearConfigs;
#JsonProperty("current_year_config")
public YearConfigView getCurrentYearConfig() {
if (this.getYearConfigs() == null || this.getYearConfigs().isEmpty()) {
return null;
}
int currentYear = LocalDate.now().getYear();
return this.yearConfigs.parallelStream().filter(yc -> yc.getYear() == currentYear).findAny().orElse(null);
}
}
YearConfigView.java:
public class YearConfigView extends EntityBase<Integer> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private CustomerView customer;
private Integer year;
private String comments;
}
My problem: What do I have to change or add in EqualsVerifier to solve the problem?
Creator of EqualsVerifier here.
Without seeing your classes (I'd like to see exactly which fields CustomerView and YearConfigView have, and how equals and hashCode are implemented on both classes), it's hard to say for certain what's going on, but I suspect it's this:
CustomerView has a reference to YearConfigView (or perhaps List<YearConfigView>), and YearConfigView has a reference to CustomerView.
EqualsVerifier, while doing its thing, tries to make instances of the classes it's verifying, and giving its fields proper values too. In order to do that, it must recursively instantiate the class's fields and give those values too. Usually, that's not a problem, but sometimes you run into a loop, like in your case: in order to create a value for CustomerView, it must have a value for YearConfigView and vice versa.
The way to avoid this, is by giving EqualsVerifier some 'prefab values'. I see you've already tried to do something like this, by adding .withGenericPrefabValues(CustomerView.class). (This method requires 2 parameters so I suspect you may have removed some code before posting it to StackOverflow 😉) This only works if CustomerView is itself a generic class, which I can't verify because you didn't post that particular piece of code. In any event, you shouldn't give generic prefab values or regular prefab values for the class you're testing.
In general, though, your tests should both give a prefab value for the other class. That would look like this:
#Test
public void CustomerViewTest() {
YearConfigView one = new YearConfigView();
one.setYear(2020);
YearConfigView two = new YearConfigView();
two.setYear(2021);
EqualsVerifier.forClass(CustomerView.class)
.withRedefinedSuperclass()
.withPrefabValues(YearConfigView.class, one, two)
.verify();
}
#Test
public void YearConfigViewTest() {
CustomerView one = new CustomerView();
one.setName("Alice");
CustomerView two = new CustomerView();
two.setName("Bob");
EqualsVerifier.forClass(YearConfigView.class)
.suppress(Warning.ALL_FIELDS_SHOULD_BE_USED)
.withPrefabValues(CustomerView.class, one, two)
.verify();
}
Note that I still don't know which fields are included in your equals methods, so I'm only making an educated guess about how to instantiate your classes.
For more information, see the relevant page in the EqualsVerifier documentation. Since the classes are JPA entities, this page might also be helpful: it explains how the #Id is treated by EqualsVerifier.

Spring Boot JPA find, filter

As Spring jpa Provides some usefull features to find Items from a repository by defining it in the method name. e .x findByTitle(String title) then Spring is automatically searching the Title Colum for the given String. If i have an int column named numberOfCopies and i want only to find the datasets with >0 greater then null how would define such a method ?
to filter out those books with the numberOfCopies equals 0 = zero
#Entity
public class Book {
#Id
private int id;
private String title;
private int numberOfCopies;
}
can i use the Repomethod
public List findBooksByNumberOfCopies.greater then 0 ?To Use this Spring Feature without some if or for loops
First, you should use Integer, since it is better, in my opinion, to use wrapper classes than to primitives, and enforce not null requirement through annotations, e.g. #Column(nullable = false)
#Entity
public class Book {
#Id
private Integer id;
private String title;
private Integer numberOfCopies;
}
Then you can add the following two methods in your BookRepository;
List<Book> findByNumberOfCopiesGreaterThan(Integer numberOfCopies);
default List<Book> findAllAvailableBooks() {
return findByNumberOfCopiesGreaterThan(0);
}
and use the default findAllAvailableBooks method, with hardcoded 0 value which is your requirement.
you can easily use
List<Book> findByNumberOfCopiesGreaterThanEqual(int numberOfCopies);
Pretty sure this would work:
public interface BookRepo extends JpaRepository<Book, Integer> {
#Query("SELECT b FROM Book b WHERE b.numberOfCopies >= 0")
public Optional<List<Book>> getTheBooksWithMultCopies();
}
// back in your component class:
{
...
Optional<List<Book>> optionalBookList = myBookRepo.getTheBooksWithMultCopies();
if (optionalBookList.isPresent()){
List<Book> bookList = optionalBookList.get();
}
}
Note that the language within the query is called HQL, which is what is used by Hibernate internally (which is used by JPA internally). It's really not very intimidating - just, know that you the objects in your POJO, which map to your database table, rather than your database table directly.
Also, I'd recommend using Integer over int in entity classes, at least if your value is nullable. Otherwise, numberOfCopies will always default to 0, which may not be desirable and may cause exceptions that are difficult to decipher.
GreaterThanEqual takes an Integer not int
List<Book> findByNumberOfCopiesGreaterThanEqual(Integer numberOfCopies);

Is the Builder Pattern not available when updating(CRUD) in a spring boot? Can only be used to create objects(for constructor)? [duplicate]

Lets say I have a lombok annotated class like
#Builder
class Band {
String name;
String type;
}
I know I can do:
Band rollingStones = Band.builder().name("Rolling Stones").type("Rock Band").build();
Is there an easy way to create an object of Foo using the existing object as a template and changing one of it's properties?
Something like:
Band nirvana = Band.builder(rollingStones).name("Nirvana");
I can't find this in the lombok documentation.
You can use the toBuilder parameter to give your instances a toBuilder() method.
#Builder(toBuilder=true)
class Foo {
int x;
...
}
Foo f0 = Foo.builder().build();
Foo f1 = f0.toBuilder().x(42).build();
From the documentation:
If using #Builder to generate builders to produce instances of your own class (this is always the case unless adding #Builder to a method that doesn't return your own type), you can use #Builder(toBuilder = true) to also generate an instance method in your class called toBuilder(); it creates a new builder that starts out with all the values of this instance.
Disclaimer: I am a lombok developer.
Is there an easy way to create an object of Foo using the existing object as a template and changing one of it's properties?
(emphasis mine)
If you really want to change a single property, then there's a nicer and more efficient way:
#With
class Band {
String name;
String type;
}
Band nirvana = rollingStones.withName("Nirvana");
The wither creates no garbage, but it can change just a single field. For changing many fields, you could use
withA(a).withB(b).withC(c)....
and produce tons of garbage (all intermediate results) but than toBuilder is more efficient and more natural.
NOTE: Older versions of lombok have used #Wither annotation. See beginning of documentation.
You might also want do a copy of the object using com.fasterxml.jackson.databind.ObjectMapper
#AllArgsConstructor
#Setter
class Band {
String name;
String type;
}
ObjectMapper objectMapper = new ObjectMapper(); //it's configurable
objectMapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
objectMapper.configure( SerializationFeature.FAIL_ON_EMPTY_BEANS, false );
Band rollingStones = new Band("Rolling Stones", "Rock Band");
Band nirvana = objectMapper.convertValue( rollingStones, Band.class);
nirvana.setName("Nirvana");
it can be easily wrapped in some utility method to be used all over the project like ConvertUtils.clone(rollingStones, Band.class)

ObjectTypeConverter not found within persistence unit

In my project I use an enum in some entities. The enum is to be stored in the database as an integer. To achieve this I use EclipseLink's ObjectTypeConverter.
I'd like to use annotations since I use Spring to omit the persistence.xml. The annotation to configure the ObjectTypeConverter must be specified on an entity. I don't feel the need to specify the annotation on all classes that use this enum as this is redundant and not maintainable. Specifying it once on some entity would work but this doesn't make sense in an OOP design (or any design for that mater). A solution would be to annotate the enum with #ObjectTypeConverter, but this doesn't work since the enum isn't an entity.
Example that isn't working but would be ideal:
#Entity
public class ExampleEntity
{
#Id
private Long id;
#Convert("exampleenum")
private ExampleEnum ee;
}
#ObjectTypeConverter(name = "exampleenum", objectType = ExampleEnum.class, dataType = Integer.class,
conversionValues =
{
#ConversionValue(objectValue = "A", dataValue = "100"),
#ConversionValue(objectValue = "B", dataValue = "200"),
#ConversionValue(objectValue = "C", dataValue = "300")
})
public enum ExampleEnum
{
A, B, C;
}
Example results in the following exception:
Exception Description: The converter with name [exampleenum] used with the element [field ee] in the class [class com.example.ExampleEntity] was not found within the persistence unit. Please ensure you have provided the correct converter name.
Since I'm using Spring, JPA and EclipseLink I accept any answer using these frameworks.
Upon reading the documentation (which I should have done more carefully in the first place) I noticed:
An ObjectTypeConverter must be be uniquely identified by name and can be defined at the class, field and property level and can be specified within an Entity, MappedSuperclass and Embeddable class.
I couldn't annotate the enum with #Entity (as this requires a table) or #MappedSuperclass (as this doesn't make sense), but #Embeddable would make sense in a way. Marking the enum with #Embeddable did the trick:
#Embeddable
#ObjectTypeConverter(...)
public enum ExampleEnum
...

Resources