Nested exception is java.lang.ClassCastException: java.lang.String cannot be cast - java

I am new to spring-data, I have this error java.lang.String cannot be cast to com.example.accessingdatamysql.User and do not know how to fix it! I add the various relevant parts of my code.
The method should output the oldest entry (via timestamp) by name.
Main.Controller
package com.example.accessingdatamysql;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
#RequestMapping(path="/demo")
public class MainController {
#Autowired
private UserRepository userRepository;
#Transactional
#PostMapping(path="/add")
public #ResponseBody String addNewUser (#RequestParam String name,
#RequestParam String email,#RequestParam String surname)
{
User n = new User();
n.setName(name);
n.setSurname(surname);
n.setEmail(email);
userRepository.create(n);
return "Saved";
}
#GetMapping(path="first")
User one(#RequestParam String name) {
return userRepository.findFirstByName(name);
}
}
User.java
package com.example.accessingdatamysql;
import java.sql.Timestamp;
import java.time.Instant;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
public String name;
private String email;
private String surname;
#Column(name="stmp", columnDefinition = "TIMESTAMP (6)")
Timestamp timestamp = Timestamp.from(Instant.now());
public void setTimestamp(Timestamp timestamp) {
this.timestamp = timestamp;
}
public Timestamp getTimestamp() {
return timestamp;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
RepoImpl.java
package com.example.accessingdatamysql;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.springframework.stereotype.Component;
#Component
public class UserRepositoryImpl implements UserRepository {
private final EntityManager em;
public UserRepositoryImpl(EntityManager entityManager) {
this.em = entityManager;
}
#Override
public User findFirstByName(String name) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(User.class);
Root<User> root = criteria.from(User.class);
criteria.select(root.get("name"));
criteria.orderBy(builder.asc(root.get("timestamp")));
TypedQuery<User> query = em.createQuery(criteria).setMaxResults(1);
return query.getSingleResult();
}
#Override
// per la creazione//
public void create(User entity) {
em.persist(entity);
}
}
ERROR
[Request processing failed; nested exception is java.lang.ClassCastException: java.lang.String cannot be cast to com.example.accessingdatamysql.User] with root cause
java.lang.ClassCastException: java.lang.String cannot be cast to com.example.accessingdatamysql.User
at com.example.accessingdatamysql.UserRepositoryImpl.findFirstByName(UserRepositoryImpl.java:35) ~[classes!/:0.0.1-SNAPSHOT]

If you meant to find User by name, you should have set the filter parameter not in criteria.select but in criteria.where:
public User findFirstByName(String name) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(User.class);
Root<User> root = criteria.from(User.class); // root is User
criteria.select(root).where(builder.equal(root.get("name"), name));
criteria.orderBy(builder.asc(root.get("timestamp")));
TypedQuery<User> query = em.createQuery(criteria).setMaxResults(1);
return query.getSingleResult();
}
While criteria.select(root.get("name")); implies that only column "name" is selected and returned, that is the name of the first user should be returned.
If such information is needed, it may be retrieved in the following way:
public String findFirstUserName() {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<String> criteria = builder.createQuery(String.class);
Root<User> root = criteria.from(User.class); // root is User
criteria.select(root.get("name")); // getting name
criteria.orderBy(builder.asc(root.get("timestamp"))); // of the first/earliest user
TypedQuery<String> query = em.createQuery(criteria).setMaxResults(1);
return query.getSingleResult();
}

Do just like the error says -
CriteriaQuery<String> criteria = builder.createQuery(String.class);
instead of
CriteriaQuery<User> criteria = builder.createQuery(User.class);
Read more here Reference

Related

Problem in Soft Deleting child entity in Spring Boot in #OneToMany relation

