I recently wrote a builder class and noticed that the standard seems to be as follows
public class PersonBuilder {
private String firstName;
private String lastName;
public PersonBuilder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public PersonBuilder withLastName(String lastName) {
this.lastName = lastName;
return this;
}
public Person build() {
return new Person(this);
}
}
Is there any disadvantage to, instead, doing the following
public class PersonBuilder {
private Person person;
public PersonBuilder withFirstName(String firstName) {
person.setFirstName(firstName);
return this;
}
public PersonBuilder withLastName(String lastName) {
person.setLastName(lastName);
return this;
}
public Person build() {
return person;
}
}
I understand this may be an opinion based question, I was just looking for any answers as to why this may be a bad or better design pattern.
There are several problems with your approach. Some of them are described in previous answers so I'll just mention the others.
The biggest problem with your design, is that you're using a single instance of Person in the builder. This means that if you're using the same builder more than once, you'll be "building" the same instance, while the clients using it are expecting two different instances. No need to mention that this could cause some serious havoc in your application.
The answer you got from #Basilevs mentions that the "built" class will require setters. This is absolutely true, but I'd just like to stress that this is a huge problem, since it means that the classes you "build" can never be immutable ! In other words, you're restricting the implementers of such classes to using synchronization for thread safety if needed, and other problem solving mechanisms that could have been avoided using the common approach.
Builder can be used when there is no setters in the class being built.
Accepting builder as constructor argument introduces tight coupling.
Following approach solves these:
public class PersonBuilder {
private String firstName;
private String lastName;
public PersonBuilder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public PersonBuilder withLastName(String lastName) {
this.lastName = lastName;
return this;
}
public Person build() {
return new Person(firstName, lastName);
}
}
Is there any disadvantage to, instead, doing the following
Yes, by the time the user call the withFirstName method it will result to NPE because you did not even instantiate person.
Related
I am following a Udemy tutorial in Spring boot. There's a part where #Query wasn't used for a user-created method in the repository interface. It works, but I want to understand when JpaRepository takes care of the creation of query. In the User class below, #Table wasn't used.
findByEmail(String email) method works without any implementation/definition. So, my impression was that, JpaRepository automatically created the Select from User where email = emailargument
So here's what I have
A database named reservation with table User
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/reservation
spring.datasource.username=root
User.java
import javax.persistence.Entity;
#Entity
public class User extends AbstractEntity{
private String firstName;
private String lastName;
private String email;
private String password;
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
UserRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import com.project.flightreservation.entities.User;
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
}
When Spring Data creates a new Repository implementation, it analyses all the methods defined by the interfaces and tries to automatically generate queries from the method names. While this has some limitations, it's a very powerful and elegant way of defining new custom access methods with very little effort. Ref
by implementing one of the Repository interfaces, the DAO will already have some basic CRUD methods (and queries) defined and implemented.
You can create more complex queries with this approach reference
The one which you posted in question is called automatic custom query.
JPA has ability to construct query in different ways. You can use queries derived from methodName with the predicates IsStartingWith, StartingWith, StartsWith, IsEndingWith, EndingWith, EndsWith, IsNotContaining, NotContaining, NotContains, IsContaining, Containing, Contains the respective arguments for these queries will get sanitized.
If you face the situation in which either the method name parser does not support the keyword you want to use or the method name would get unnecessarily ugly, you can use #Query for namedQuery support of JPQL or nativeQuery.
I would strongly suggest you to go through this documentation
I have a POJO which has tens of fields, and I have to set all the fields' values.
How to avoid forgetting to set some field's value?
// POJO
public class Employee {
private Date birthday;
private String firstName;
private String lastName;
private String birthOfPlace;
// ...
// setters and getters
}
// Main class
public class MainClass {
public static void main(String[] args) {
Employee employee = new Employee();
// Call all the setters of Class Employee
employee.setFirstName("Jack");
employee.setLastName("Reed");
employee.setBirthOfPlace("Iceland");
// Oops, forget to call setBirthday()
}
}
As far as I know, there's no silver bullet solution to what you're asking for: at some point, you will have to either add a value to needed fields in your object, or write code that checks if you did it or not.
However, if you want to try anyway, there's a decent approache to making sure the most critical fields are present when needed: constructor parameters.
public Employee(String firstName, String lastName, Date birthday) {
this.firstName = firstName;
this.lastName = lastName;
this.birthday = birthday;
}
As long as you don't implement another constructor in this class, with this code, you'll be forced to provide a first name, last name, and date for each employee, meaning they'll never not be present (unless you pass null, but avoid doing that, it's arguably bad practice). If you need all your fields to be present, you'll need that many matching parameters in your constructor.
An alternative to this is to use an embedded Builder.
Use inner Builder class inside your class with constructor with required parameter(s), e.g. firstName:
public static class Builder {
private String firstName;
private String lastName;
public Builder(String firstName) {
this.firstName= firstName;
}
public Builder lastName(String lastName) {
lastName = lastName;
return this;
}
Make sure you can create an object only through the Builder
So I am wondering what the best way to process an edit request based on a user role.
Say I have the following PostMapping:
#PostMapping(value = "/edit")
public ResponseEntity<String> editIoc(#RequestBody GeneralPojoAllFields editRequest)
the GeneralPojoAllFields looks like this:
public class GeneralPojoAllFields {
private String firstName;
private String lastName;
private String onlyAdminCanEditField;
}
This is the pojo the the admin will be able to use and that will eventually get mapped into the entity class to be saved to the database. However, if we have a regular user who wants to edit it and hypothetically they aren't restricted in the UI would that design work? What I am currently thinking is I would have a user pojo like so:
public class UserPojo {
private String firstName;
private String lastName;
}
After the request mapping comes we check if the user is either regular user or an admin. If it is a regular user we just map the GeneralPojoAllFields to the UserPojo and it wont map over the onlyAdminCanEditField and continue from there.
Is there a better way to do this?
First, your backend should be as independent of the UI as possible. So, access control in UI is a good to have design, but you should not depend upon it.
Now, coming back to your question, yes you can use SecurityContextHolder to find out if the user if regular user/admin. However, if its possible, I would suggest making two controllers, one for admin and one for regular user. Use #PreAuthorize on the admin controller to restrict access. Having two separate controllers will increase readability of your code tremendously.
Additionally, you can call the same service class method from both the controllers. And since you already have two POJO classes, you can use them in #RequestBody and let Spring take care of the mappings for you.
Well, it depends what you think a better way would be. It also depends a bit on your data source. But as there is no information on that here, I would suggest that a better way to do yours is by inheritance.
Make UserPojo the super class and GeneralPojoAllFields extend that class.
UserPojo.java:
public class UserPojo {
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 UserPojo() {}
public UserPojo(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
GeneralPojoAllFields.java:
public class GeneralPojoAllFields extends UserPojo {
private String onlyAdminCanEditField;
public String getOnlyAdminCanEditField() {
return onlyAdminCanEditField;
}
public void setOnlyAdminCanEditField(String onlyAdminCanEditField) {
this.onlyAdminCanEditField = onlyAdminCanEditField;
}
public GeneralPojoAllFields() {}
public GeneralPojoAllFields(String firstName, String lastName, String onlyAdminCanEditField) {
super(firstName, lastName);
this.onlyAdminCanEditField = onlyAdminCanEditField;
}
}
App.java:
public class App {
public static void main(String[] args) {
UserPojo up1 = new UserPojo();
up1.setFirstName("MyFirstName");
up1.setLastName("MyLastName");
GeneralPojoAllFields gpaf1 = new GeneralPojoAllFields();
gpaf1.setFirstName("MyFirstName");
gpaf1.setLastName("MyLastName");
gpaf1.setOnlyAdminCanEditField("yes");
}
}
I want to create DTO class for User. my input to program is
firstname, lastname,lastname.role,group1,group2,group3.
so for each user role consist of group_1,group_2,group_3.....
In database i want to store in following format
demo,demo,demo,roleId, gorup_1_name group_1_Id
demo,demo,demo,roleId, gorup_2 and group_2_Id
demo,demo,demo,roleId, gorup_3 and group_3_Id
I was able separate all this things , but i want to assign this value to userDTO class and stored into database. basically im new to core java part. so how can create structure for this?
A Data Transfer Object (DTO) class is a java-bean like artifact that holds the data that you want to share between layer in your SW architecture.
For your usecase, it should look more or less like this:
public class UserDTO {
String firstName;
String lastName;
List<String> groups;
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 List<String> getGroups() {
return groups;
}
public void setGroups(List<String> groups) {
this.groups = groups;
}
// Depending on your needs, you could opt for finer-grained access to the group list
}
One thing to add:
The essence of a DTO is that it transfers data across the wire. So it will need to be Serializable.
http://martinfowler.com/eaaCatalog/dataTransferObject.html
I am a novice in Java World. How to avoid confusion over variable declaration in MVC pattern over same variable?
For Example,
In Servlet (Controller):
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
In Bean (Model):
private String firstname;
private String lastname;
public Person(String FirstName, String LastName) {
setFirstName(FirstName);
setLastName(LastName);
}
//Getter and Setter Methods
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;
}
In DAO (Data Access Layer):
public void savePerson(String firstName, String lastName) {
// Method statements
}
And in JSP (View):
${person.firstname} ${person.lastname}
My Questions/Confusion?
What is the proper way of declaring same variable in different
modules(controller,models,views,dao)? And how should I avoid confusion?
Is there any conventions I have to follow while declaring variables in different
modules?
Should variables in Servlets and DAO be same? Should variables in Models/Bean
be different from Servlet and DAO?
In your servlet these would be method variables. That's pretty fine.
In your Model this works as a Model's properties. That's pretty fine, too.
In view you are actually referring to Model's properties, and not declaring any variable, whatsoever.
In DAO, you are actually, persisting your Model.
So, In Servlet/Controller this will be something more like this,
Person p = new Person();
p.setFirstName(request.getParameter("firstname"));
p.setLastName(request.getParameter("lastname"));
And in your DAO, it would be more like this,
public void savePerson(Person person) {
// Method statements
}
Hence, declaration only happens in Model. I hope it clears your confusion.
I think the variable names you have used are fine. You can name your classes based on the type of the module. So you could name your classes using names like MyApplicationController, EmployeeModel, EmployeeDAO, etc.