i want to retrieve data with DTO Projection using sprind data jpa, but unfortunately when i call the method an error has occurred :
[2020-05-28 21:02:03] Unable to locate appropriate constructor on class [com.burgerbuilder.backend.DTO.Response.UserResponse]. Expected arguments are: java.util.UUID, java.lang.String , java.lang.String , java.lang.String , java.util.Collection
[select new com.burgerbuilder.backend.DTO.Response.UserResponse(u.id,u.email,u.name,u.lastName,u.authorities) from com.burgerbuilder.backend.Model.User u where u.id=:id]
my repository :
#Repository
public interface UserRepository extends JpaRepository<User, UUID> {
#Query("select new com.burgerbuilder.backend.DTO.Response.UserResponse(u.id,u.email,u.name,u.lastName,u.authorities) from User u where u.id=:id")
Optional<UserResponse> findUserById(#Param("id") String id);}
User class:
#Entity
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Type(type=”uuid-char”)
private UUID id;
#NotNull
private String email;
#NotNull
private String password;
private String name;
private String lastName;
private String phoneNumber;
private String emailVerificationToken;
private boolean isEmailVerified=false;
private boolean isPhoneNumberVerified=false;
#OneToMany(mappedBy = “user”,cascade = CascadeType.ALL)
private List<Authority> authorities=new ArrayList();
DTO Class :
public class UserResponse {
private String userId;
private String email;
private String name;
private String lastName;
private List<Authority> authorities=new ArrayList<>();
public UserResponse(UUID userId, String email, String name, String lastName, List<Authority> authorities) {
this.userId = userId.toString();
this.email = email;
this.name = name;
this.lastName = lastName;
this.authorities=authorities;
}
}
can someone help me please ?
Related
I created an entity class :
#Entity
#Table(name="users")
#Getter #Setter
public class UserModel implements Serializable {
#Setter(AccessLevel.NONE)
#Getter(AccessLevel.NONE)
private static final long serialVersionUID = -5608230793232883579L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(nullable = false, unique = true)
private String userId;
#Column(nullable = false, length = 50)
private String firstName;
#Column(nullable = false, length = 50)
private String lastName;
#Email
#Column(nullable = false, length = 120, unique = true)
private String email;
#Column(nullable = false)
private String encryptedPassword;
private Boolean emailVerificationStatus = false;
private String emailVerificationToken;
#ManyToMany(cascade= { CascadeType.PERSIST }, fetch = FetchType.EAGER )
#JoinTable(
name = "user_role",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns=#JoinColumn(name = "role_id", referencedColumnName = "id"))
private List<RoleModel> roles;
#JsonManagedReference
#OneToMany(mappedBy = "user")
private List<ProjectModel> projects;
}
For the list of projects, I also have an entity class:
#Entity
#Table(name= "projects")
#Getter #Setter
public class ProjectModel implements Serializable {
#Setter(AccessLevel.NONE)
#Getter(AccessLevel.NONE)
public static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(nullable = false, unique = true)
private String projectId;
// ...
#Column
#JsonManagedReference
#OneToMany(mappedBy = "project")
private List<ObjectiveModel> objectives;
// ...
#JsonBackReference
#ManyToOne(
cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH },
fetch = FetchType.LAZY
)
private UserModel user;
}
I also use a DTO layer to communicate with database:
#Getter #Setter
public class UserDto implements Serializable {
#Setter(AccessLevel.NONE)
#Getter(AccessLevel.NONE)
private static final long serialVersionUID = -5352357837541477260L;
// contains more information than models used for rest
private long id;
private String userId;
private String firstName;
private String lastName;
private String email;
private String password;
private String encryptedPassword;
private String emailVerificationToken;
private Boolean emailVerificationStatus = false;
private List<String> roles;
private List<ProjectDto> projects;
}
Each entity has its own Dto equivalent. I can create a user. My issue is trying to log in. My userServiceImpl implements Spring Security UserService. Here is my implementation :
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
UserModel userModel = userRepository.findByEmail(email);
if(userModel == null)
throw new UsernameNotFoundException("User with email " + email + " not found");
return new UserPrincipalManager(userModel);
}
My UserPrincipalManager :
public class UserPrincipalManager implements UserDetails {
private static final long serialVersionUID = 7464059818443209139L;
private UserModel userModel;
private ProjectModel projectModel;
#Getter #Setter
private String userId;
#Autowired
public UserPrincipalManager(UserModel userModel) {
this.userModel = userModel;
this.userId = userModel.getUserId();
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new HashSet<>();
Collection<AuthorityModel> authorityModelEntities = new HashSet<>();
// get user roles
Collection<RoleModel> roleModels = userModel.getRoles();
if (roleModels == null) {
return authorities; // null
}
// get user roles
roleModels.forEach((role) ->{
authorities.add(new SimpleGrantedAuthority(role.getName()));
authorityModelEntities.addAll(role.getAuthorities());
});
// get user authorities
authorityModelEntities.forEach(authorityModel -> {
authorities.add(new SimpleGrantedAuthority(authorityModel.getName()));
});
return authorities;
}
#Override
public String getPassword() {
return this.userModel.getEncryptedPassword();
}
#Override
public String getUsername() {
return this.userModel.getEmail();
}
// we do not store this information in DB
#Override
public boolean isAccountNonExpired() {
return true;
}
// we do not store this information in DB (yet)
#Override
public boolean isAccountNonLocked() {
return true;
}
// we do not store this information in DB (yet)
#Override
public boolean isCredentialsNonExpired() {
return true;
}
// isEnabled depending if account is activated => email verification status value
#Override
public boolean isEnabled() {
return this.userModel.getEmailVerificationStatus();
}
}
While trying to log in a User sql request is looping.
at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:59)
at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:31)
at org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:303)
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:110)
at org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:242)
at org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:188)
at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:152)
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:106)
at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:59)
at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:31)
at org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:303)
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:110)
at org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:242)
at org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:188)
at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:152)
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:106)
at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:59)
at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:31)
at org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:303)
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:110)
at org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:242)
at org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:188)
at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:152)
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:106)
In the end the application crashes and returns a 403 error.
2020-10-05 12:07:22.215 DEBUG 4564 --- [nio-8080-exec-8] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.3.3.RELEASE.jar:5.3.3.RELEASE]
The login fonction works if user do not have project associated.
I don't know anything about model mapper, but I would like to provide you an alternative solution because I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(UserModel.class)
public interface UserDto extends Serializable {
#IdMapping
Long getId();
String getUserId();
String getFirstName();
String getLastName();
String getEmail();
String getPassword();
String getEncryptedPassword();
String getEmailVerificationToken();
Boolean getEmailVerificationStatus();
Set<String> getRoles();
Set<ProjectDto> getProjects();
#EntityView(ProjectModel.class)
interface ProjectDto {
#IdMapping
Long getId();
String getProjectId();
// Other mappings...
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
UserDto a = entityViewManager.find(entityManager, UserDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
The big bonus here, it will only fetch the columns that are actually needed and it validates the DTO model against your JPA model during boot time, so there are no more runtime surprises!
I am new to the world of JPA and hibernate. I have an entity EMPLOYEE for which I am trying to save a simple empty record but I keep on getting the following exception:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet] with root cause java.sql.SQLSyntaxErrorException: Unknown column 'employee0_.employee_id' in 'field list'
My entity class looks like this:
package com.workforcesoftware.groupmanagementservice.data.entities;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
#Entity
#Table(name = "employee")
public class Employee implements Serializable {
#Id
#Column(name = "employeeId")
private String employeeId;
#Column(name = "displayEmployeeId")
private String displayEmployeeId;
#Column(name = "accountId")
private String accountId;
#Column(name = "userId")
private String userId;
private String firstName;
private String lastName;
private String displayName;
private String birthDate;
private String phoneNumber;
private String originalHireDate;
private String externalMatchId;
#OneToMany(mappedBy = "employee")
private List<EffectiveDatedEmployee> effectiveDatedEmployees;
#OneToMany(mappedBy = "employee")
private List<Job> jobs;
public Employee(){ }
public Employee(String employeeId, String displayEmployeeId, String accountId, String userId, String firstName,
String lastName, String displayName, String birthDate, String phoneNumber, String originalHireDate,
String externalMatchId, List<EffectiveDatedEmployee> effectiveDatedEmployees, List<Job> jobs) {
this.employeeId = employeeId;
this.displayEmployeeId = displayEmployeeId;
this.accountId = accountId;
this.userId = userId;
this.firstName = firstName;
this.lastName = lastName;
this.displayName = displayName;
this.birthDate = birthDate;
this.phoneNumber = phoneNumber;
this.originalHireDate = originalHireDate;
this.externalMatchId = externalMatchId;
this.effectiveDatedEmployees = effectiveDatedEmployees;
this.jobs = jobs;
}
}
My repository interface looks like:
public interface EmployeeRepository extends JpaRepository<Employee, String> {
}
Finally, my repository calling code looks like this:
Employee employee = new Employee("1", "", "", "", "", "", "", "", "", "", "", null, null);
employeeRepository.save(employee);
The project crashes for one simple reason - it does not see the table (it seems to me), maybe the problem is in the #Table annotation
#Entity
#Table(name = "user")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class User extends BaseEntity<Long> {
public enum Roles {
ADMIN
}
private String firstName;
private String lastName;
#Column(name = "username")
private String username;
#Convert(converter = PurshasedProductConverter.class)
private List<PurshasedProduct> purshasedProducts;
private String email;
private String activationCode;
#Convert(converter = AttachmentConverter.class)
private Attachment userAvatar;
public Attachment getUserAvatar() {
return userAvatar;
}
public void setUserAvatar(Attachment userAvatar) {
this.userAvatar = userAvatar;
}
#JsonProperty(access = Access.WRITE_ONLY)
private String password;
#JsonProperty(access = Access.WRITE_ONLY)
private String temporaryPassword;
#Convert(converter = StringArrayConverter.class)
private String[] roles;
private Date lastPasswordReset;
private Date dateCreated;
private Date dateUpdated;
private Date validatyTime;
private Boolean active;}
I used to have #Table (name = "\" user \ ""), but this created a lot of other problems for me, now as you see in the code, but it doesn't work. Here is the error itself Caused by: org.postgresql.util.PSQLException: ERROR: column user0_.id does not exist
some advise adding schema to the table annotation, but this does not help me
I also faced this problem and including schema name in my #Table annotation solved the problem:
#Table(name = "user", schema="mySchema")
I am trying to use a projection and am getting the following error. Not sure what the issue is.
Here is the projection:
public interface UserMini {
Long getApproverKey();
String getEmailAddress();
String getFirstName();
String getLastName();
Long getUserKey();
String getUserName();
}
Here is the Query in the repository:
#RestResource(path="getUserMini")
#Query(value="SELECT approverKey, emailAddress, firstName, lastName, userKey, userName FROM [dbo].BdmUser WHERE userKey = :userKey ", nativeQuery=true)
UserMini getUserMini(#Param("userKey") long userKey);
Here is the Entity
#Table (name="[BdmUser]")
#Entity
public class BdmUser {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long userKey;
private Long priceListKey;
private String firstName;
private String lastName;
private String userName;
private String emailAddress;
private String password;
private Boolean active;
private Long approverKey;
private BigDecimal orderLimit;
private Long salesOfficeKey;
private Long reportsToId;
private Boolean requiresOrderApproval;
private Date lastLoginDate;
private String rowIsCurrent;
private Date rowStartDate;
private Date rowEndDate;
#Column(name="HashByteValueType1", updatable=false, insertable=false)
private String hashByteValueType1;
#Column(name="HashByteValueType2", updatable=false, insertable=false)
private String hashByteValueType2;
private String rowChangeReason;
#Column(name="DQScoreKey")
private Integer dqScoreKey;
private Integer insertAuditKey;
private Integer updateAuditKey;
Try to cast the NVARCHAR to VARCHAR in your query
CONVERT(varchar,theNVarcharColumn)
I have the following classes: DepartmentMember and Account, mapped by a OneToOne relationship.
This is the DepartmentMember class:
#Entity(name="departmentmember")
#Table(name="departmentmember")
#Embeddable
public class DepartmentMember {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name="name", nullable=false)
private String nume;
#Column(name="lastName", nullable=false)
private String prenume;
#OneToOne(mappedBy="departmentMember",cascade=CascadeType.ALL,fetch=FetchType.LAZY, optional=false)
#JsonIgnore
private Account account;
public DepartmentMember() {}
public DepartmentMember(String nume, String prenume, String cNP, String email) {
super();
this.nume = nume;
this.prenume = prenume;
}
//getters and setters
}
And this is the Account class :
#Entity(name="users")
#Table(name="users")
public class Account {
#Id
private int id;
#Column(name="username", unique=true, nullable=false)
private String username;
#Column(name="password", nullable = false)
private String password;
#Column(name="authorities", nullable=false)
private String authorities;
#OneToOne(fetch=FetchType.EAGER)
#MapsId
#Embedded
private DepartmentMember departmentMember;
public Account() {}
public Account(String username, String password, String authorities) {
super();
this.username = username;
this.password = password;
this.authorities = authorities;
}
//getters and setters
}
I have defined an interface AccountRepository which extends the CrudRepository interface provided by Spring JPA.
What I want to do is define a query, which takes as a parameter a DepartmentMember id and retrieves the associated account for that member. Now this is how an Account object looks like:
{
"username": "Maria_Popescu",
"password": "4ec38c6e-2463-4562-99ba-9f6c2b4528c4",
"authorities": "ROLE_USER",
"departamentMember": {
"id": 2,
"nume": "Popescu",
"prenume": "Maria",
}
I tried using the findOne(int id) method, but it didn't work, so which is the correct approach to solve this?
Edit:
In the AccountRepository I have defined the following method :
Account findByDepartmentMemberId(int id) and I still get a not found error.
There was actually another problem in my controller. I managed to get it working by adding
Account findByDepartmentMemberId(#Param("id")int id);
in the AccountRepository