Hibernate exception - hibernate.internal.QueryImpl cannot be cast - spring

I'm trying to authenticate with a database username. So far the error is:
Your login attempt was not successful, try again.
Reason: org.hibernate.internal.QueryImpl cannot be cast to com.**.**.model.UserEntity
The query in the dao class
#Repository
public class UserEntityDAOImpl implements UserEntityDAO{
#Autowired
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getCurrentSession() {
return this.sessionFactory.getCurrentSession();
}
#Override
public UserEntity getUserByName(String username) {
// TODO Auto-generated method stub
UserEntity userEntity = (UserEntity)
sessionFactory.getCurrentSession().createQuery(
"select u from UserEntity u where u.username = '' + username + ''");
return userEntity;
}
service
#Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService{
#Autowired
private UserEntityDAO userEntityDAO;
#Autowired
private Assembler assembler;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
// TODO Auto-generated method stub
UserDetails userDetails = null;
UserEntity userEntity = userEntityDAO.getUserByName(username);
if (userEntity == null)
throw new UsernameNotFoundException("user not found");
return assembler.buildUserFromUser(userEntity);
}
}
DB table that holds the user details
/*Table structure for table `user` */
CREATE TABLE `user` (
`user_id` INT(11) NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(45) NULL DEFAULT NULL ,
`password` VARCHAR(45) NOT NULL ,
`username` VARCHAR(45) NOT NULL ,
`active` TINYINT(1) NOT NULL ,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
Model
#Entity
#Table(name = "user", schema = "")
#Component
public class UserEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "user_id")
private Integer id;
#Column(name = "name")
private String name;
#Basic(optional = false)
#Column(name = "password")
private String password;
#Basic(optional = false)
#Column(name = "username")
private String username;
#Basic(optional = false)
#Column(name = "active")
private boolean active;
#JoinTable(name = "user_role", joinColumns = {
#JoinColumn(name = "user_id")}, inverseJoinColumns = {
#JoinColumn(name = "role_id")})
#OneToMany
private Set <Role> roles;
public UserEntity() {
}
//getters and setters
What I would like insight on is why there is a problem with the query, and why the username is not able to be retrieved from the database.
Edit: After changing the query, the login is still not successful. The login page is returned and there is no error message in the output console other than this:
Hibernate: select userentity0_.user_id as user1_1_, userentity0_.active as
active1_, userentity0_.name as name1_, userentity0_.password as password1_,
userentity0_.username as username1_ from user userentity0_ where
userentity0_.username=?
Hibernate: select roles0_.user_id as user1_1_1_, roles0_.role_id as role2_2_1_,
role1_.role_id as role1_0_0_, role1_.role as role0_0_ from user_role roles0_ inner
join role role1_ on roles0_.role_id=role1_.role_id where roles0_.user_id=?
INFO : com.**.**.controller.ApplicationController - This is the login page {}.

You forgot to execute the query you created. It should be:
sessionFactory.getCurrentSession().createQuery(...).uniqueResult();
Also, use a proper bind variable. As it stands your query is bogus with single quotes, I'm not sure if you made a typo pasting it into stackoverflow, but something like this would be much safer:
sessionFactory
.getCurrentSession()
.createQuery("select u from UserEntity u where u.username = :username")
.setParameter("username", username)
.uniqueResult();

Related

JPA lazy initialization error with #OneToMany #EmbeddedId