I have started learning Spring Boot recently.
I am trying to Soft delete the user. I want to soft delete all the Notes of the user when I soft delete the User. But my code is only soft deleting the user, not its notes.
When I am doing soft delete only on notes table, it's working fine but on User Entity, it is only deleting the user.
Notes
package com.we.springmvcboot.Model;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
import com.fasterxml.jackson.annotation.JsonIgnore;
#Entity
#Table(name="Notes")
#Where(clause = "deleted = 'false'")//FALSE
public class Notes {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="NotesID")
private long NotesID;
#Column(name="Title")
private String Title;
#Column(name="Message")
private String Message;
#Column(name="Date")
private String date;
#Column(name="deleted")
private String deleted="false";
#Column(name="label")
private int label=1;
#ManyToOne()
#JoinColumn(name = "UserID", nullable = false)
private User user;
public Notes() {}
public String getDeleted() {
return deleted;
}
public void setDeleted(String deleted) {
this.deleted = deleted;
}
public Notes(String title, String message, String date, User user, int label) {
super();
Title = title;
Message = message;
this.date = date;
this.user = user;
this.label=label;
}
public Notes(long notesID, String title, String message, String date, int label) {
super();
NotesID = notesID;
Title = title;
Message = message;
this.date = date;
this.label=label;
}
public int getLabel() {
return label;
}
public void setLabel(int label) {
this.label = label;
}
public long getNotesID() {
return NotesID;
}
public void setNotesID(long notesID) {
NotesID = notesID;
}
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getMessage() {
return Message;
}
public void setMessage(String message) {
Message = message;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public void setUser(User user) {
this.user = user;
}
}
User
package com.we.springmvcboot.Model;
import java.util.ArrayList;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Where;
import antlr.collections.List;
#Entity
#Table(name="User")
#Where(clause = "deleted = 'false'")//FALSE
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long UserID;
#Column(name="emailid")
private String emailID;
#Column(name="deleted")
private String deleted="false";
#OneToMany(mappedBy="user", fetch = FetchType.EAGER,cascade=CascadeType.ALL, orphanRemoval=true)
private Set<Notes> usernotes;
public User() {}
public User(String emailID) {
super();
this.emailID = emailID;
}
public long getUserID() {
return UserID;
}
public void setUserID(long userID) {
UserID = userID;
}
public String getemailID() {
return emailID;
}
public void setemailID(String emailID) {
emailID = emailID;
}
public Set<Notes> getUsernotes() {
return usernotes;
}
public void setUsernotes(Set<Notes> usernotes) {
this.usernotes = usernotes;
}
}
NotesRepository
package com.we.springmvcboot.Repository;
import java.sql.Date;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.we.springmvcboot.Model.Notes;
#Repository
public interface NotesRepository extends JpaRepository<Notes, Long> {
#Query("update Notes e set e.deleted='true' where e.NotesID=?1")
#Transactional
#Modifying
public void softDelete(long id);
}
UserRepository
package com.we.springmvcboot.Repository;
import java.sql.Date;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.we.springmvcboot.Model.Notes;
import com.we.springmvcboot.Model.User;
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByEmailID(String email);
#Query("update User e set e.deleted='true', where e.UserID=?1")
#Transactional
#Modifying
public void softDelete(long id);
}
TodoService
package com.we.springmvcboot.Service;
import com.we.springmvcboot.Model.*;
import com.we.springmvcboot.exception.*;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import com.we.springmvcboot.Repository.NotesRepository;
import com.we.springmvcboot.Repository.UserRepository;
#Service
public class TodoService {
#Autowired
UserRepository userrepo;
#Autowired
NotesRepository notesrepo;
public Object deleteUser(Map<String, Object> input) {
long userID;
userID = ((Number) input.get("userID")).longValue();
userrepo.softDelete(userID);
return null;
}
}
I would suggest that you read this post for the simplest approach to soft delete. You should arrive at sth like the following:
#SQLDelete("UPDATE User SET deleted = TRUE WHERE id = ?")
#Where(clause = "deleted = FALSE")
public class User {
#OneToMany(mappedBy = "user", fetch = EAGER, cascade=ALL, orphanRemoval = true)
private Set<Notes> usernotes;
...
}
#SQLDelete("UPDATE Note SET deleted = TRUE WHERE id = ?")
#Where(clause = "deleted = FALSE")
public class Note {...}
The above will work if you use the following code to delete a User:
public Object deleteUser(Map<String, Object> input) {
long userID;
userID = ((Number) input.get("userID")).longValue();
User user = userrepo.deleteById(userID);
return null;
}
If you want to keep using the custom query, though, you still need to call a separate query to delete Notes by userId, because Cascade.REMOVE will not be triggered in this case. In other words, you'll want a method like:
public interface NotesRepository extends JpaRepository<Notes, Long> {
#Query("UPDATE Notes n SET n.deleted = TRUE WHERE n.user.id = :id")
public void deleteByUserId(long id);
}
which you then call from deleteUser:
long userID;
userID = ((Number) input.get("userID")).longValue();
userrepo.softDelete(userID);
noteRepo.deleteByUserId(userID);
return null;

