Lombok builder to check non null and not empty - java

I have a class with variables I don't want it to be null or empty. Is there a way to use Lombok builder to set the property? I can use #NonNull but I won't be able to verify if it is empty or not. Obviously the other option is to write my own builder which does all these checks. For example:
class Person {
#NonNull
private String firstName;
#NonNull
private String lastName;
public static class PersonBuilder() {
// .
// .
// .
public Person build() {
//do checks for empty etc and return object
}
}
}

Maxim Kirilov's answer is incomplete. It doesn't check for blank/empty Strings.
I've faced the same issue before, and I realized that in addition to using #NonNull and #Builder from Lombok, overload the constructor with a private access modifier, where you can perform the validations. Something like this:
private Person(final String firstName, final String lastName) {
if(StringUtils.isBlank(firstName)) {
throw new IllegalArgumentException("First name can't be blank/empty/null");
}
if(StringUtils.isBlank(lastName)) {
throw new IllegalArgumentException("Last name can't be blank/empty/null");
}
this.firstName = firstName;
this.lastName = lastName;
}
Also, throwing IllegalArgumentException makes more sense (instead of NPE) when String has blank, empty or null values.

The builder annotation should solve your issue:
#Builder
class Person {
#NonNull
private String firstName;
#NonNull
private String lastName;
}
The generated code is:
class Person {
#NonNull
private String firstName;
#NonNull
private String lastName;
#ConstructorProperties({"firstName", "lastName"})
Person(#NonNull String firstName, #NonNull String lastName) {
if(firstName == null) {
throw new NullPointerException("firstName");
} else if(lastName == null) {
throw new NullPointerException("lastName");
} else {
this.firstName = firstName;
this.lastName = lastName;
}
}
public static Person.PersonBuilder builder() {
return new Person.PersonBuilder();
}
public static class PersonBuilder {
private String firstName;
private String lastName;
PersonBuilder() {
}
public Person.PersonBuilder firstName(String firstName) {
this.firstName = firstName;
return this;
}
public Person.PersonBuilder lastName(String lastName) {
this.lastName = lastName;
return this;
}
public Person build() {
return new Person(this.firstName, this.lastName);
}
public String toString() {
return "Person.PersonBuilder(firstName=" + this.firstName + ", lastName=" + this.lastName + ")";
}
}
}
In this case the null validation will take place during object construction.

I did something like this,
class Person {
private String mFristName;
private String mSecondName;
#Builder
Person(String firstName, String secondName) {
mFristName = PreCondition.checkNotNullOrEmpty(firstName);
mSecondName = PreCondition.checkNotNullOrEmpty(secondName);
}
}
class PreCondition {
static <T> T checkNotNullOrEmpty(T instance) {
if (instance == null || (instance instanceof String && ((String) instance).isEmpty())) {
throw new NullOrEmptyException();
}
return instance;
}
static class NullOrEmptyException extends RuntimeException {
NullOrEmptyException() {
super("Null or Empty");
}
}
}

Have you tried "#NotEmpty"? It's in the javax.validation.constraints package
https://javaee.github.io/javaee-spec/javadocs/javax/validation/constraints/NotEmpty.html

Related

Pattern Builder to create multiple objects at once (list)

