InvalidDataAccessApiUsageException: ("Unable to locate persister: java.lang.Integer" ) on Http DELETE request in spring boot

90 views Asked by At

I am creating a REST API for my my flutter expense tracker app.Every other http request works but when I give DELETE request it gives me InvalidDataAccessApiUsageException

Users entity:

package com.expense_tracker.expenseTracker.entities;

//imports

@Entity
@Table(name = "users")
public class Users {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "uid")
    private int userId;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "email")
    private String email;

    @Column(name = "password")
    private String password;

    @Column(name = "phone_number")
    private String phoneNumber;

    @OneToMany(mappedBy = "user",cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Expenses> expenses;

    // constructor,getters and setters, toString

Expenses Entity:

package com.expense_tracker.expenseTracker.entities;

//imports

@Entity
@Table(name = "expenses")
public class Expenses {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "expense_id")
    private int id;

    @Column(name = "title")
    private String title;

    @Column(name = "amount")
    private int amt;

    @Column(name = "expense_date")
    private String date;

    @Column(name = "category")
    private String category;

    @ManyToOne(fetch = FetchType.EAGER, cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST,
            CascadeType.REFRESH })
    @JoinColumn(name = "user_id")
    private Users user;

   // constructor,getters and setters, toString

UserDao:

package com.expense_tracker.expenseTracker.Dao.UserDao;

//imports

@Repository
public class UserDao implements UserDaoInterface {

    private EntityManager entityManager;

    public UserDao() {
    }

    @Autowired
    public UserDao(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    @Transactional
    public String creatUsers(Users user) {

        // BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        // String password = encoder.encode(user.getPassword());
        // user.setPassword(password);
        // saving the user
        entityManager.persist(user);
        // success
        return "Saved user with uid:" + user.getUserId();
    }

    @Override
    @Transactional
    public Users updateUsers(Users user) {
        // updating user
        return entityManager.merge(user);

    }

    @Override
    public Users getUser(int uid) {
        return entityManager.find(Users.class, uid);
    }

    @Override
    @Transactional
    public String deleteUser(int id) {

        Users temp = getUser(id);

        if (temp == null) {
            return "Unable to find any users with uid:" + id;
        }
        entityManager.remove(id);
        return "Removed user with uid:" + id;
    }
}

ExpensesDao:

package com.expense_tracker.expenseTracker.Dao.ExpenseDao;

//imports

@Repository
public class ExpenseDao implements ExpenseDaoInterface {

    private EntityManager entityManager;

    @Autowired
    public ExpenseDao(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public ExpenseDao() {
    }

    @Override
    @Transactional
    public Expenses saveExpense(Expenses expense) {
        return entityManager.merge(expense);
    }

    @Override
    public List<Expenses> getAll() {
        TypedQuery<Expenses> query = entityManager.createQuery("FROM Expenses", Expenses.class);

        return query.getResultList();
    }

    @Override
    public Expenses expense(int id) {
        return entityManager.find(Expenses.class, id);
    }

    @Override
    @Transactional
    public void deleteExpense(int id) {

        Expenses expense = expense(id);
        entityManager.remove(expense);
    }

}

UserController:

package com.expense_tracker.expenseTracker.Controllers;

//imports

@RestController
@RequestMapping("/expense-tracker")
public class UserController {

    private UserDao userDao;
    
    public UserController(UserDao userDao) {
        this.userDao = userDao;
    }

    @GetMapping("/users/{uid}")
    Users getCurrentUser(@PathVariable int uid) {
        return userDao.getUser(uid);
    }

    @PutMapping("/users")
    Users updateCurrentUser(@RequestBody Users users) {
        return userDao.updateUsers(users);
    }

    @PostMapping("/users")
    String createUser(@RequestBody Users users) {
        return userDao.creatUsers(users);
    }

    @DeleteMapping("/users/{uid}")
    String deleteCurrentUser(@PathVariable int uid) {
        return userDao.deleteUser(uid);
    }

}

ExpensesController:

package com.expense_tracker.expenseTracker.Controllers;

//imports

@RestController
@RequestMapping("/expense-tracker")
public class ExpenseController {

    private ExpenseDao expenseDao;

    public ExpenseController(ExpenseDao expenseDao) {
        this.expenseDao = expenseDao;
    }

    @GetMapping("/expense")
    private List<Expenses> get() {
        return expenseDao.getAll();
    }

    @PostMapping("/expense")
    private Expenses post(@RequestBody Expenses expense) {
        expense.setId(0);
        return expenseDao.saveExpense(expense);
    }

    @GetMapping("/expense/{expenseId}")
    private Expenses getSingleExpense(@PathVariable int expenseId) {
        return expenseDao.expense(expenseId);
    }

    @PutMapping("/expense")
    private Expenses update(@RequestBody Expenses expense) {
        return expenseDao.saveExpense(expense);
    }

