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
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
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
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;
}
}
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);
}
}
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);
}
}
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";
}
}
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]
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).
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)