Hibernate Exception:Could not execute statement, com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'USERID' in 'field list'

package hibernate2;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="User1_Details")
public class UserDetails {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int userId;
private String userName;
#OneToMany(mappedBy="user")
private Collection<Vehicle> vehicle = new ArrayList<Vehicle>();
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Collection<Vehicle> getVehicle() {
return vehicle;
}
public void setVehicle(Collection<Vehicle> vehicle) {
this.vehicle = vehicle;
}
}
And i created a vehicle class
package hibernate2;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
#Entity
public class Vehicle {
#Id
#GeneratedValue(strategy =GenerationType.AUTO)
private int vehicle_Id;
private String vehicle_Name;
#ManyToOne
#JoinColumn(name="USER_ID")
private UserDetails user;
public UserDetails getUser() {
return user;
}
public void setUser(UserDetails user) {
this.user = user;
}
public int getVehicle_Id() {
return vehicle_Id;
}
public void setVehicle_Id(int vehicle_Id) {
this.vehicle_Id = vehicle_Id;
}
public String getVehicle_Name() {
return vehicle_Name;
}
public void setVehicle_Name(String vehicle_Name) {
this.vehicle_Name = vehicle_Name;
}
}
And The Following were my hiernate code or DAO class
package hibernate2;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Hibernate {
public static void main(String[] args) {
UserDetails user = new UserDetails();
user.setUserName("Ranjith");
Vehicle vehicle = new Vehicle();
vehicle.setVehicle_Name("Car");
Vehicle vehicle2 = new Vehicle();
vehicle2.setVehicle_Name("Jeep");
user.getVehicle().add(vehicle);
user.getVehicle().add(vehicle2);
vehicle.setUser(user);
vehicle2.setUser(user);
SessionFactory sessionfactory = new
Configuration().configure().buildSessionFactory();
Session session = sessionfactory.openSession();
session.beginTransaction();
session.save(user);
session.save(vehicle);
session.save(vehicle2);
session.getTransaction().commit();
session.close();
}
}
After Running this above class i get the following error
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute statement
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'USER_ID' in 'field list'

Spring JpaSpecificationExecutor new query method NoSuchElementException

