Native Query mapstruct - java

I am using native query and I get a Tuple with a set of login, email, pass, regDate.
I also created a class with these attributes (This is not an Entity and I don't need it).
Question: How can I get this class using mapstruct (DTO)
#Query("SELECT * FROM users .......", nativeQuery = true)
List<Tuple> getInfo();
#Data
public class UserPro {
String login;
String email;
String pass;
Date regDate;
}

You are almost there but you have some misunderstood concept. If i understood what you are asking...
The "getInfo" query has to obtain every "user" it receives from the query. Everything it receives it's been saved into a "Tuple" List, I suppose Tuple is a model or dto. If you want to save what you receive from that query you have to create a model, not a dto and you may call it "user".
Dtos are classes made to work with data relationated to a Http request, not a query.
Models are classes made to work with data relationated to a database, including database queries.
Inside that "user" model you have to instantiate every column you get from the database (be sure to name the #Column annotation variable the same each column is named on the database and give them the correct data type as in the Database).
Keep in mind that every user has an unique identifier, it doesn't have to be called ID, but you have to know who that unique identifier is.
After instantiating every variable you have to instantiate the getters and setters and a constructor instantiating every variable.
Example:
#Entity
#Table(name = "TABLE_NAME")
public class User implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PUT_HERE_YOUR_UNIQUE_INDENTIFIER_HERE")
private "UNIQUE_INDENTIFIER_DATA_TYPE" id;
#Column(name = "LOGIN_COLUMN_NAME")
private String login;
#Column(name = "EMAIL_COLUMN_NAME")
private String email;
#Column(name = "PASSWORD_COLUMN_NAME")
private String pass;
#Column(name = "REGDATE_COLUMN_NAME", nullable = false)
private Date regDate;
//default constructor
public User() {}
//user constructor
public User()
{
this.id = id;
this.login = login;
this.email = email;
this.pass = pass;
this.regDate = regDate;
}
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getLogin()
{
return login;
}
public void setLogin(String login)
{
this.login = login;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
public String getPass()
{
return pass;
}
public void setPass(String pass)
{
this.pass = pass;
}
public Date getRegDate()
{
return regDate;
}
public void setRegDate(Date regDate)
{
this.regDate = regDate;
}
}

Related

OneToOne relationship hibernate+spring-data-jpa null value in owning schema

I am new to Hibernate and JPA (I worked mostly with stored procedure integration using JDBC.). I created two entities User and UserPassword with OneToOne relationship. I am trying to store values in both the tables (MySQL DB) but UserId (foreign_key) column of the UserPassword table stores null whereas the password gets stored. Please correct my mistake in below code :
#Entity
#Table(name = "User")
public class User implements Serializable{
private static final long serialVersionUID = -3366411610525655274L;
#Column(name = "UserId", nullable = false,unique = true)
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#GeneratedValue(generator = "uuid2")
#Id
#Type(type="uuid-char")
private UUID userId;
#Embedded
private Name name;
#Column(name = "DateOfBirth", nullable = false)
private Date dob;
#OneToOne(mappedBy="user", cascade=CascadeType.ALL)
private Password password;
public Password getPassword() {
return password;
}
public void setPassword(Password password) {
this.password = password;
}
public UUID getUserId() {
return userId;
}
public void setUserId(UUID userId) {
this.userId = userId;
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
public Date getDob() {
return dob;
}
public void setDob(Date dob) {
this.dob = dob;
}
}
and
#Entity
#Table(name= "UserPassword")
public class Password implements Serializable{
private static final long serialVersionUID = -8990341903052492314L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="PasswordId")
private Long Id;
#Column(name="Password")
private String password;
#OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
#JoinColumn(name="UserId", referencedColumnName="UserId")
private User user;
public Long getId() {
return Id;
}
public void setId(Long id) {
Id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
These are the my JPA repositories :
public interface UserRepository extends JpaRepository<User, UUID>{
}
and
public interface PasswordRepository extends JpaRepository<Password, Long>{
}
and service layer code to save entities in database :
public void insertUsers(List<User> users) {
List<com.poc.entity.User> usersData = ObjectMapperUtils.mapAll(users, com.poc.entity.User.class);
userRepository.saveAll(usersData);
}
Also, please help me in proper designing approach for this work.
It worked by doing small modification in service layer logic.
public void insertUsers(List<User> users) {
List<com.poc.entity.User> usersData = ObjectMapperUtils.mapAll(users, com.poc.entity.User.class);
usersData = usersData.stream().map(user->mapUserPassWordEntity(user)).collect(Collectors.toList());
userRepository.saveAll(usersData);
}
private com.poc.entity.User mapUserPassWordEntity(com.poc.entity.User user) {
Password password = new Password();
password.setPassword(user.getPassword().getPassword());
//set parent reference to child
password.setUser(user);
// set child reference to parent
user.setPassword(password);
return user;
}
Still, I would appreciate more suggestions for better approach.

JPA system exception error accesing field

I'm trying to implement a unidirectional many to many relationship between entities with spring+JPA.
After a few tries changing hibernate versions I don't know whats the cause
Caused by: org.springframework.orm.jpa.JpaSystemException: Error accessing field [private java.lang.Integer com.uca.refactor2.model.Achievement.id] by reflection for persistent property [com.uca.refactor2.model.Achievement#id] : 1; nested exception is org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private java.lang.Integer com.uca.refactor2.model.Achievement.id] by reflection for persistent property [com.uca.refactor2.model.Achievement#id] : 1
User.java
#Entity
#Table(name="USER")
public class User implements Serializable {
private static final long serialVersionUID = 4402583037980335445L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String firstName;
private String lastName;
#Column(unique = true)
private String username;
private String password;
#Enumerated(EnumType.STRING)
private UserType userType;
#OneToMany(cascade=CascadeType.ALL, mappedBy="joinedUserAchievementId.user")
private List<JoinedUserAchievement> joinedUserAchievementList = new ArrayList<JoinedUserAchievement>();
public User() {}
public User(Integer id) {
this.id = id;
}
public User(String username, String firstName, String lastName,
String password, UserType userType) {
this.username = username;
this.firstName = firstName;
this.lastName = lastName;
this.password = password;
this.userType = userType;
}
public List<JoinedUserAchievement> getAllAchievement() {
return joinedUserAchievementList;
}
public void addAchievement(Achievement achievement) {
// Notice a JoinedUserAchievement object
Date dateOfAcquisition = new Date();
JoinedUserAchievement joinedUserAchievement = new JoinedUserAchievement(new JoinedUserAchievement.JoinedUserAchievementId(this, achievement),dateOfAcquisition );
joinedUserAchievement.setAchievementId(achievement.getId());
joinedUserAchievementList.add(joinedUserAchievement);
}
//set and gets
JoinedUserAchievement.java
#Entity
#Table(name="USER_ACHIEVEMENT")
public class JoinedUserAchievement {
public JoinedUserAchievement() {}
public JoinedUserAchievement(JoinedUserAchievementId joinedUserAchievementId, Date dateOfAcquisition) {
this.joinedUserAchievementId = joinedUserAchievementId;
this.dateOfAcquisition = dateOfAcquisition;
}
#ManyToOne(targetEntity = Achievement.class)
#JoinColumn(name="id", insertable=false, updatable=false)
private Integer achievementId;
private Date dateOfAcquisition;
public String getDate() {
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date date = dateOfAcquisition;
return dateFormat.format(date);
}
public Integer getAchievementId() {
return achievementId;
}
public void setAchievementId(Integer achievementId) {
this.achievementId = achievementId;
}
#EmbeddedId
private JoinedUserAchievementId joinedUserAchievementId;
// required because JoinedUserAchievments contains composite id
#Embeddable
public static class JoinedUserAchievementId implements Serializable {
/**
*
*/
private static final long serialVersionUID = -9180674903145773104L;
#ManyToOne
#JoinColumn(name="USER_ID")
private User user;
#ManyToOne
#JoinColumn(name="ACHIEVEMENT_ID")
private Achievement achievement;
// required no arg constructor
public JoinedUserAchievementId() {}
public JoinedUserAchievementId(User user, Achievement achievement) {
this.user = user;
this.achievement = achievement;
}
public JoinedUserAchievementId(Integer userId, Integer achievementId) {
this(new User(userId), new Achievement(achievementId));
}
public User getUser() {
return user;
}
public Achievement getAchievement() {
return achievement;
}
public void setUser(User user) {
this.user = user;
}
public void setAchievement(Achievement achievement) {
this.achievement = achievement;
}
#Override
public boolean equals(Object instance) {
if (instance == null)
return false;
if (!(instance instanceof JoinedUserAchievementId))
return false;
final JoinedUserAchievementId other = (JoinedUserAchievementId) instance;
if (!(user.getId().equals(other.getUser().getId())))
return false;
if (!(achievement.getId().equals(other.getAchievement().getId())))
return false;
return true;
}
#Override
public int hashCode() {
int hash = 7;
hash = 47 * hash + (this.user != null ? this.user.hashCode() : 0);
hash = 47 * hash + (this.achievement != null ? this.achievement.hashCode() : 0);
return hash;
}
}
}
Achievement.java
#Entity
#Table(name="ACHIEVEMENT")
public class Achievement implements Serializable{
private static final long serialVersionUID = 7747630789725422177L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer points;
public Achievement() {
}
public Achievement(String name, Integer points) {
this.name = name;
this.points = points;
}
public Achievement(Integer id) {
this.id = id;
}
//set and gets
I've also tried to make this relationship bidirectional and it didn't work, so I may be missing something
Also before this I had achievement objects instead of achievementId on joinedUserAchievement, it worked but I think its not what I need, I don't need to get every achievement object always, with only the id is fine.
From the docs:
Relationship mappings defined within an embedded id class are not supported
You should put the ids only in JoinedUserAchievementId, and put User and Achievement associations in JoinedUserAchievement directly like so:
public class JoinedUserAchievementId {
private Long userId;
private Long achievementId;
...
}
public class JoinedUserAchievement {
#EmbeddedId
private JoinedUserAchievementId joinedUserAchievementId;
#ManyToOne
#MapsId("userId")
#JoinColumn(name = "USER_ID")
private User user;
#ManyToOne(optional = false, fetch = LAZY)
#MapsId("achievementId")
#JoinColumn(name = "ACHIEVEMENT_ID")
private Achievement achievement;
//if you absolutely need to map the achievement_id column here as well
//note that it will already be mapped to joinedUserAchievementId.achievementId
#Column(name = "ACHIEVEMENT_ID", insertable=false, updatable=false)
private Long achievementId;
...
}
Remember to update the User.joinedUserAchievementList mapping to mappedBy="user".

Spring boot , CrudRepository findbyid or findOne is not getting One to many table details of role table

#Entity
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Long id;
private String email;
private String password;
private String username;
#Transient
private String passwordConfirm;
//bi-directional many-to-one association to Role
#ManyToOne(fetch=FetchType.LAZY ,cascade = {CascadeType.PERSIST})
private Role role;
public User() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public Role getRole() {
return this.role;
}
public void setRole(Role role) {
this.role = role;
}
#Transient
public String getPasswordConfirm() {
return passwordConfirm;
}
public void setPasswordConfirm(String passwordConfirm) {
this.passwordConfirm = passwordConfirm;
}
}
#Entity
#NamedQuery(name="Role.findAll", query="SELECT r FROM Role r")
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Long id;
private String name;
//bi-directional many-to-one association to User
#OneToMany(fetch=FetchType.LAZY, mappedBy="role", cascade = {CascadeType.PERSIST})
private List<User> users;
public Role() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public List<User> getUsers() {
return this.users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public User addUser(User user) {
getUsers().add(user);
user.setRole(this);
return user;
}
public User removeUser(User user) {
getUsers().remove(user);
user.setRole(null);
return user;
}
}
public interface UserRepository extends CrudRepository <User, Long> {
public UserDto getUserDetailsById(Long userId) throws commonException {
//ArrayList<UserDto> arr = new ArrayList<>();
User user = userRepository.`findOne`(userId);
UserDto userDto = new UserDto();
userDto.setId(user.getId());
userDto.setUsername(user.getUsername());
userDto.setEmail(user.getEmail());
userDto.setPassword(user.getPassword());
userDto.setRoleId(user.getRole().getId());
userDto.setRoleName(user.getRole().getName());
// arr.add(userDto);
return userDto;
}
find by Id is not getting role details by using user object.lazy initialization is not happening.When I use to get user ID from user object, I can not get role details.
userDto.setRoleId(user.getRole().getId()); is having null value
In your User entity, you have configured the Role collection to load lazily. Therefore when you first call user.getRole(), you get a proxy object. If you want to call methods on the proxy object that need to fetch data, you should initialize the proxy. There is a technique to initialize it. Try the following:
Before the following line of code
userDto.setRoleId(user.getRole().getId());
add the following;
user.getRole().size();
For situations where you know that you need a particular association, its generally recommended that you specify that the association be join-fetched.
If the association is optional, you'd use something like:
FROM User u LEFT JOIN FETCH u.role WHERE u.id = :userId
If the association is not-optional, you could improve the above by specifying an inner join like:
FROM User u JOIN FETCH u.role WHERE u.id = :userId
With Spring data, you can use the #Query annotation on methods and specify the JPQL/HQL above to suit your needs.

How to save an object to db and connect it with logged in user

I'm making my first web-app using Spring Boot, Thymeleaf, Hibernate (with in-memory H2 database). I also want to use Spring Security but I try to avoid it for now (want to finish Entities and repositories first although I know I will have to change the way they work) I want a user to register on my site (he is created and added to my db) and then he can CRUD his ToDos (which are also saved to db). I have connected both entitites with bidirectional OneToMany using annotations and #JoinTable/#mappedBy. Here are my entities:
ToDoItem.java
#Entity
#Table (name = "TO_DO_ITEM")
public class ToDoItem extends BaseEntity {
#Column(name = "TITLE", nullable = false)
private String title;
#Column(name = "COMPLETED")
private boolean completed;
// TODO: 29.01.17 Add description property
#Column(name = "DUE_DATE", nullable = false)
private LocalDate dueDate;
// two-directional OneToMany
#ManyToOne
#JoinColumn(name = "USER_ID")
private User user;
// JPA demands empty contructor
ToDoItem() {}
public ToDoItem(String title, LocalDate dueDate) {
this.title = title;
this.dueDate = dueDate;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isCompleted() {
return completed;
}
public void setCompleted(boolean completed) {
this.completed = completed;
}
public LocalDate getDueDate() {
return dueDate;
}
public void setDueDate(LocalDate dueDate) {
this.dueDate = dueDate;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
User.java
#Entity
#Table (name = "USERS")
public class User extends BaseEntity {
#Column(name = "USERNAME")
private String username;
// TODO: 28.01.17 Find a way to store hashed and salted pws in DB
#Column(name = "PASSWORD")
private String password;
#Column(name = "EMAIL")
private String email;
#OneToMany(mappedBy = "user")
private Set<ToDoItem> toDoItems = new HashSet<>();
// JPA demands empty constructor
User() {}
public User(String username, String password, String email) {
this.username = username;
this.password = password;
this.email = email;
}
public Set<ToDoItem> getToDoItems() {
return toDoItems;
}
public void setToDoItems(Set<ToDoItem> toDoItems) {
this.toDoItems = toDoItems;
}
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;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
I am initialized a set in User.java so I can add created items by logged in user to his own set so they are not just sent to the db, but they are actually connected. Now I just need a method to add newly created item by him to his set (and to the db).
I have two Service beans:
ToDoItemServiceBean.java
#Service
public class ToDoItemServiceBean implements ToDoItemService {
#Autowired
private ToDoItemRepository toDoItemRepository;
#Override
public Iterable<ToDoItem> listAllToDoItems() {
return toDoItemRepository.findAll();
}
#Override
public ToDoItem getToDoItemById(Long id) {
return toDoItemRepository.findOne(id);
}
#Override
public ToDoItem addNewToDo(ToDoItem toDoItem) {
return toDoItemRepository.save(toDoItem);
}
#Override
public void deleteToDo(Long id) {
toDoItemRepository.delete(id);
}
}
UserServiceBean.java
#Service
public class UserServiceBean implements UserService {
#Autowired
private UserRepository userRepository;
#Override
public User saveUser(User user) {
return userRepository.save(user);
}
}
And I have no clue how to add those ToDos to a specific user in db. Should I just add an item to a set in addNewToDo so apart from adding new ToDo to db this method would also somehow connect ToDo with a user? But how do I do it? What's the best approach to fix it?
HERE is the rest of my code (didn't want to paste all of my files into this post).
EDIT:
I rethought my db structure and I think that I should have OneToMany in UserEntity because User can have many ToDos but OneToOne in ToDoItemEntity because a ToDo can have only one user - that's correct, right?
And from that link I made something like this, is it ok?
ToDoItemEntity
// a ToDoItem is only associated with one user
#OneToOne(cascade = CascadeType.ALL, mappedBy = "toDoItems")
private User user;
UserEntity
//user can have many ToDoItems
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private Set<ToDoItem> toDoItems;
Added updateUser to:
UserServiceBean.java
#Override
public void updateUser(ToDoItem toDoItem) {
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User queriedUser = userRepository.findOne(currentUser.getId());
queriedUser.setToDoItems();
}
you can add ToDoItems to the user and save the user entity. Make use of Cascade operations to cascade the operation
http://howtodoinjava.com/hibernate/hibernate-jpa-cascade-types/
// two-directional OneToMany
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private User user;
update : UserServiceBean.java
public void updateUser(User user){
// update the user entity here by adding the todoitems and call saveuser again
}
Update 2 : ToDoItemController
#Override
public ToDoItem addNewToDo(ToDoItem toDoItem) {
return toDoItemRepository.updateItems(toDoItem);
}
ToDoItemServiceBean :
public void updateItems(ToDoItem toDoItem) {
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User queriedUser = userRepository.findOne(currentUser.getId());
toDoItem.setUser(queriedUser);
saveToDoItem(toDoItem)// since it is bidirectional
}

Spring Restcontroller not returning xml

I'm getting json response from my controller even though I added the xml annotations to my model. I get the list of users in json with no problems. Can I use #Entity and #XmlRootElement in the same class?
User.java
#Entity
#Table(name = "usr")
#XmlRootElement
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", nullable = false, unique = true, length = 11)
private int id;
#Column(nullable = false)
private String username;
#Column(nullable = false)
private String password;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
#Column(nullable = false)
private String email;
#OneToMany(mappedBy = "user")
private List<Post> post;
#OneToMany(mappedBy = "user")
private List<Friend> friends;
public List<Friend> getFriends() {
return friends;
}
public void setFriends(List<Friend> friends) {
this.friends = friends;
}
public List<Post> getPost() {
return post;
}
public void setPost(List<Post> post) {
this.post = post;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#XmlElement
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;
}
#XmlElement
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#XmlElement
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#XmlElement
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
getAllUsers
#Override
public List<User> getAllUsers() {
List<User> users = new ArrayList<User>();
Session session = HibernateUtil.getSessionAnnotationFactory().openSession();
Transaction trns = null;
try {
trns = session.beginTransaction();
users = session.createQuery("select firstName, lastName, email, username as name from User").list();
trns.commit();
} catch (RuntimeException e) {
if (trns != null) {
trns.rollback();
}
e.printStackTrace();
} finally {
session.flush();
session.close();
}
return users;
}
and in the controller
#RequestMapping(value="/api/users", method = RequestMethod.GET)
public List<User> getAllUsers() {
//List<User> users = new ArrayList<User>();
UserDao userdao = new UserDaoImpl();
List<User> users = userdao.getAllUsers();
return users;
}
What am I missing here?
There is a nice blog entry from Spring about this. From there is this about content negotiation:
Enabling Content Negotiation in Spring MVC
Spring supports a couple of conventions for selecting the format
required: URL suffixes and/or a URL parameter. These work alongside
the use of Accept headers. As a result, the content-type can be
requested in any of three ways. By default they are checked in this
order:
Add a path extension (suffix) in the URL. So, if the incoming URL is
something like http://myserver/myapp/accounts/list.html then HTML is
required. For a spreadsheet the URL should be
http://myserver/myapp/accounts/list.xls. The suffix to media-type
mapping is automatically defined via the JavaBeans Activation
Framework or JAF (so activation.jar must be on the class path).
A URL parameter like this: http://myserver/myapp/accounts/list?format=xls.
The name of the parameter is format by default, but this may be
changed. Using a parameter is disabled by default, but when enabled,
it is checked second.
Finally the Accept HTTP header property is
checked. This is how HTTP is actually defined to work, but, as
previously mentioned, it can be problematic to use.
But if you just want to fix the return type I'd add the annotation #RequestMapping(value="/api/users", produces={"application/xml"}) to your controller method.
First, try to change
#RequestMapping(value="/api/users", method = RequestMethod.GET)
to
#ResponseBody
#RequestMapping(value="/api/users", method = RequestMethod.GET, produces = MediaType.APPLICATION_XML_VALUE)
Second, check out if client code ( I assume it is javascript ) is sending correct accept-type, because Jackson - the default serialization engine would derive format of response body from HTTP header.
Third, ensure that you have JAXB present in your classpath.

Categories