Lombok: Generate 2 constructors with specified fields - spring

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

Related

Lombok: Annotation that generates only few paramteres in Constructor

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.

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)

Spring Data Couchbase put #Id attribute to json when embedded

I have a one to many relationship namely A and B. A may refer to many B instances. B instances also can be managed independently.
That's why, B class looks like this:
public class B {
#Id
private String id;
private String appId;
}
A class will refer to a list of B instances. So it looks like this:
public class A {
#Id
private String id;
private int age;
private List<B> bInstances;
}
When bInstances are filled with B instances and then A instance is saved, id fields of the B instances are removed from the JSON document since it is annotated with #Id.
I simply need to add this field to JSON when B is embedded into another class.
And when B instance is saved independently, #Id field can be used as the regular key.
How may I do this?
To answer your question specifically, yes the field annotated #Id won't get written to the serialized json. Your best bet here is to duplicate the field and set its value in either the constructor or a setter, for example:
public class B {
#Id
private String metaId;
private String id;
private String appId;
public setMetaId(String metaId) {
this.metaId = metaId;
this.id = metaId;
}
}
You can #JsonIgnore one of them if you don't want to see the duplication in your serializations.
Note: I totally agree with Robin's answer, but there are cases where you want to save the data as-it-was and you want to refer to it in the future.. so you don't care if B instance changed one week after you saved the data. So it really depends on your scenario.
I would strongly advise you to not store the instances of B directly in a document of A. Doing this would result in data inconsistencies if an instance of B is changed in another context than A. Additionally you duplicate data unnecessarily if an instance of B is stored in multiple documents of class A.
The desired way to store instances of one class in another is to save the document ids instead. So your class A should look like this:
public class A {
#Id
private String id;
private int age;
private List<String> bInstanceIds;
}

Spring JPA OneToOne out of a OneToMany with only the fist entry

my problem can be broken down to this little example:
I have a entity class A and a entity class B. A has a List of B objects. Now there is always only one B relevant. So I do not want to load all B's of an A, only to access this one B (last inserted B inside a A).
The question: Can I manipulate an entity without an service, so that there is a #Transient variable, that is always the newest B? And also without saving the newest B separately in A. Is there a way to achieve this?
class B{
#Id
#GeneratedValue
private Long id;
#Column(nullable=false)
private String name;
#Column(nullable=false)
private Date created = new Date();
}
class A{
#Id
#GeneratedValue
private Long id;
#OneToMany
#OrderBy("created ASC")
private List<B> b;
#Transient
private B newestB; // Here should be only the newest B
}
Yes. Forget storing the newest B as a variable and instead simply add a getter for it:
#Transient
public B getNewestB() {
return b.get(b.size() -1);
}
This will solve your problem under the assumption that b is set to FetchType.EAGER. Fetching using b's getter and FetchType.LAZY may not be so straight forward as Spring may rely on an AOP proxy call to trigger the lazy load (you'd need to experiment).
However, I'd discourage both these approaches. You're effectively trying to fit business logic into your Entity. Why not keep your entity clean and perform this query using B's repository?
E.g.
public interface BRepository extends CrudRepository<B, Long> {
#Query(...) //query to get newest B for specified A
B getNewest(A a)
}

Resources