I'm using Spring and JpaRepository as data access layer. I have my #Repository interface as below:
#Repository
interface EventRepository extends JpaRepository<Event, Long>, JpaSpecificationExecutor<Event> {
.... some custom methods irrelevant to this post ....
}
Here's my simplified model classes:
class Event {
Long eventID;
String name;
Date time;
Zone zone;
}
class Zone {
Long zoneId;
String zoneName;
User user;
}
class User {
Long userId;
String username;
}
I'm using there JpaSpecificationExecutor to fetch database for list of Events in specific time. I'm using this method and it work correctly:
Page<T> findAll(Specification<T> spec, Pageable pageable);
But I want to add another condition to fetch entries only for specific User.
I tried to create new method like this:
Page<Event> findAllByZone_User(User user, Specification<Event> spec, Pageable pageable);
But when I call it I get in this line Exception:
java.util.NoSuchElementException: null
Is it even possible to create such method? If not - how should I proceed?
I have created a Spring boot project like yours and this is working for me. You can check my code below.....
Event.java
package com.example.model;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
#Entity
public class Event {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long eventID;
private String name;
private Date time = new Date();
#OneToOne(cascade = CascadeType.ALL)
private Zone zone;
public Long getEventID() {
return eventID;
}
public void setEventID(Long eventID) {
this.eventID = eventID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public Zone getZone() {
return zone;
}
public void setZone(Zone zone) {
this.zone = zone;
}
}
Zone.java
package com.example.model;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
#Entity
public class Zone {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long zoneId;
private String zoneName;
#OneToOne(cascade = CascadeType.ALL)
private User user;
public Long getZoneId() {
return zoneId;
}
public void setZoneId(Long zoneId) {
this.zoneId = zoneId;
}
public String getZoneName() {
return zoneName;
}
public void setZoneName(String zoneName) {
this.zoneName = zoneName;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
User.java
package com.example.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long userId;
private String username;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
and my repositories are
EventRepository.java
package com.example.model;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EventRepository extends JpaRepository<Event, Long>, JpaSpecificationExecutor<Event>{
Page<Event> findAllByZoneUser(User user, Pageable pageable);
}
UserRepository.java
package com.example.model;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long>{
}
I am calling repository methods directly in my controller like below
UserController.java
package com.example.model;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class UserController {
#Autowired
EventRepository eventRepository;
#Autowired
UserRepository userRepository;
#RequestMapping(value = "/{userId}", method = RequestMethod.GET)
public Map<String, Object> updateUserDO(#PathVariable Long userId) {
Map<String, Object> map = new HashMap<>();
User user = userRepository.findOne(userId);
PageRequest pageRequest = new PageRequest(0, 10, Sort.Direction.ASC, "eventID");
map.put("user", eventRepository.findAllByZoneUser(user, pageRequest));
return map;
}
}

Hibernate + JPA + spring boot org.hibernate.PersistentObjectException: detached entity passed to persist

I am using Spring Boot 4, Hibernate and JPA annotations. I ran into this error
org.hibernate.PersistentObjectException: detached entity passed to
persist.
I tried searching through the internet and couldn't quite get the proper answer. I tried to use merge instead of persist and it did not work. Besides I think merge is used when updating a resource.
Here is my code:
`
package com.matome.users.login.stats.springbootStarter.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.NamedQueries;
import com.matome.users.login.stats.springbootStarter.userconstants.UserRepositoryConstants;
#NamedQueries({
#NamedQuery(name = UserRepositoryConstants.NAME_GET_ALL_USERS,
query = UserRepositoryConstants.QUERY_GET_ALL_USERS),
#NamedQuery(name = UserRepositoryConstants.NAME_GET_USER_BY_ID,
query = UserRepositoryConstants.QUERY_GET_USER_BY_ID),
#NamedQuery(name = UserRepositoryConstants.NAME_GET_USER_BY_USERNAME,
query = UserRepositoryConstants.QUERY_GET_USER_BY_USERNAME),
#NamedQuery(name = UserRepositoryConstants.NAME_DELETE_USER,
query = UserRepositoryConstants.QUERY_DELETE_USER)
})
#Entity
public class User implements Serializable{
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy = GenerationType.AUTO)
Long id;
String username;
String password;
String phone;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = 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;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
`
CRUD service
`
package com.matome.users.login.stats.springbootStarter.CRUDService;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.matome.users.login.stats.springbootStarter.model.User;
import com.matome.users.login.stats.springbootStarter.repository.UserRepository;
#Service
#Transactional
public class UserCRUDService {
#Autowired
UserRepository userRepository;
public User createUser(User user) {
userRepository.save(user);
return user;
}
public User updateUser(User user) {
User existingUser = userRepository.getUserById(user.getId());
if (existingUser == null) {
throw new NoResultException();
}
existingUser.setId(user.getId());
existingUser.setUsername(user.getUsername());
existingUser.setPhone(user.getPhone());
existingUser.setPassword(user.getPassword());
userRepository.update(user);
return user;
}
public User deleteUser(long id) {
User user = userRepository.getUserById(id);
if (user == null) {
throw new NoResultException();
}
userRepository.delete(user);
return user;
}
}
`
Repository
`
package com.matome.users.login.stats.springbootStarter.repository;
import java.util.List;
import javax.persistence.TypedQuery;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.matome.users.login.stats.springbootStarter.model.User;
import com.matome.users.login.stats.springbootStarter.userconstants.UserRepositoryConstants;
#Repository
#Transactional
public class UserRepository extends AbstractRepository<User> {
TypedQuery<User> query;
public List<User> getAllUsers() {
query = entityManager.createNamedQuery(UserRepositoryConstants.NAME_GET_ALL_USERS, User.class);
return query.getResultList();
}
public User getUserById(long id) {
query = entityManager.createNamedQuery(UserRepositoryConstants.NAME_GET_USER_BY_ID, User.class);
query.setParameter("id", id);
return query.getSingleResult();
}
public User getUserByUsername(String username) {
query = entityManager.createNamedQuery(UserRepositoryConstants.NAME_GET_USER_BY_USERNAME, User.class);
query.setParameter("username", username);
return query.getSingleResult();
}
}
`
Abstract repository
`
package com.matome.users.login.stats.springbootStarter.repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public abstract class AbstractRepository<T> {
#PersistenceContext
protected EntityManager entityManager;
#Transactional(propagation = Propagation.MANDATORY)
public void save(T entity) {
entityManager.persist(entity);
entityManager.flush();
entityManager.refresh(entity);
}
#Transactional
public T update(T entity) {
return entityManager.merge(entity);
}
#Transactional
public void delete(T entity) {
entityManager.remove(entity);
}
}
`
Factory
`
package com.matome.users.login.stats.springbootStarter.factories;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import com.matome.users.login.stats.springbootStarter.BackingForm.UserBackingForm;
import com.matome.users.login.stats.springbootStarter.model.User;
import com.matome.users.login.stats.springbootStarter.viewmodels.UserViewModel;
#Service
public class UserFactory {
public UserViewModel createViewModel(User user) {
UserViewModel viewModel = new UserViewModel();
viewModel.setId(user.getId());
viewModel.setUsername(user.getUsername());
viewModel.setPhone(user.getPhone());
return viewModel;
}
public List<UserViewModel> createVewModels(List<User> users) {
List<UserViewModel> viewModels = new ArrayList<>();
if (users != null) {
for (User user : users) {
viewModels.add(createViewModel(user));
}
}
return viewModels;
}
public User createEntity(UserBackingForm userBackingForm) {
User user = new User();
user.setId(userBackingForm.getId());
user.setUsername(userBackingForm.getUsername());
user.setPassword(userBackingForm.getPassword());
user.setPhone(userBackingForm.getPhone());
return user;
}
}
`
Backing form
`
package com.matome.users.login.stats.springbootStarter.BackingForm;
public class UserBackingForm {
private long id;
private String username;
private String password;
private String phone;
public long getId() {
return id;
}
public void setId(long id) {
this.id = 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;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
`
Controller
`
package com.matome.users.login.stats.springbootStarter.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.matome.users.login.stats.springbootStarter.BackingForm.UserBackingForm;
import com.matome.users.login.stats.springbootStarter.CRUDService.UserCRUDService;
import com.matome.users.login.stats.springbootStarter.factories.UserFactory;
import com.matome.users.login.stats.springbootStarter.model.User;
import com.matome.users.login.stats.springbootStarter.repository.UserRepository;
import com.matome.users.login.stats.springbootStarter.viewmodels.UserViewModel;
#RestController
#RequestMapping("api")
public class UserController {
#Autowired
private UserRepository userRepository;
#Autowired
private UserCRUDService userCRUDService;
#Autowired
private UserFactory userFactory;
#RequestMapping(value = "/users", method = RequestMethod.GET)
public Map<String, Object> getAllUsers() {
Map<String, Object> map = new HashMap<>();
map.put("users", userRepository.getAllUsers());
return map;
}
#RequestMapping(value = "{id}", method = RequestMethod.GET)
public Map<String, Object> getUserById(#PathVariable long id) {
Map<String, Object> map = new HashMap<>();
map.put("user", userRepository.getUserById(id));
return map;
}
#RequestMapping(value = "/user/add", method = RequestMethod.POST)
public UserViewModel addUser(#RequestBody UserBackingForm form) {
User user = userFactory.createEntity(form);
//user.setIsActive(true);
user = userCRUDService.createUser(user);
return userFactory.createViewModel(user);
}
#RequestMapping(value = "/user/add/{id}", method = RequestMethod.PUT)
public Map<String, Object> updateUser(#PathVariable("id") Long id, #RequestBody User user) {
Map<String, Object> map = new HashMap<>();
user.setId(id);
map.put("updatedUser", userCRUDService.updateUser(user));
return map;
}
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String testFinal() {
return "User test sucessfully";
}
#RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public void deleteUser(#PathVariable("id") Long id) {
User user = userRepository.getUserById(id);
userRepository.delete(user);
}
}
`
View Model
`
package com.matome.users.login.stats.springbootStarter.viewmodels;
public class UserViewModel extends BaseViewModel<Long> {
private String username;
private String phone;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
`
base ViewModel
`
package com.matome.users.login.stats.springbootStarter.viewmodels;
public abstract class BaseViewModel<T> {
private T id;
public T getId() {
return id;
}
public void setId(T id) {
this.id = id;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
#SuppressWarnings("unchecked")
BaseViewModel<T> other = (BaseViewModel<T>) obj;
if (getId() == null) {
if (other.getId() != null)
return false;
} else if (!getId().equals(other.getId()))
return false;
return true;
}
}
`
Main
`
package com.matome.users.login.stats.springbootStarter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Main { public static void main(String[] args) {
SpringApplication.run(Main.class,args);
}
}
`
Stack Trace
`
org.hibernate.PersistentObjectException: detached entity passed to persist: com.matome.users.login.stats.springbootStarter.model.User
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347) ~[spring-orm-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at com.sun.proxy.$Proxy78.persist(Unknown Source) ~[na:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
`
In my opinion the problem lies in the fact that you have declared the id of User entity as auto-generated:
#Id #GeneratedValue(strategy = GenerationType.AUTO)
Long id;
and when you create the User object you set the id manually:
public User createEntity(UserBackingForm userBackingForm) {
User user = new User();
user.setId(userBackingForm.getId());
...
and thus when you pass that to persist / save, the Persistence Provider will not allow that as it expects that the id will not be set by the client.
The bottom line is that you should not set the id regarding the current configuration when you are aiming at persisting a new entry and you should be fine.
Can you provide a full stack trace ?
Some hints for you :
You should only set #Transactional at Service level, not dao / repository.
Entitymanager refresh method means get data from DB to recreate an entity. If you just persist the entity, there is no need to refresh it.
#Transactional(propagation = Propagation.MANDATORY)
public void save(T entity) {
entityManager.persist(entity);
entityManager.flush(); // This is not really usefull on a small transaction
entityManager.refresh(entity); // No need for that : persist means entity already in sync
}
On update side, if you have a managed entity there is no need to sync it back to the DB, JPA take care of that automatically. (and merge push entity in the db forcing an update of all column) :
public User updateUser(User user) {
User existingUser = userRepository.getUserById(user.getId());
// ...
existingUser.setPassword(user.getPassword());
// ...
userRepository.update(user); // This is not needed !
return user;
}
If you want simplest things, you should take a look at lombok. It will help you write simpliest bean ( #Data to generate getter/setter ...)
You use Spring, so take also a look at spring-Data-JPA, It writes for you some cumberstone code.

Messing around with JPA and getting an Error creating user - could not set field value

I am following the Spring tutorial to get started with JPA, and I have a basic mysql db with a user table.
I've set up User.java as follows:
package com.test.models;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Id;
import java.util.UUID;
#Entity
#Table(name="user")
public class User {
#Id
#GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
#Column(name="id")
private UUID id;
#Column(name="first_name")
String first_name;
#Column(name="last_name")
String last_name;
#Column(name="username")
String username;
public User(String first_name, String last_name, String username) {
this.first_name = first_name;
this.last_name = last_name;
this.username = username;
}
public User() { }
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getFirst_name() {
return first_name;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
I've set up the UserRepo.java:
package com.test.models;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.UUID;
#RepositoryRestResource
public interface UserRepo extends CrudRepository<User, UUID>{
User findByUsername(String username);
}
And finally the UserController.java:
package com.test.controllers;
import com.test.models.UserRepo;
import com.test.models.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class UserController {
#Autowired
private UserRepo userRepo;
#RequestMapping("/create")
#ResponseBody
public String create(String first_name, String last_name, String username) {
String userId = "";
try {
User user = new User(first_name, last_name, username);
userRepo.save(user);
userId = String.valueOf(user.getId());
}
catch (Exception ex) {
return "Error creating the user: " + ex.toString();
}
return "User successfully created with id = " + userId;
}
}
I've also set up my db connection:
spring.datasource.url=jdbc:mysql://localhost:3306/test?autoReconnect=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=fakepass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
However, when I use postman to make a POST to localhost:8080/create with
{
"first_name": "Jim",
"last_name": "Smith",
"username": "jim.smith"
}
I get this error:
Error creating the user:
org.springframework.orm.jpa.JpaSystemException: Could not set field
value [ff80818158b79f8e0158b7a285b60001] value by reflection : [class
com.test.models.User.id] setter of com.test.models.User.id; nested
exception is org.hibernate.PropertyAccessException: Could not set
field value [ff80818158b79f8e0158b7a285b60001] value by reflection :
[class com.test.models.User.id] setter of com.test.models.User.id
I had the same problem. Your strategy in #GenericGenerator is set incorrectly.
Try:
#GenericGenerator(name = "system-uuid", strategy = "org.hibernate.id.UUIDGenerator")
All JPA entity classes should have the empty constructors and your User class is missing empty constructor which is causing this issue, so change your User Entity class as shown below and add User() constructor:
public class User {
public User() {//empty constructor
}
//add existing code here
}
The entity class must have a no-arg constructor. The entity class may
have other constructors as well. The no-arg constructor must be public
or protected.
You can look here for the spec.
in dataBase exists UUID type, try to use UUID instead of varchar(36).

Categories

Resources