I would like to create a Builder pattern to create multiple objects at once.
Because with basic builder pattern it can only build one object..
Example of what I did:
package builders;
import java.util.function.Function;
public class UserBuilder {
private List<User> users;
private int userCount;
private UserBuilder() {
}
private UserBuilder(int userCount) {
this.userCount = userCount;
}
private UserBuilder(UserBuilder copy) {
this.users = copy.users;
this.userCount = copy.userCount;
}
public static UserBuilder user() {
return new UserBuilder();
}
public static UserBuilder users(int userCount) {
return new UserBuilder(userCount);
}
public UserBuilder withFirstname(String firstName) {
return withFirstname((unused) -> firstName);
}
public UserBuilder withFirstname(Function<Integer, String> func) {
for (int i = 0; i < users.size(); i++)
users.get(i).setFirstName(func.apply(i));
return this;
}
public UserBuilder withLastName(String lastName) {
return withLastName((unused) -> lastName);
}
public UserBuilder withLastName(Function<Integer, String> func) {
for (int i = 0; i < users.size(); i++)
users.get(i).setLastName(func.apply(i));
return this;
}
public User build() {
return user.get(0);
}
public User build(int index) {
return user.get(index);
}
public List<User> buildAll() {
return users;
}
}
Usage:
// Our builder can be use to create single object like basic builder:
User user = UserBuilder.user()
.withFirstName("toto")
.withLastName("tata")
.build();
// OR it can also build 10 users and set parameters thanks to lambdas
List<User> users = UserBuilder.users(10)
.withFirstName((index) -> "toto" + index)
.withLastName("tata")
.buildAll();
// users will have firstName=toto$index and all will have lastName=tata
What do you think about this pattern?
This is what I want BUT I must duplicate all my methods (with its lambda version..)
Maybe there is a way to delete 50% of methods by adding an annotation or something like that?
Is there a cleaner version?
The more common approach (also used in e.g. JavaFX) would be to stay with a single object builder but re-use the common fields.
In your example you aren't winning much by having the list allocation in your Builder.
public class User {
private String firstName;
private String lastName;
private User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Override
public String toString() {
return "User{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
public static class UserBuilder {
private String firstName;
private String lastName;
public UserBuilder firstName(String firstName) {
this.firstName = firstName;
return this;
}
public UserBuilder lastName(String lastName) {
this.lastName = lastName;
return this;
}
public User build() {
return new User(firstName, lastName);
}
}
}
User user = new User.UserBuilder().firstName("toto").lastName("tata").build();
User.UserBuilder commonBuilder = new User.UserBuilder().lastName("tata");
List<User> users = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
users.add(commonBuilder.firstName("toto" + i).build());
}
List<User> users2 = IntStream.range(0, 10).mapToObj(index -> commonBuilder.firstName("toto" + index).build()).toList();
This may be helpful:
How difficult can it ever be to build a list of objects in Java and Kotlin using the builder pattern?
Part of the code:
class ManufacturerListBuilder {
private String continent;
private final List<Manufacturer> manufacturers = new LinkedList<>();
public ManufacturerListBuilder withContinent(String continent) {
this.continent = continent;
return this;
}
ManufacturerListBuilder add(Function<ManufacturerBuilder, ManufacturerBuilder> builderFunction) {
ManufacturerBuilder builder = ManufacturerBuilder
.apply(new ManufacturerBuilder()
.withContinent(continent))
.build();
this.manufacturers.add(builder);
return this;
}
public Collection<UserFilter> getManufacturers() {
return this.manufacturers;
}
}

Nested JSON mapped to POJO in AWS Lambda is returning null