In Sprinboot/JPA I defined an entity with one-to-may association as follows:
#Entity
#Table(name = "useraccount", catalog = "useraccount")
public class UserAccount implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//other stuff...
#OneToMany(mappedBy ="tokenId.user", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.REFRESH}, orphanRemoval =true, fetch=FetchType.LAZY)
private Set<SecureToken> tokens = new HashSet<>();
public Set<SecureToken> getTokens()
{
return this.tokens;
}
//other getter and setter
}
The SecureToken entity:
#Entity
#Table(name = "secureToken", catalog = "useraccount")
public class SecureToken implements Serializable
{
#EmbeddedId
public SecureTokenId tokenId= new SecureTokenId();
#Column(unique = true)
private String token;
private Timestamp isConsumed;
#CreationTimestamp
#Column(updatable = false)
private Timestamp timestamp;
#Column(updatable = false)
#Basic(optional = false)
private Timestamp expireAt;
#MapsId("user_id")
#JoinColumn(name = "user_id", referencedColumnName ="id")
#ManyToOne
private UserAccount user;
public SecureToken(UserAccount user, String token, String tokenType, Timestamp timestamp, Timestamp expire)
{
super();
this.token=token;
this.tokenId.setTokenType(tokenType);
this.tokenId.setUser(user);
this.timestamp=timestamp;
this.expireAt=expire;
this.isExpired=false;
}
}
The SecureTokenId:
#Embeddable
public class SecureTokenId implements Serializable
{
#Column(name="tokenType")
private String tokenType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private UserAccount user;
public SecureTokenId()
{
super();
}
public SecureTokenId(String tokenType)
{
//this.user_id=user_id;
this.tokenType=tokenType;
}
#Override
public boolean equals(Object o)
{
if (o == null || getClass() != o.getClass())
return false;
SecureTokenId that = (SecureTokenId) o;
return Objects.equals(this.tokenType, that.tokenType) &&
Objects.equals(this.user.getId(), that.user.getId());
}
#Override
public int hashCode() {
return Objects.hash(tokenType, this.user.getId());
}
public void setTokenType(String tokenType)
{
this.tokenType=tokenType;
}
public String getTokenType()
{
return this.tokenType;
}
public void setUser(UserAccount user)
{
this.user=user;
}
public UserAccount getUser()
{
return this.user;
}
public Long getTokenId()
{
return this.user.getId();
}
}
But calling the method getToken() of entity UserAccount gets the famous "LazyInitializationException". I generally use Hibernate.initialize, but with this configuration I cannot get rid of the problem.
This how I create a token within a #Service annoted SecureTokenService class.
#Override
#Transactional
public SecureToken generateToken(UserAccount user, String tokenType)
{
byte[] random = new byte[64];
new SecureRandom().nextBytes(random);
Timestamp timestamp = java.sql.Timestamp.valueOf(LocalDateTime.now());
LocalDateTime expire= LocalDateTime.now().plusHours(12);
SecureToken token = new SecureToken(new SecureTokenId(user, tokenType),Base64.encodeBase64URLSafeString(random),
timestamp, Timestamp.valueOf(expire));
return token;
}
Then in the UserService class (#Service annotated) I try to create a token:
SecureToken token = secureTokenService.generateToken(user, type);
secureTokenService.save(token);
user.addSecureToken(token); //Error
this.save(user)
When I try to associate the token with the user the error is thrown. Without that statement, the application seems working but even with "spring.jpa.open-in-view = false" in application.properties calling user.getTokens() rises the lazy initialization error.
In parent child relationship, you didn't declare any parent reference from child side.
In the parent side (UserAccount), you declared as follows
#OneToMany(mappedBy ="user"....
Which means your child side (SecureToken) there is no such property named user.
To get rid of this situation,
First you need to declare user inside of SecureToken / SecureTokenId. From your definition, you declared user_id inside SecureTokenId, instead declare user inside SecureTokenId.
...
public class SecureTokenId ... {
...
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private UserAccount user;
...
}
Then in the UserAccount declare the #OneToMany as follows
#OneToMany(mappedBy ="tokenId.user"...
private Set<SecureToken> tokens;

Why can’t I insert an entity twice by using Spring Data Jdbc?

my entity:
#Table("user")
public class User {
#Id
private Long user_id;
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public User() {
}
public Long getUser_id() {
return user_id;
}
public void setUser_id(Long user_id) {
this.user_id = user_id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
my repository:
public interface UserRepository extends CrudRepository<User, Long> {
#Query("select * from user where username = :username")
User findByUsername(#Param("username") String username);
}
my sql for creating the user table:
CREATE TABLE `user` (
`user_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL,
`password` text NOT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `UINQUE_USERNAME`(`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
User userForRegister = new User(username, passwordEncoder.encode(password));
userRepository.save(userForRegister)
If I execute the line of 'userRepository.save(userForRegister)', I will insert an entity successfully the first time.
But, if I want to insert another user entity with different username, i will get an error:
2021-01-08 21:37:38.242 INFO 11180 --- [nio-8080-exec-8] c.k.centre.controller.UserController : Failed to execute DbAction.InsertRoot(entity=com.***.***.Entity.User#65bc9ea1, generatedId=null)
I can insert it until I delete all the data of user table.
Is there any point I missed?
I think that GenerateValue would solve the problem
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long user_id;
Also I think you should map your ther fields to database columns using #Column annotation
#Column(name = "user_id")
private Long user_id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
Try adding #GeneratedValue(strategy = GenerationType.IDENTITY) to your user_id. This tells Hibernate that id is generated by your database. You configured your database primary key as autoincrement Column. Take also a look here.

Spring boot Rest create a category which can reference to another category or not

I have an entity class
public class CategoryEntity implements Serializable {
#Getter(AccessLevel.NONE)
#Setter(AccessLevel.NONE)
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
#Column(length = 30, nullable = false)
private String categoryKeyId;
#Column(nullable = false)
private String name;
//Here mappedBy indicates that the owner is in the other side
#OneToMany(fetch = FetchType.EAGER, mappedBy = "category", cascade = CascadeType.ALL)
private List<ProductEntity> products;
#ManyToOne(optional = true, fetch = FetchType.LAZY)
private CategoryEntity parent;
// allow to delete also subcategories
#OneToMany(mappedBy="parent", cascade = CascadeType.ALL)
private List<CategoryEntity> subCategories;
}
this class generates this SQL code :
CREATE TABLE `categories` (
`id` bigint(20) NOT NULL,
`category_key_id` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`parent_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FKsaok720gsu4u2wrgbk10b5n8d` (`parent_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
So far, so good it's perfectly what i'm expecting. My issue concerns how to create a new category.
My DTO layer is :
#Getter #Setter
public class CategoryDto implements Serializable {
#Getter(AccessLevel.NONE)
#Setter(AccessLevel.NONE)
private static final long serialVersionUID = 1L;
private long id;
private int parentCategoryId;
private String categoryKeyId;
private String name;
private List<CategoryDto> subCategories;
private CategoryDto parentCategory;
}
I also created 2 Rest Model for creating categories one for the request and the other for the response.
I need to provide a json as entry with the name and the parent category id:
#Getter #Setter
public class CategoryCreateRequestModel {
private String name;
private int parentCategory;
}
And i retrieve a json as output :
#Getter #Setter
public class CategoryCreateRest {
private String categoryKeyId;
private String name;
private CategoryCreateRest parentCategory;
}
My createCategory method returns the output result i expect and takes a CategoryCreateRequestModel as input.
#PostMapping(
consumes = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE },
produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }
)
public CategoryCreateRest createCategory(#RequestBody CategoryCreateRequestModel categoryCreateRest) throws Exception {
CategoryCreateRest returnValue = new CategoryCreateRest();
if( categoryCreateRest.getName().isEmpty())
throw new NullPointerException(ErrorMessages.MISSING_REQUIRED_FIELDS.getErrorMessage());
ModelMapper modelMapper = new ModelMapper();
CategoryDto categoryDto = modelMapper.map(categoryCreateRest, CategoryDto.class);
CategoryDto createdCategory = categoryService.createCategory(categoryDto);
returnValue = modelMapper.map(createdCategory, CategoryCreateRest.class);
return returnValue;
}
My service layer :
#Override
public CategoryDto createCategory(CategoryDto categoryDto) {
// check if category name and parentId are identicals
if (categoryRepository.findByName(categoryDto.getName()) != null)
throw new ApplicationServiceException("Record already in Database");
ModelMapper modelMapper = new ModelMapper();
CategoryEntity categoryEntity = modelMapper.map(categoryDto, CategoryEntity.class);
// generate categoryKeyId
String categoryKeyId = utils.generateCategoryKeyId(30);
categoryEntity.setCategoryKeyId(categoryKeyId);
CategoryEntity storedCategory = categoryRepository.save(categoryEntity);
CategoryDto returnValue = modelMapper.map(storedCategory, CategoryDto.class);
return returnValue;
}
When i set a new category for example:
{
"name": "catName",
"parentCategoryId": 12
}
or
{
"name": "catName",
"parentCategoryId": null
}
I obtain a 500 error message : could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"
Apparently I have issues with the primary key and I don't see what is going wrong. I should not need to pass an id to this json because it should be automatically generated.

Spring Security Set Role On Registration

I'm new to Spring security, so I've followed some tutorials but I'm having trouble understanding how the structure of roles really works under the hood. I have two tables, one for the User:
#Entity
#Table(name = "UserProfile", schema = "dbo", catalog = "DevTestTeam")
public class UserProfileEntity implements UserDetails{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private long id;
#Column(name = "enabled", nullable = false)
private boolean enabled;
#NotEmpty(message = "Enter a password.")
#Size(min = 6, max = 15, message = "Password must be between 6 and 15 characters.")
#Column(name = "password", nullable = true, length = 100)
private String password;
#NotEmpty(message = "Enter a username.")
#Size(min = 6, max = 20, message = "Username must be between 6 and 20 characters.")
#Column(name = "username", nullable = true, length = 20, unique = true)
private String username;
#OneToOne
#JoinColumn(name = "role_id")
private RoleEntity role;
public RoleEntity getRole() {
return role;
}
public void setRole(RoleEntity role) {
this.role = role;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return authorities;
}
and one for the role:
#Entity
#Table(name = "Role", schema = "dbo", catalog = "DevTestTeam")
public class RoleEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private long id;
#Column(name = "name", nullable = true, length = 255)
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
My confusion comes when creating a new user. I have a registration form backed by a UserProfileEntity object, and that populates the username and password. Then obviously it's easy to setEnabled()=true (I left some of the getters/setters out of this code for clarity).
My question is how to set the role when instantiating a UserProfileEntity to be saved in the database. My role_id foreign key should just take an integer and return the role from the Role table, but I'm not sure how to express this when instantiating. I have a ROLE_USER in the roles table with an id of 1, and I feel like this is pretty simple to instantiate but I can't find the answer I'm looking for.
UserImpl:
#Service
public class UserProfileServiceImpl implements UserProfileService{
#Autowired
private UserProfileDao userDao;
#Override
public UserProfileEntity findByUser(String username) {
return userDao.findByUsername(username);
}
#Override
public List<UserProfileEntity> findAll() {
List<UserProfileEntity> list = userDao.findAll();
return list;
}
#Override
public UserProfileEntity save(UserProfileEntity persisted) {
userDao.save(persisted);
return null;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserProfileEntity user = userDao.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found.");
}
return user;
}
}
You'll need some repository method to obtain user role by name:
RoleEntity roleEntity = roleEntityRepository.findByName("ROLE_USER");
Then set that RoleEntity to UserProfileEntity before persisting it:
UserProfileEntity userProfileEntity = new UserProfileEntity();
userProfileEntity.setRoleEntity(roleEntity);
userService.save(userProfileEntity);
What you also want is to leave your UserProfileEntity unextended. For Spring Security, you'll need UserDetailsService implementation:
#Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserProfileEntity userProfileEntity = userRepository.findByUsername(username);
if (userProfileEntity == null) {
throw new UsernameNotFoundException("Non existing user!");
}
return new org.springframework.security.core.userdetails.User(userProfileEntity.getUsername(),
userProfileEntity.getPassword(),
Arrays.asList(new SimpleGrantedAuthority(userByUsername.getRoleEntity().getName())));
}
}
However, I see that your requirements are quite simple - one role per user. Therefore, your RoleEntity could simply be an enum with predefined roles:
public enum RoleEntity {
ROLE_USER
}
And in UserProfileEntity you'd use it like this:
public class UserProfileEntity {
#Enumerated(EnumType.STRING)
private RoleEntity roleEntity;
}
To persist user with role:
UserProfileEntity userProfileEntity = new UserProfileEntity();
userProfileEntity.setRoleEntity(RoleEntity.USER);
userService.save(userProfileEntity);

I can't get a row from a database in hibernate with sessionFactory.getCurrentSession().load (...)

I have a database (in postgres) and I'm working with spring 3 and hibernate 3, the problem is when try to delete or get a row from database, here is the class that I'm using, ohh another thing after the query, a don't have any mistake, the only thing es that class User is null
#Repository("userDao")
public class UserDao implements IUserDao {
#Autowired
private SessionFactory sessionFactory;
public void SaveUser(User user) {
sessionFactory.getCurrentSession().save(user);
}
#SuppressWarnings("unchecked")
public List<User> ListUsers() {
List<User> users = (List<User>) sessionFactory.getCurrentSession().createCriteria(User.class).list();
return users;
}
public User GetUserById(Integer id) {
User user = (User) sessionFactory.getCurrentSession().load(User.class, id);
return user;
}
}
by the way, methods, SaveUser and ListUser work really good.
this is the model class
#Entity
#Table(name = "mrbean")
public class User {
#Id
#GeneratedValue (strategy = GenerationType.AUTO)
#Column (name = "id")
private Integer id;
#NotNull (message = "not null")
#NotEmpty (message = "empty")
#Column (name = "user_name", length = 20, nullable = false, unique = true)
private String userName;
#NotNull
#NotEmpty (message = "empty password")
#Size (min = 7, max = 20, message = "La contraseña debe tener entre 7 y 20 caracteres")
#Column (name = "password", length = 20, nullable = false)
private String password;
//with getters and setters
this is what hibernate show in console when
User user = (User)sessionFactory.getCurrentSession().load(User.class, id) is executed
Hibernate: select user0_.id as id0_0_, user0_.password as password0_0_, user0_.user_name as user3_0_0_ from mrbean user0_ where user0_.id=?
I would use "get" instead of "load" because load() creates a proxy of User (see Hibernate ref doc )
so i would try : User user = (User) sessionFactory.getCurrentSession().get(User.class, id);

Resources