    @DeleteMapping("/expense/{expenseId}")
    private String delete(@PathVariable int expenseId) {
        Expenses temp = expenseDao.expense(expenseId);

        if (temp == null) {
            throw new RuntimeErrorException(null, "Expense with id" + expenseId + "not found");
        }
        expenseDao.deleteExpense(expenseId);
        return "Succesfully deleted";
    }
}

Exception (After sending DELETE Request):

Url to which request was sent :(http://localhost:8080/expense-tracker/users/3)

ERROR 31159 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.dao.InvalidDataAccessApiUsageException: Unable to locate persister: java.lang.Integer] with root cause

org.hibernate.UnknownEntityTypeException: Unable to locate persister: java.lang.Integer
        at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.getEntityDescriptor(MappingMetamodelImpl.java:392) ~[hibernate-core-6.2.9.Final.jar:6.2.9.Final]
        at org.hibernate.internal.SessionImpl.getEntityPersister(SessionImpl.java:1484) ~[hibernate-core-6.2.9.Final.jar:6.2.9.Final]
        at org.hibernate.event.internal.DefaultDeleteEventListener.deleteTransientInstance(DefaultDeleteEventListener.java:168) ~[hibernate-core-6.2.9.Final.jar:6.2.9.Final]
        at org.hibernate.event.internal.DefaultDeleteEventListener.delete(DefaultDeleteEventListener.java:156) ~[hibernate-core-6.2.9.Final.jar:6.2.9.Final]
        at org.hibernate.event.internal.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:95) ~[hibernate-core-6.2.9.Final.jar:6.2.9.Final]
        at org.hibernate.event.internal.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:83) ~[hibernate-core-6.2.9.Final.jar:6.2.9.Final]
        at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127) ~[hibernate-core-6.2.9.Final.jar:6.2.9.Final]
        at org.hibernate.internal.SessionImpl.fireDelete(SessionImpl.java:961) ~[hibernate-core-6.2.9.Final.jar:6.2.9.Final]
        at org.hibernate.internal.SessionImpl.delete(SessionImpl.java:892) ~[hibernate-core-6.2.9.Final.jar:6.2.9.Final]
        at org.hibernate.internal.SessionImpl.remove(SessionImpl.java:2359) ~[hibernate-core-6.2.9.Final.jar:6.2.9.Final]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
        at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) ~[spring-orm-6.0.12.jar:6.0.12]
        at jdk.proxy4/jdk.proxy4.$Proxy112.remove(Unknown Source) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
        at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311) ~[spring-orm-6.0.12.jar:6.0.12]
        at jdk.proxy4/jdk.proxy4.$Proxy112.remove(Unknown Source) ~[na:na]
        at com.expense_tracker.expenseTracker.Dao.UserDao.UserDao.deleteUser(UserDao.java:58) ~[classes/:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-6.0.12.jar:6.0.12]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.0.12.jar:6.0.12]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-6.0.12.jar:6.0.12]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.12.jar:6.0.12]
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-6.0.12.jar:6.0.12]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.12.jar:6.0.12]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.12.jar:6.0.12]
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-6.0.12.jar:6.0.12]
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:391) ~[spring-tx-6.0.12.jar:6.0.12]
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-6.0.12.jar:6.0.12]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.12.jar:6.0.12]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.12.jar:6.0.12]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) ~[spring-aop-6.0.12.jar:6.0.12]
        at com.expense_tracker.expenseTracker.Dao.UserDao.UserDao$$SpringCGLIB$$0.deleteUser(<generated>) ~[classes/:na]
        at com.expense_tracker.expenseTracker.Controllers.UserController.deleteCurrentUser(UserController.java:41) ~[classes/:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-6.0.12.jar:6.0.12]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-6.0.12.jar:6.0.12]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.0.12.jar:6.0.12]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) ~[spring-webmvc-6.0.12.jar:6.0.12]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-6.0.12.jar:6.0.12]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.0.12.jar:6.0.12]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081) ~[spring-webmvc-6.0.12.jar:6.0.12]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974) ~[spring-webmvc-6.0.12.jar:6.0.12]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011) ~[spring-webmvc-6.0.12.jar:6.0.12]
        at org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:936) ~[spring-webmvc-6.0.12.jar:6.0.12]
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:596) ~[tomcat-embed-core-10.1.13.jar:6.0]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.0.12.jar:6.0.12]
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.13.jar:6.0]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.13.jar:10.1.13]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.0.12.jar:6.0.12]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.12.jar:6.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.0.12.jar:6.0.12]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.12.jar:6.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.0.12.jar:6.0.12]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.12.jar:6.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1740) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-10.1.13.jar:10.1.13]
        at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

Database Schema:

enter image description here

Every other endpoint works,even a single expense can be deleted but when I want to delete an user it throws me an exception.

I am new to spring boot I would also love some insights on my code by some of you about what I am doing wrong in code,about my logic,etc.

One last question how should I save a single expense for a particular user,currently I am adding user_id manually in json when storing an expense.

I have tried creating new spring boot project,Dropped DB and recreated it,Checked all dependencies,removed JPA advance mapping(one to many and vice versa relations).

3

There are 3 answers

0
Musab Shaikh On BEST ANSWER

As @chris metioned in comments the expenses must be deleted before the user is deleted otherwise there will be a constraint violation.It can be achieved by manually setting user of (user_id foreign key) in exepense to null or in my case the entityManager.remove(id) should be entityManager.remove(temp)

3
Abdelghani On

The solution is to delete the expenses of the user, before deleting the user, this is caused by the relation between the two entities.

There an better solution is to use the DETACH cascade type, so the Object user and the expenses will be detached, and you can delete the user safely, with no need to delete the expenses, you need just to change this attribute in the entity user:

@OneToMany(mappedBy = "user", cascade = CascadeType.DETACH, fetch = FetchType.EAGER)private List<Expenses> expenses;
0
phuongnq1995 On

You should call entityManager.remove(user); instead of entityManager.remove(id); Entity Manager requires the entity instance not the id.