I've created a new project in Java using Springboot. I've followed a tutorial online to create an Entity called User which I have stored in a PostgreSQL database using Hibernate and a schema file. The User file is shown below. I'm now trying to create a Controller that will allow me to get all the data of a User from the database, but Hibernate creates another table to store the #ElementCollection. This means when I use the default queries, I get the User, but the roles column is not able to be accessed since it has stored in another table. It is stored as a jsonb. How can I get the entire User data?
User class
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private #Getter long id;
private #Getter #Setter String email;
private #Getter #Setter String encryptedPassword;
private #Getter String accessToken;
private #Getter float netWorth;
#ElementCollection
private #Getter #Setter Set<String> roles;
... (Other class functions)
}
Repository and Service class
#Repository
public interface UserRepository extends CrudRepository<User, Long> {}
#Service
public class UserService {
#Autowired // This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
private UserRepository repository;
public Optional<User> findOne(long id) {
return repository.findById(id);
}
}
Controller Class
#RestController
#RequestMapping(path="/user") // This means URL's start with /user (after Application path)
public class UserController {
#Autowired
private UserService userService;
#GetMapping(path="/get/{id}") // Map ONLY GET Requests
public ResponseEntity<User> getUser(#PathVariable("id") long id) {
// #ResponseBody means the returned String is the response, not a view name
// #RequestParam means it is a parameter from the GET or POST request
try {
Optional<User> savedUser = userService.findOne(id);
if (!savedUser.isPresent()) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "User with ID: " + id + " not found.");
}
return new ResponseEntity<>(savedUser.get(), HttpStatus.FOUND);
} catch (Exception e) {
throw new ResponseStatusException(
HttpStatus.INTERNAL_SERVER_ERROR, "Error in retrieving user.", e);
}
}
}
Related
I have developed two tables in Spring Boot, User and UserMeta. User is the parent and UserMeta is the child table. The foreign-key is user_id. I may be looking at it the wrong way, but I want to be able to first create an entity of User. Then, I want to create an entity of UserMeta. Simply UserMeta should contain additional data to User.
However, when first creating a User and then a UserMeta entity, I get e new User entity (ending up with two User entities and one UserMeta entity.)
The problem I think is that I create a UserMeta object with a User, since I want to have a relationship between User and UserMeta. But if I want to be able to first create a User and then a UserMeta, should I simply ignore a foreign-key? Or, does it exists another way of creating a UserMeta entity without creating a new User?
User
public class User {
#Id
#SequenceGenerator(name = "user_sequence", sequenceName = "user_sequence", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_sequence")
//#OneToOne(optional=false)
private Long userId;
private String username;
private String password;
private String email;
#OneToOne(mappedBy = "user")
private UserMeta userMeta;
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
}
}
UserMeta
public class UserMeta {
#Id
#SequenceGenerator(name = "user_meta_sequence", sequenceName = "user_meta_sequence", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_meta_sequence")
private Long userMeta_Id;
private String lastname;
private int age;
#OneToOne(
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
optional = false
)
#JoinColumn(
name = "user_Id",
referencedColumnName="userId"
)
private User user;
public UserMeta(String lastName, int age, User user){
this.lastname = lastName;
this.age = age;
this.user = user;
}
}
UserRepository
public interface UserRepository extends CrudRepository<User, Long> {
}
UserService
public interface UserService {
User saveUser(User user);
}
UserServiceImpl
#Service
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
super();
this.userRepository = userRepository;
}
#Override
public User saveUser(User user) {
// TODO Auto-generated method stub
return this.userRepository.save(user);
}
UserController
#RestController
public class UserController {
private UserService userService;
public UserController(UserService userService) {
super();
this.userService = userService;
}
#PostMapping("/user")
public ResponseEntity<User> saveUser(#RequestBody User user) {
return new ResponseEntity<User>(userService.saveUser(user), HttpStatus.CREATED);
}
}
UserMetaRepository
public interface UserMetaRepository extends CrudRepository<UserMeta, Long> {
}
UserMetaService
public interface UserMetaService {
UserMeta saveUserMeta(UserMeta userMeta);
}
UserMetaServiceImpl
#Service
public class UserMetaServiceImpl implements UserMetaService{
private UserMetaRepository userMetaRepo;
public UserMetaServiceImpl(UserMetaRepository userMetaRepo) {
super();
this.userMetaRepo = userMetaRepo;
}
#Override
public UserMeta saveUserMeta(UserMeta userMeta) {
return this.userMetaRepo.save(userMeta);
}
}
UserMetaController
#RestController
public class UserMetaController {
public UserMetaService userMetaService;
public UserMetaController(UserMetaService service) {
super();
this.userMetaService = service;
}
#PostMapping("/userMeta")
public ResponseEntity<UserMeta> saveUserMeta(#RequestBody UserMeta userMeta) {
return new ResponseEntity<UserMeta>(this.userMetaService.saveUserMeta(userMeta), HttpStatus.CREATED);
}
}
you should use this constructor in the User class,
public User(String username, String email, String password, UserMeta userMeta) {
this.username = username;
this.email = email;
this.password = password;
this.userMeta = userMeta;
}
now when you save your user the user Meta will be added to your UserMeta table,
If you want to add a user Meta to an existing user you will only need to set the userMeta and save it with a simple userRepository.save(theUpdatedUser)
you can also create userMeta seperately with your code above, and if you want to assign it to a user already in data base or not you can allows use the power of spring data and use simple userRepository.save(userWithTheAssignedMeta)
the same logic applies the other way for metaUser.
The problem here is that your UserMetadata creation logic is using incomplete JSON:
{ "lastName":"foo", "age":1, "user":{ "username":"foo", "password":"bar", "email":"foo-bar" } }
Within this, the problem is the 'user' has all the data, duplicating what was already created the the database, but does not identify it. Since the mapping has cascade.ALL set on it, Spring/JPA will persist the UserMetadata and find this User instance that doesn't have identity, so persist it - giving it identity from the sequence.
There are a few ways you might correct this. First and easiest is to send the User ID in the json from the previously created instance:
{ "lastName":"foo", "age":1, "user":{ "userId":1, "username":"foo", "password":"bar", "email":"foo-bar" } }
This will allow Spring/JPA to recognize the user's identity and merge it and the data provided into the database. It means though that you must send complete data for the User - it will push incomplete data into the DB.
If that is a concern, you can change the cascade options. You may not want cascading persist/merge at all on this relationship, and I suspect when you delete userMetadata you don't really want to delete the User instance, so I think this might have been done incorrectly (maybe put it on the user->UserMetadata relationship instead?). If you remove the cascade settings, spring/JPA will let you just pass in JSON with the USER id specified, as this gives it enough to set the fk:
{ "lastName":"foo", "age":1, "user":{ "userId":1} }
I have created a spring boot application. And in the application I'm working with API's. I have an POST API for creating an user, but every time I use the api, i will get the following error
Spring boot post api - org.postgresql.util.PSQLException: ERROR: null value in column "password" violates not-null constraint
Im using hibernate and PostgreSQL as database.
Even if I give de data values, i will get this error. I searched over the internet, but I cant find a solution for this problem
This is the code that i user:
Users.java:
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#Builder(toBuilder = true)
#ToString
#Table
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int user_id;
#Column(unique = true, nullable = false)
private String username;
#Column(nullable = false)
private String password;
}
UsersRepository.java
#Repository
public interface UsersRepository extends JpaRepository<Users, Integer> {}
UsersService
#Service
#RequiredArgsConstructor
#Transactional
public class UsersService {
private final UsersRepository usersRepository;
public Users createUser(Users newUsers) {
return this.usersRepository.save(newUsers);
}
}
UsersDto
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class UsersDto {
private int user_id;
private String username;
private String password;
}
UsersMapper
#Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface UsersMapper {
UsersDto toDto(Users users);
Users toModel(UsersDto usersDto);
}
UsersController
#RestController
#CrossOrigin(origins = "http://localhost:4200")
#RequiredArgsConstructor
#RequestMapping("/users")
#Validated
public class UsersController {
private final UsersService usersService;
private final UsersMapper usersMapper;
#PostMapping()
#ApiOperation(value = "Create new user", httpMethod = "POST", code = 201)
#ResponseBody
public ResponseEntity<UsersDto> createUser(#RequestBody UsersDto usersDto) throws Exception {
Users users = this.usersMapper.toModel(usersDto);
Users createUsers = this.usersService.createUser(users);
return ResponseEntity.ok(this.usersMapper.toDto(createUsers));
}
}
I hope someone can help me with this problem
The error says that the password is null, what is not allowed. So it's probably not provided on the request send to your API. You could add validation constraints to the endpoint, like
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class UsersDto {
private int user_id;
#NotNull
private String username;
#NotNull
private String password;
}
One more note, storing password as plain text is not advised , it's a major security issue. You should create and use a hash instead, check out Spring Security for this.
PS - check out bootify.io - here you can create your REST API together with the validation constraints.
I have a UserEntity object from a registration form. Here is the object:
#Entity
#Table(name = "users")
public class UserEntity {
private String name;
private String email;
private String password;
And in my controller:
#PostMapping("/register")
public void register(#RequestBody UserEntity user) {
user.save(); // how to do this?
}
Is there a simple way to save this object directly to my database? What would be the most direct way to do that above?
You can by using Repository, just need to create Repository interface.
some thing like that
public interface UserEntityRepositoryextends PagingAndSortingRepository<UserEntity ,Long>
and inject the Repository
#Autowired
UserEntityRepository userEntityRepository ;
then save
userEntityRepository.save(user)
I am doing a project for my studies using Spring, Maven, Tomcat, mySQL. I would like to create a website where users can login and update their settings and based on these settings they generate stuff.
At the moment the login is working fine and new users can be registered and saved to the database. Now I created a new entity and made a one to one reletaionship between the two tables - one is the table of the login details like password and username and the other one contains the settings of this user. The issue I am facing:
I have some textfield and combobox in the UI with vaadin - I populate the fields and click save
A binder passes these settings to a service that saves the object
It gets the currently logged in user and loads it from the database
When SQL tries to save the objects it throws error:
Caused by: java.sql.SQLException: Field 'user_login_id' doesn't have a
default value
Here are the entities:
#Entity
#Table(name = "USERLOGIN")
public class UserLogin implements UserDetails {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#OneToOne(mappedBy = "userlogin")
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
**Other getters and setters**
}
#Entity
#Table(name = "USER")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Integer id;
#Column(name = "meal")
private Integer meal;
#OneToOne
#JoinColumn(name = "userlogin_id")
private UserLogin userlogin;
public UserLogin getUserLogin() {
return userlogin;
}
public void setUserLogin(UserLogin userLogin) {
this.userlogin = userLogin;
userLogin.setUser(this);
**Other getters and setters**
}
The service that saves the settings:
#Service
public class AddUserServiceImpl implements AddUserService{
#Autowired
private UserRepository userRepository;
#Autowired
private CurrentUserService currentUserService;
public void saveUser(User userDAO) {
User user = new User();
user.setMeal(userDAO.getMeal());
user.setUserLogin(currentUserService.getCurrentUser());
userRepository.save(user);
}
}
The repository extends the JPArepository:
#Repository
public interface UserRepository extends JpaRepository<User, Integer>{
}
And finally the service and the repository that loads the currently logged in user:
#Service
public class CurrentUserServiceImpl implements CurrentUserService {
#Autowired
UserLoginRepository userLoginRepository;
public String getCurrentUsername() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
public UserLogin getCurrentUser() {
return userLoginRepository.findByUserName(getCurrentUsername());
}
}
#Repository
public interface UserLoginRepository extends JpaRepository<UserLogin,
Integer> {
#Query("select u from UserLogin u where u.username=:username")
UserLogin findByUserName( #Param("username") String username);
}
Any help would be appreciated I am really new to this topic. So the main goal is that I want to have a table that stores properties for the currently logged in user - these settings should be able to be updated any time. Is there any best practice for this?
Thank you!
I have a hibernate project that connects to two data sources and has a base dao. I use the base dao to derive generic daos for the data sources as well.
I have a service that fetches a join relationship and I am running into the following error when ever an entity has a one to many relationship. I am stuck in that I am not able to get the one to many relationship objects.
I used the apache commons beanutils to copy properties hoping it would do a deep copy but it does not work either. I am running out of ideas.
I read that I there is the option to use Open Session In View but I am not sure how to go about that.
Error
failed to lazily initialize a collection of role: com.sony.spe.mc.domain.OperationalUnit.user, could not initialize proxy - no Session
I have the following layers and files
Controller Layer
#ApiOperation(value = "read", nickname = "getByID")
#RequestMapping(value="/read", method = RequestMethod.GET)
#ApiImplicitParams({
#ApiImplicitParam(name = "id", value = "User's id", required = true, dataType = "int", paramType = "query")
})
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success", response = User.class),
#ApiResponse(code = 500, message = "Failure")})
#ResponseBody
public UserProxy getByID(long id) {
UserProxy user;
try {
user = userService.fetchUserById(id);
}
catch(Exception ex) {
ex.printStackTrace();
return null;
}
return user;
}
The Service Layer
User Service
#Service
#Transactional("fuseTransactionManager")
public class UserServiceImpl extends BaseFuseServiceImpl<User> implements UserService {
#Autowired
UserDao userDao;
#Override
protected UserDao getDao() {
return userDao;
}
#Override
public UserProxy fetchUserById(long id) {
try {
/***** ERROR HAPPENS HERE. THE USER OBJECT IS NOT ABLE TO GET THE ONE TO MANY OBJECTS even though I have #Transactional *****/
User user = userDao.fetchEntityById(User.class, id);
UserProxy userProxy = new UserProxy();
BeanUtils.copyProperties(userProxy, user);
return userProxy;
} catch(Exception ex) {
ex.printStackTrace();
return null;
}
}
.....
Generic Fuse Service
#Service
public class BaseFuseServiceImpl<T extends Serializable> extends BaseServiceImpl<T> implements BaseFuseService<T> {
#Autowired
BaseFuseDao<T> baseFuseDao;
#Override
protected BaseFuseDao<T> getDao() {
return baseFuseDao;
}
}
Very generic service that the specific services implement
#Service
#Transactional("baseTransactionManager")
public abstract class BaseServiceImpl<T extends Serializable> implements BaseService<T> {
protected abstract BaseDao<T> getDao();
#Override
public T fetchEntityById(Class<T> entityClass, long id) {
return getDao().fetchEntityById(entityClass, id);
}
User Entity. There is also a corresponding proxy object that is pretty much identical except it does not have the #Entity #Column annotations.
#Entity
#Table(name="USER")
//#AttributeOverride(name = "ID", column = #Column(name = "USER_ID", nullable = false))
public class User extends BaseEntity {
//public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 5236507646361562577L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "USER_ID")
private long id;
#OneToMany(cascade=CascadeType.ALL)
#JoinTable(name="USER_OPERATIONALUNIT",
joinColumns = {#JoinColumn(name="USER_ID")},
inverseJoinColumns = {#JoinColumn(name="OPERATIONALUNIT_ID")}
)
private Set<OperationalUnit> operationalUnit;
.... getters and setters
Why you want make all the methods #Transactional inside class. You can use #Transactional whenever it requires. For best practices use #Transactional over the method.
So in Your case there are 2 solutions:
1.By Fetching childs eagerly:
You need to pass fetchType Eagerly with your annotation i.e.
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
2. By using #Transactional:
Here you need to initialize you collection in current transaction i.e.
public UserProxy fetchUserById(long id) {
try {
User user = userDao.fetchEntityById(User.class, id);
// Here you need to initialize collection using getter method after retrieving object
user.getOperationalUnit().size();
//Now you will get childs with your parent entity
UserProxy userProxy = new UserProxy();
BeanUtils.copyProperties(userProxy, user);
return userProxy;
} catch(Exception ex) {
ex.printStackTrace();
return null;
}
}
For more details about #Transactional Refer this link.