Let's say I have a User class (with properties like name, last name, etc.) and a UserService class that is used to query the database and get User data. Let's say I have the following method in my UserService class:
public User getUser(int userId)
{
User user = new User();
/* query database and returns user data. Then I use setters to set User data
...........
*/
return user;
}
I have the following controller class:
public class DIGRCController {
private User user;
private UserService service;
//getters and setters
#PostConstruct
public void init() {
service = new UserService();
//imagine userId is coming from somewhere (not relevant to this question)
user = service.getUser(userId);
}
}
My question is:
Is user = service.getUser(userId) good practice?
user has one object reference and then I am pointing it to another reference. Is this ok in programming? If not, what should I do?
I checked a few questions in SO but couldn't find one with what I am looking for. If you have a SO question I could look at, please show me.
Related
Hello everyone and thank you in advance for looking at this question. I am using a Couchbase Server community-6.6.0 on Java Spring Boot (Java JDK version 1.8).
Problem Description: To interact with Couchbase I am using a PagingAndSortingRepository Repository. Each time I call .save() a new document representing a new instance of the Object I am using gets created in Couchbase. Also, when I retrieve an Object from Couchbase change the value of some field e.g., .setPassword() and then call .save() to make the change persistent then I get a new document (with a new Id) of that Object is created in Couchbase. It seems to me that many different revisions of that Object exist in the Database when I call .save(), I want to make sure that I am always working on the latest version of that instance of my Object/Entity.
I am really confused! What I am trying to do should be straightforward, every time I update a Java Entity I want the changes to be made persistent for that Document (with that Document id) in Couchbase. Perhaps I am missing something here. Please advice.
Partial view of the pom looks like:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-couchbase</artifactId>
</dependency>
Entities as follows:
#Data
#Document
#CompositeQueryIndex(fields = {"id", "userName"})
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#IdPrefix
private String prefix;
#Id #NotNull #GeneratedValue( delimiter = "::", strategy = GenerationStrategy.UNIQUE)
private String id;
#Field
#NotNull
#Size(min=2, max=40)
private String firstname;
#Field
#NotNull
#QueryIndexed
private String username;
//Other attributes here ...
}
//ConfirmationToken Entity
#Data
#NoArgsConstructor
#CompositeQueryIndex(fields = {"id", "confirmationToken"})
public class ConfirmationToken {
#IdPrefix
private String prefix = "token";
#Id #NotNull #GeneratedValue(delimiter = "::", strategy = GenerationStrategy.UNIQUE)
private String id;
#Field
#Reference
private User user;
#Field
#QueryIndexed
private String confirmationToken;
//Other attributes here ...
}
UserRepository looks like:
#Repository
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
#ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
List<User> findByUsername(String username);
}
#Service
#AllArgsConstructor
public class ConfirmationTokenServiceImpl implements ConfirmationTokenService {
#Autowired
private final ConfirmationTokenRepository confirmationTokenRepository;
#Override
public void saveConfirmationToken(ConfirmationToken confirmToken) {
confirmationTokenRepository.save(confirmToken);
}
}//end class
When I want to retrieve the User Object from Couchbase I do the following:
//How do I ensure this Object is the latest version of that document?
List<User> users = userRepository.findByUsername(username);
//The following does not ensure that I get the latest version of that User document with that username
User testUser = users.get(users.size()-1);
In some method I change field values of that Java Object i.e., User and then a new revision of that User Document gets created in the Database when I call .save(User Object). How do I update the fields of that User object and make that Document persistent in the Database without creating a new revision of that Document? Also, how do I ensure I always get and work on the latest version of that User Document?
public void someMethod(UserDTO regForm, final String contextPath) {
User testUser = new User();
testUser.setFirstname(regForm.getFname());
testUser.setLastname(regForm.getSname());
//Make User persistent
userRepository.save(testUser);
//Create the confirmation token for that User instance
final ConfirmationToken confirmToken = new ConfirmationToken(testUser);
confirmationTokenService.saveConfirmationToken(confirmToken);
}
In this Method I have another Class called ConfirmationToken that has a reference to a User Object. This is to associate each ConfirmationToken instance with a specific User Instance. When I call the following method to change the User password a new document with a new id is created for the User in the Database. I cannot understand how to update the current instance. Please help.
public void changeUserPassword(ConfirmationToken confirmToken, ResetPassDTO resetPassForm) {
//Retrieve the User instance that is associated with that Token
final User testUser = confirmToken.getUser();
if (testUser.getEmail().equals(resetPassForm.getEmail())) {
//Get the Hash of the User's password
final String encryptedPassword = bCryptPasswordEncoder.encode(resetPassForm.getNewPassword());
testUser.setPassword(encryptedPassword);
//Enable the user account - since email ownership is also verified
testUser.setIsEnabled(true);
userRepository.save(testUser);
}
//Delete the Confirmation Token entity
confirmationTokenService.deleteConfirmationToken(confirmToken);
}
Update:
It seems that I had to go back and work on my domain modelling for the Entities. More specifically to think of how couchbase is doing docs embedding and when to do referencing. In my example, the ConfirmationToken instance holds a reference to a User instance. In reality the ConfirmationToken embeds the User instance in the same JSON doc. I cannot access the actual User object I want though. In other words, it seems that I cannot dereference and get the User instance by following the id of User object from the ConfirmationToken instance. My solution: I introduced a uuid field in the User object, I then get the reference for a User instance from ConfirmationToken, then I call userRepository.findByUuid(userFromToken.getUuid()); only then I was able to get the actual User object that I wanted. My question is why Couchbase spring SDK cannot do this dereferencing automatically? Also, it seems that when I change the value of some attribute the change does not happen on the actual object but on the embedding, so every time I need to do this dereferencing to get to the real object manually. This is similar to MongoDB #DBRefs?? Not sure how if there is a solution with N1QL though and NEST queries? Can I achieve this with N1QL?
I have User class like this :
#Data
#Entity
public class User {
#Id #GeneratedValue Long userID;
String eMail;
String passwordHash;
}
And I have data like this :
[{"userID":1,"passwordHash":"asdasd","email":"admin#admin.com"},
{"userID":2,"passwordHash":"12345","email":"admin1asdasd#admin.com"}]
I have two method in my controller class, one - to get single user :
#GetMapping("/user/{id}")
User one(#PathVariable Long id) {
return repository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
Other method to retrieve all user :
#GetMapping("/user")
List<User> all() {
return repository.findAll();
}
In my browser, going to this address - http://localhost:8080/user , I can see these data. And if I goto http://localhost:8080/user/id I can get a specific value.
Now my question is how can access data like http://localhost:8080/user/email/passwordHash? I am quite sure that it is not possible, because I haven't stored data in that way.
As my main target is to verify login, I have already written a #Query in my repository interface. Here it is :
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select u from User u where u.eMail = ?1 and u.passwordHash = ?2")
List<User> listByLoginCredential(String emailAddress,String passwordHash);
}
Can Anyone tell me how can I do this,use this method of this interface?
I think you can can achieve what you want by adding the following method to the controller class:
#GetMapping("/user/{emailAddress}/{passwordHash}")
List<User> byMailAndPassword(#PathVariable String emailAddress, #PathVariable String passwordHash) {
return repository.listByLoginCredential(emailAddress, passwordHash)
}
On the other hand you say that your main goal is to verify login, so it looks like you are doing authentication. If you have time you should look into doing it with spring security https://spring.io/guides/gs/securing-web/#initial
Maybe this help https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.
Or you can also create procedure in Database and call stored procedure with Spring boot.
Login is related to security so ideally you should create a separate post method and use the repository method. Always make sure to follow the best practice.
Spring security is something you can utilize for better authentication and authorization.
Heads Up: It is my first post here, please excuse any missing information or the really novice questions.
So I am currently trying to write jUnit tests for the already finished web application that uses spring (everything works, I just have to get full coverage with the tests).
I have the classes: "Employee", "EmployeeController" and "EmployeeManagement".
I want to test the "registerNew" function which creates a new Employee with the filled form "EmployeeRegistrationForm" if it has no errors ("Errors result").
Now I want to write a Test for this to make sure that the function really does create a new object "Employee" which should be saved in the "EmployeeRepository" with said form.
However, I cannot seem to be able to create a filled "EmployeeForm" since it is abstract and cannot be instantiated. Therefore I am struggling to give any argument to that function and do not know how to pass the information needed for the test to function being tested.
#Service
#Transactional
public class EmployeeManagement {
private final EmployeeRepository employees;
private final UserAccountManager userAccounts;
EmployeeManagement(EmployeeRepository employees, UserAccountManager userAccounts) {
Assert.notNull(employees, "employeeRepository must not be null!");
Assert.notNull(userAccounts, "UserAccountManager must not be null!");
this.employees=employees;
this.userAccounts = userAccounts;
}
//the function that creates the employee
public Employee createEmployee(EmployeeRegistrationForm form) {
Assert.notNull(form, "Registration form must not be null!");
String type = form.getType();
Role role = this.setRole(type);
UserAccount useraccount = userAccounts.create(form.getUsername(), form.getPassword(), role);
useraccount.setFirstname(form.getFirstname());
useraccount.setLastname(form.getLastname());
return employees.save(new Employee(form.getNumber(), form.getAddress(), useraccount));
}
#Controller
public class EmployeeController {
private final EmployeeManagement employeeManagement;
EmployeeController(EmployeeManagement employeeManagement) {
Assert.notNull(employeeManagement, "userManagement must not be null!");
this.employeeManagement = employeeManagement;
}
#PostMapping("/registerEmployee")
#PreAuthorize("hasRole('ROLE_ADMIN')")
String registerNew(#Valid EmployeeRegistrationForm form, Errors result) {
if (result.hasErrors()) {
return "registerEmployee";
}
employeeManagement.createEmployee(form);
return "redirect:/";
}
public interface EmployeeRegistrationForm {
#NotEmpty(message = "{RegistrationForm.firstname.NotEmpty}")
String getFirstname();
#NotEmpty(message = "{RegistrationForm.lastname.NotEmpty}")
String getLastname();
#NotEmpty(message = "{RegistrationForm.password.NotEmpty}")
String getPassword();
#NotEmpty(message = "{RegistrationForm.address.NotEmpty}")
String getAddress();
#NotEmpty(message = "{RegistrationForm.number.NotEmpty}")
String getNumber();
#NotEmpty(message = "{RegistrationForm.type.NotEmpty}")
String getType();
#NotEmpty(message = "{RegistrationForm.username.NotEmpty}")
String getUsername();
}
However, I cannot seem to be able to create a filled "EmployeeForm" since it is abstract and cannot be instantiated.
Use Mockito to instantiate your abstract classes.
You can use it like this:
EmployeeForm form = mock(EmployeeForm.class);
Now you have an instance of EmployeeForm which you can pass to your methods. If you need to call some methods from your mock you can do somethifg like this:
given(form.getFirstname()).willReturn("John");
This way the form will behave the way you want.
Note: mock() comes from org.mockito.Mockito and given comes from org.mockito.BDDMockito.
I am tring to implement logging of users in Spring Security on the basis of a popular Tutorial and have a doubt about how spring beans are wired.
The below class is defined as a standard bean in the Spring Context
public class ActiveUserStore {
public List<String> users;
public ActiveUserStore() {
users = new ArrayList<String>();
}
public List<String> getUsers() {
return users;
}
public void setUsers(List<String> users) {
this.users = users;
}
}
The above is defined as a Bean through
#Bean
public ActiveUserStore activeUserStore(){
return new ActiveUserStore();
}
And the Bean is being used in the below class, please note the users.add(user.getUsername());
#Component
public class LoggedUser implements HttpSessionBindingListener {
private String username;
private ActiveUserStore activeUserStore;
public LoggedUser(String username, ActiveUserStore activeUserStore) {
this.username = username;
this.activeUserStore = activeUserStore;
}
public LoggedUser() {}
#Override
public void valueBound(HttpSessionBindingEvent event) {
List<String> users = activeUserStore.getUsers();
LoggedUser user = (LoggedUser) event.getValue();
if (!users.contains(user.getUsername())) {
users.add(user.getUsername());//HOW IS THIS SAVED TO THE ACTIVEUSERSTORE BEAN
}
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
List<String> users = activeUserStore.getUsers();
LoggedUser user = (LoggedUser) event.getValue();
if (users.contains(user.getUsername())) {
users.remove(user.getUsername());//HOW IS THIS SAVED TO THE ACTIVEUSERSTORE BEAN
}
}
My Question: Since users variable belongs to the ActiveUserStore Bean, how does the following line of code inside the valueBound and valueUnbound methods of Logged User Class, automatically save the ussers data inside the ActiveUserStore Bean ?
users.add(user.getUsername());
I have also marked this line in the code snipped above for clarity.
Any help is appreciated, since I think my understanding of how Beans are wired and used is probably not clear since I am not able to understand the above working. Thanks.
Think about Spring Bean as usual Java class. This class instantiated by Spring at application start just once (actually this is not always true, but by default it is)
Now you inside of your bean, you have reference to List variable and get it with:
List<String> users = activeUserStore.getUsers();
Now users variable contains reference to the List stored in bean. This is because in Java objects are passed by reference.
LoggedUser user = (LoggedUser) event.getValue();
if (!users.contains(user.getUsername())) {
and here users variable contains List class reference. List class have method add, and LoggedUser have getUsername method. As users variable refers to same List object as your bean property contain, this adds username to your bean:
users.add(user.getUsername());
}
So i have a simple UsersDao
public interface UserDao extends JpaRepository<User, Long> {
}
And inside my user controller i want to do something like this :
#RequestMapping(value = "/register",method = RequestMethod.POST)
public void addUser(#RequestBody User user) {
//How do i check if user already exist with email instead of id
// i managed to do this but can i search on something else than the id
User user1 = userDao.findOne(1);
if (user.getEmail().equals(user1.getEmail()))
{
// And how should i give one error to the front end if the email
//already exist I'm using angular js
}
else {
userDao.save(user);
}
}
I also have some extra questions on this topic:
Somethings that are not clear are following. I have done a small tutorial on jpa but there they use:
EntityManager,
EntityTransaction
Note : when using EntityManagerFactory it goes as follow :
EntityManagerFactory emf = null,
//Then they use EntityManagerFactory
emf = Persistence.createEntityManagerFactory("SomeValue")
//where can i get "someValue" When using application .properties
//because in the example they use xml but can't find the right properties in application.properties
Or do i not need to use these in springboot
Sorry for all these question. I really want to get into spring but somethings are still a bit unclear at this point ;)
You can do the following:
Assuming User has an attribute email, define a method in the interface like this to generate a dynamic query:
public interface UserDao extends JpaRepository<User, Long> {
public User findByEmail(String email);
}
Then you can find a user by email. If null is returned, no user with the given email exists. Also, within the User entity class, you can define an annotation to ensure that email is unique like this:
public class User {
....
#Column(unique=true)
String email;
}
You have 2 options:
Use method User findByEmail(String email); in repository interface.
Use method like
#Query("SELECT COUNT(u.id) FROM User u WHERE u.email=:email) Long
countUsersWithEmail(String email);
Than it's obvious how to use rusults of these queries. I would use 2nd choice because of smaller overhead.
this can actually be done in two different ways. although #ufuoma's solution is valid, spring has the exists and Optional which are more flexible. i will give code examples of each.
in the repository interface, we will have these methods
boolean existsByEmail(String email);
Optional<User> findByEmail(String email);
then in your Service class we will have
public Optional<User> findByEmail(String email){
return baseUserRepository.findByEmail(email);
}
public boolean exist(String email){
return baseUserRepository.existsByEmail(email);
}
then in the controller class, we will have
if(baseUserSevice.exists==true){
return "User already exist";
}
or
Optional<baseUserEntity> user=baseUserService.findByEmail(user.getEmail);
if(user.isPresent()){
return "user already exists";
}
the exist method is most preferred since it's faster
you can use any combination with exists keyword
public interface UserDao extends JpaRepository<User, Long> {
public boolean existsByEmail(String email);
}