I am trying to run a lambda function which will get couple of nested JSON's as input. I am trying to map them with POJO classes. But the nested JSON's values are returning null.
I have given a sample of the problem here.
Input:
{
"firstName": "Raj",
"lastName": "Guru",
"parameters" : {
"Address ": "Testaddress",
"POBOX" : "123"
}
}
OutPut:
Uploading function code to lambda...
Upload success. Function ARN: arn:aws:lambda:eu-central-1:938487755516:function:lambda
Invoking function...
==================== FUNCTION OUTPUT ====================
{"greetings":"Hello `Raj,` null.null"}
package com.amazonaws.lambda.demo;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
public class HelloPojo implements RequestHandler<RequestClass, ResponseClass> {
public ResponseClass handleRequest(RequestClass request, Context context){
String greetingString = String.format("Hello %s, %s.", request.getFirstName(), request.getparameters().getAddress());
greetingString+= request.getparameters().getAddress();
return new ResponseClass(greetingString);
}
---------------------------------------------------------------------------------------------------------------
package com.amazonaws.lambda.demo;
public class parameters {
private String Address;
private String POBOX;
public String getAddress() {
return Address;
}
public void setAddress(String Address) {
this.Address = Address;
}
public String getPOBOX() {
return POBOX;
}
public void setPOBOX(String POBOX) {
this.POBOX = POBOX;
}
public parameters(String Address,String POBOX) {
this.Address = Address;
this.POBOX = POBOX;
}
public parameters() {
}
#Override
public String toString(){
return getPOBOX()+getAddress();
}
}
// RequestClass:
package com.amazonaws.lambda.demo;
import com.fasterxml.jackson.annotation.JsonProperty;
public class RequestClass {
private parameters parameters = new parameters( );
#JsonProperty("parameters")
public parameters getparameters() {
return parameters;
}
public void setparameters(parameters paramters) {
this.parameters = paramters;
}
package com.amazonaws.lambda.demo;
public class ResponseClass {
String greetings;
public String getGreetings() {
return greetings;
}
public void setGreetings(String greetings) {
this.greetings = greetings;
}
public ResponseClass(String greetings) {
this.greetings = greetings;
}
public ResponseClass() {
}
}
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public RequestClass(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public RequestClass() {
}
#Override
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("firstName=" + getFirstName() + "\n");
sb.append("lastName=" + getLastName() + "\n");
sb.append("parameters =" + getparameters() + "\n");
return sb.toString();
}
}
Try renaming class parameters to class Parameters. With uppercase.
There is some issue with getter and setter functions of your code. I tried running your code in eclipse and faced same error. I think getter and setter functions of your parameter class is improper. [Agree with Iam, rename parameter class to Parameter, and update getter, setter methods accordingly]
Also, AWS Lambda does the deserialization of input JSON objetcs for you, so you may not need to use Jackson Annotation for deserializing JSON input.
Thanks!

How i can bind two substring to one?

I have two string
private StringProperties firstName;
private StringProperties lastName;
private StringProperties nickName;
the first and last name are picked by user, the nickName is a concatenation of first 3 character of first and lastname
How i can do that?
Actually i initialize it like that (this is the entire class).
public class Person {
private StringProperty firstName;
private StringProperty lastName;
private StringProperty nickName;
private ObservableList<Evento> eventi = FXCollections.observableArrayList();
public Person(String firstName, String lastName) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
if (firstName.length() > 2 && lastName.length() > 2)
this.nickName = new SimpleStringProperty(firstName.trim().substring(0,3).concat(lastName.trim().substring(0,3)));
else
this.nickName = new SimpleStringProperty("");
}
public ObservableList<Evento> getEventi() {
return eventi;
}
public String getFirstName() {
if(firstName == null) firstName = new SimpleStringProperty(this,"firstName");
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public String getLastName() {
if(lastName == null) lastName = new SimpleStringProperty(this, "lastName");
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public String getNickName() {
if(nickName == null) nickName = new SimpleStringProperty(this,"nickName");
return nickName.get();
}
public StringProperty nickNameProperty() {
return nickName;
}
#Override
public String toString() {
return getNickName() + "(" + getLastName() + " " + getFirstName() + ")";
}
}
but when i let the user change first or lastName, the nickName won't update.
You should use ReadOnlyStringProperty for the nickname:
private ReadOnlyStringWrapper nickName= new ReadOnlyStringWrapper();
...
public final String getNickName() {
return nickName.get();
}
public final ReadOnlyStringProperty nickNameProperty() {
return nickName.getReadOnlyProperty();
}
As for binding, you can use utility methods from Bindings class or implement your own binding for any other complicated cases. This example uses createStringBinding() method. It takes Callable functional interface, which will be used to calculate new value, and list of observable properties, which values will be observed for changes:
public Person(String firstName, String lastName) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
this.nickName.bind(Bindings.createStringBinding(()->{
if(this.firstName.get().length() > 2 && this.lastName.get().length() > 2) {
return this.firstName.get().substring(0,3).concat(this.lastName.get().trim().substring(0,3));
} else {
return "";
}
}, this.firstName, this.lastName));
}
You can use Bindings.format:
nickName.bind(Bindings.format("%.3s%.3s", firstName, lastName));
The 3 in %.3s is the maximum length of the string.
This won't do any trimming of the strings though, (you could do that before passing the strings to firstName and lastName).
It will also work on strings that are smaller than 3 characters. So, you can get nicknames like FoBar, FooB or Bar (if the first name is an empty string).

Java Inheritance with Private Setter

I've created a Person class, and a class that inherits from it, the Professor class. Now, I've declared my setters private in the Person class and Professor class. I want the constructors to set the variables, by calling the setters and performing validation. Is what I've done correct? If not, what can I do to correct it?
Person Class:
public class Person {
private String firstName;
private String lastName;
public Person(String firstname,String lastname) throws InvalidDataException
{
setFirstName(firstname);
setLastName(lastname);
}
public String getFirstName() {
return firstName;
}
private void setFirstName(String firstName) throws InvalidDataException {
if ( firstName == null || firstName.length() < 1) {
throw new InvalidDataException("Person Must have First Name");}
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
private void setLastName(String lastName) throws InvalidDataException {
if ( lastName == null || lastName.length() < 1) {
throw new InvalidDataException("Person Must have Last Name");}
this.lastName = lastName;
}
Professor class
public class Professor extends Person {
private String professorID;
public Professor(String professorID,String firstname, String lastname) throws InvalidDataException {
super(firstname, lastname);
// TODO Auto-generated constructor stub
this.setID(professorID);
}
private void setID(String professorID) throws InvalidDataException{
if ( professorID == null ||professorID.length() < 1) {
throw new InvalidDataException("Person Must have ID");}
this.professorID = professorID;
}
public String getID()
{
return this.professorID;
}
public void printData()
{
System.out.println("Professor ID: " + this.getID() + " First Name: " + this.getFirstName() + " Last Name: " + this.getLastName());
}
}
Considering that your "setters" mainly check Strings for being neither null nor empty, you might have a static or utility method doing just that, and call it in the constructor (and/or public setters) before you assign to the class member.
public class Person {
protected void check( String s, String msg ){
if( s == null ||s.length < 1) {
throw new InvalidDataException(msg);
}
}
public Person(String firstname,String lastname) throws InvalidDataException{
check( firstname, "Person's first name missing" );
check( lastname, "Person's last name missing" );
this.firstname = firstname;
this.lastname = lastname;
}
public void setFirstname( String firstname ){
check( firstname, "Person's first name missing" );
this.firstname = firstname;
}
}
But a bean shouldn't need guards like this. If there's a GUI, the GUI should do the validation, passing only correct values to object construction.
It is a bad practice to declare setters as private . because setters goal is to call them outside that class from the class instance. If you really want to fill your class properties with the constructor you may create a private functions that will build up your class.
** ps: if your class attributes are easy to fill you may fill them in your constructor .you dont need any support functions.
The best way would be to set the Person class members protected instead of private.
Anyway, setters and getters are supposed to be public in OOD.

Java Overriding Protected Setters and Eliminate Public Setters

Person Class:
public class Person {
private String firstName;
private String lastName;
public Person(String firstname,String lastname) throws InvalidDataException
{
setFirstname( firstname);
setLastname(lastname);
}
public void personFirstName(String firstName) throws InvalidDataException {
setFirstname(firstName);
}
public void personLastName(String lastname) throws InvalidDataException {
setLastname(lastname);
}
public String getFirstName() {
return firstName;
}
public String getlasttName()
{
return lastName;
}
protected final void setFirstname(String firstname) throws InvalidDataException{
if( firstname == null ||firstname.length() < 1) {
throw new InvalidDataException("First Name Cannot be Empty");
}
this.firstName=firstname;
}
protected final void setLastname(String lastname) throws InvalidDataException {
if( lastname == null ||lastname.length() < 1) {
throw new InvalidDataException("Last Name Cannot be Empty");
}
this.lastName = lastname;
}
}
Professor Class:
public class Professor extends Person {
private String professorID;
public Professor(String professorID,String firstname, String lastname) throws InvalidDataException {
super(firstname, lastname);
// TODO Auto-generated constructor stub
setProfessorID(professorID);
}
public void setID(String professorID) throws InvalidDataException{
setProfessorID(professorID);
}
public String getID()
{
return this.professorID;
}
private void setProfessorID(String ID) throws InvalidDataException{
if( ID == null ||ID.length() < 1) {
throw new InvalidDataException("ID Cannot be Empty");
}
this.professorID=ID;
}
public void printData()
{
System.out.println("Professor ID: " + this.getID() + " First Name: " + this.getFirstName() + " Last Name: " + this.getlasttName());
}
}
I've done some research on implementing setters and calling them in my sub-class. By declaring them protected and final, I prevent the sub-class from overriding it and doing unwanted behavior. My question is this, can I now get rid of personFirstName() and personLastName()? My constructor doesn't use it, and they call the protected final setFirstname, and setLastname(). Would getting rid of the public setters cause an issue later on in development?
You've said your goal is to avoid calling methods in the constructor that may be overridden by a subclass. If so, I'd approach it like this:
public Person(String firstName, String lastName) {
this.privateSetFirstName(firstName);
this.privateSetLastName(lastName);
}
private void privateSetFirstName(String firstName) {
// ...your logic for setting the field...
}
private void privateSetLastName(String lastName) {
// ...your logic for setting the field...
}
public void setFirstName(String firstName) {
this.privateSetFirstName(firstName);
}
public void setLastName(String lastName) {
this.privateSetLastName(lastName);
}
E.g., make the standard setters standard, and keep your implementation-specific details in private methods within your implementation.
You should try to avoid doing stuff within the getters and setter, it can give you a hard time tracking down errors - check the data elsewhere. I think this much simpler version will do:
public class Person {
private String firstName;
private String lastName;
public Person() {} // introducing an empty constructor gives you more flexibility
public Person(String firstname, String lastname) {
setFirstname( firstname);
setLastname(lastname);
}
public String getFirstName() {
return firstName;
}
public String getLasttName() {
return lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
public class Professor extends Person {
private String professorID;
public Professor (super();) {} // introducing an empty constructor gives you more flexibility
public Professor (String firstname, String lastname, String professorID) {
super(firstname, lastname);
this.professorID = professorID;
}
public void setID(String professorID) {
setProfessorID(professorID);
}
public String getID() {
return this.professorID;
}
}

Categories

Resources