I've below domain model objects, with below DDL and spring version, when i try to fetch the complete aggregate (just two entities) with my custom sql, spring-data returns below error.
when I remove the aggregate definition( i.e, remove the AppUsersAuth entity from my root Entity AppUsers, this method isEmailRegistered(String Email) works fine.
So I'm thinking that either i don't have my aggregates defined correctly or my DDL or hitting a blocker in spring-data-jdbc.
Any help, suggestion on this will be much appreciated.
spring boot = 2.2.5-RELEASE
spring-data-releasetrain.version =Moore-SR5
spring-boot-starter-data-jdbc = 2.1.0.RELEASE
#Table("APPUSERS")
#Data #AllArgsConstructor #NoArgsConstructor
public class AppUsers implements Serializable {
private #Id
Long userid;
private String username;
#Column(value = "first_name")
private String firstName;
#Column(value = "last_name")
private String lastName;
private String email;
#Column(value = "phone_number")
private String phoneNumber;
private boolean active;
private boolean disabled;
private boolean verified;
private boolean locked;
private String zipcode;
private String password;
#Column(value = "registered_date")
private LocalDateTime registeredDate;
#Column(value = "registered_date")
private LocalDateTime lastModified;
private List<AppUsersAuth> appUsersAuthList = new ArrayList<>();
}
#Table("appusers_auth")
#Data
class AppUsersAuth {
#Column("auth_user_id")
private long authUserId;
#Column("userid")
private Long userid;
private String email;
#Column("role_id")
private String roleId;
#Column("username")
private String username;
#Column("updated_time")
private Date updatedTime;
}
```
The DDL for these are:
```CREATE TABLE APPUSERS(
userid bigserial PRIMARY KEY,
username text not null unique ,
password text not null,
first_name text not null unique ,
last_name text not null,
zipcode text not null,
email text not null unique
}
CREATE TABLE appusers_auth (
auth_user_id bigserial not null ,
userid bigserial ,
username text,
email text,
role_id VARCHAR(50),
updated_time timestamp default CURRENT_TIMESTAMP,
primary key (auth_user_id),
CONSTRAINT FK_APPUSERS_AUTH_APPUSER foreign key (userid,username,email) references APPUSERS(userid,username,email)
);```
isEmailRegistered(String email) is a method in service which call findByEmail(String email)
#Repository
public interface AppUsersRepository extends CrudRepository<AppUsers, Long> {
#Query("select * from APPUSERS where upper(email) = upper(:email) ")
AppUsers findByEmail(#Param("email") String email);
.......
}
01:01:08.120 [https-jsse-nio-8585-exec-10] DEBUG o.s.jdbc.core.JdbcTemplate - Executing prepared SQL statement [SELECT appusers_auth.email AS email, appusers_auth.role_id AS role_id, appusers_auth.userid AS userid, appusers_auth.username AS username, appusers_auth.auth_user_id AS auth_user_id, appusers_auth.updated_time AS updated_time, appusers_auth.APPUSERS_key AS APPUSERS_key FROM appusers_auth WHERE appusers_auth.app_users = ? ORDER BY APPUSERS_key]
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT appusers_auth.email AS email, appusers_auth.role_id AS role_id, appusers_auth.userid AS userid, appusers_auth.username AS username, appusers_auth.auth_user_id AS auth_user_id, appusers_auth.updated_time AS updated_time, appusers_auth.APPUSERS_key AS APPUSERS_key FROM appusers_auth WHERE appusers_auth.app_users = ? ORDER BY APPUSERS_key]; nested exception is org.postgresql.util.PSQLException: ERROR: column appusers_auth.appusers_key does not exist
Position: 228
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:101)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1443)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:669)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:694)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:748)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:216)
at org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy.findAllByPath(DefaultDataAccessStrategy.java:282)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205)
at com.sun.proxy.$Proxy109.findAllByPath(Unknown Source)
at org.springframework.data.jdbc.core.convert.BasicJdbcConverter$ReadingContext.resolveRelation(BasicJdbcConverter.java:360)
at org.springframework.data.jdbc.core.convert.BasicJdbcConverter$ReadingContext.readOrLoadProperty(BasicJdbcConverter.java:338)
at org.springframework.data.jdbc.core.convert.BasicJdbcConverter$ReadingContext.populateProperties(BasicJdbcConverter.java:327)
at org.springframework.data.jdbc.core.convert.BasicJdbcConverter$ReadingContext.createInstanceInternal(BasicJdbcConverter.java:463)
at org.springframework.data.jdbc.core.convert.BasicJdbcConverter$ReadingContext.mapRow(BasicJdbcConverter.java:312)
at org.springframework.data.jdbc.core.convert.BasicJdbcConverter.mapRow(BasicJdbcConverter.java:252)
at org.springframework.data.jdbc.core.convert.EntityRowMapper.mapRow(EntityRowMapper.java:67)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61)
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:679)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:669)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:694)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:748)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:236)
at org.springframework.data.jdbc.repository.support.JdbcRepositoryQuery.lambda$createObjectRowMapperQueryExecutor$4(JdbcRepositoryQuery.java:178)
at org.springframework.data.jdbc.repository.support.JdbcRepositoryQuery.lambda$createObjectQueryExecutor$0(JdbcRepositoryQuery.java:135)
at org.springframework.data.jdbc.repository.support.JdbcRepositoryQuery.execute(JdbcRepositoryQuery.java:124)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:618)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:605)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:366)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy120.findByEmail(Unknown Source)
at com.rajesh.transcribe.transribeapi.api.services.JwtUserDetailsService.isEmailRegistered(JwtUserDetailsService.java:356)
at com.rajesh.transcribe.transribeapi.api.controller.JwtAuthenticationController.createAuthenticationToken(JwtAuthenticationController.java:98)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.rajesh.transcribe.transribeapi.api.filters.JwtRequestFilter.doFilterInternal(JwtRequestFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:209)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:666)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:688)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.postgresql.util.PSQLException: ERROR: column appusers_auth.appusers_key does not exist
I was able resolve this usecase (aggregate with just two entities) by using the #MappedCollection with attributes IdColumn and KeyColumn defined.
and changing the Java Type from String to Long for property strong text
complete code after changes:
#Table("APPUSERS")
#Data #AllArgsConstructor #NoArgsConstructor
public class AppUsers implements Serializable {
private #Id
Long userid;
private String username;
#Column(value = "first_name")
private String firstName;
#Column(value = "last_name")
private String lastName;
private String email;
#Column(value = "phone_number")
private String phoneNumber;
private boolean active;
private boolean disabled;
private boolean verified;
private boolean locked;
private String zipcode;
private String password;
#Column(value = "registered_date")
private LocalDateTime registeredDate;
#Column(value = "registered_date")
private LocalDateTime lastModified;
#MappedCollection(idColumn="userid", keyColumn="userid")
private Set<AppUsersAuth> appUsersAuthList ;
}
#Table("appusers_auth")
#Data
public class AppUsersAuth {
#Column("auth_user_id")
private Long authUserId;
#Column("userid")
private Long userid;
private String email;
#Column("role_id")
private String roleId;
#Column("username")
private String username;
#Column("updated_time")
private Date updatedTime;
}
public interface AppUsersRepository extends CrudRepository<AppUsers, Long> {
#Query("select * from APPUSERS where upper(email) = upper(:email) ")
AppUsers findByEmail(#Param("email") String email);
}
#Service
public class JwtUserDetailsService implements UserDetailsService {
/**
* This method will validate if the given email is registered.
* #param email
* #return
*/
public boolean isEmailRegistered(String email){
boolean isRegistered = false;
Optional<AppUsers> appUsers = Optional.ofNullable(userRepo.findByEmail(email));
if(!appUsers.isEmpty() && !appUsers.get().isDisabled()){
isRegistered = true;
} else {
isRegistered = false;
}
return isRegistered;
}
}
Related
I am having an issue with a bidirectional mapping. and when I try to post or get I get a error class site cant be serialized. if I take away the mappedby in the site then it works just fine and take always the site field in the inventory it will work is that the right way?
11:24:52.341 [main] INFO - in 3.977 seconds (JVM running for 4.471)
11:25:36.453 [http-nio-8080-exec-2] INFO com.cbcse.controller.SiteController - I Fell in here
11:25:36.533 [http-nio-8080-exec-2] WARN com.cbcse.service.SiteServiceImpl - Handling of [org.springframework.transaction.TransactionSystemException] resulted in Exception
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:571)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:407)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at jdk.proxy2/jdk.proxy2.$Proxy107.save(Unknown Source)
at com.cbcse.service.SiteServiceImpl.add(SiteServiceImpl.java:71)
at com.cbcse.controller.SiteController.add(SiteController.java:53)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:81)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:562)
... 66 common frames omitted
Caused by: java.lang.ClassCastException: class com.cbcse.entity.Site cannot be cast to class java.io.Serializable (com.cbcse.entity.Site is in unnamed module of loader 'app'; java.io.Serializable is in module java.base of loader 'bootstrap')
at org.hibernate.type.CollectionType.getKeyOfOwner(CollectionType.java:446)
at org.hibernate.engine.internal.Collections.processReachableCollection(Collections.java:166)
at org.hibernate.event.internal.FlushVisitor.processCollection(FlushVisitor.java:53)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65)
at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:183)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:229)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:93)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1416)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:507)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3299)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2434)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:449)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
... 67 common frames omitted
#Entity
public class Site {
#Id
#GeneratedValue
Long id;
String name;
String date;
String suite;
String unit;
long siteId;
#OneToMany( mappedBy="sites", fetch = FetchType.LAZY ,cascade = {CascadeType.MERGE,CascadeType.REFRESH},orphanRemoval = true)
List<Inventory> inventory = new ArrayList<>();
// #OneToMany(fetch = FetchType.LAZY ,cascade = CascadeType.ALL,orphanRemoval = true)
// List<SiteFiles> siteFiles = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSiteName() {
return name;
}
public void setSiteName(String name) {
this.name = name;
}
public String getSiteDate() {
return date;
}
public void setSiteDate(String date) {
this.date = date;
}
public String getSiteSuite() {
return suite;
}
public void setSiteSuite(String suite) {
this.suite = suite;
}
public String getSiteUnit() {
return unit;
}
public void setSiteUnit(String unit) {
this.unit = unit;
}
public Long getSiteId() {
return siteId;
}
public void setSiteId(Long siteId) {
this.siteId = siteId;
}
public List<Inventory> getInventory() {
return inventory;
}
public void setInventory(List<Inventory> inventory) {
this.inventory = inventory;
}
}
#Entity
public class Inventory {
#Id
#GeneratedValue
Long id;
Long parentId;
#ManyToOne(fetch = FetchType.LAZY ,cascade = {CascadeType.MERGE,CascadeType.REFRESH})
#JoinColumn(name = "parentId", referencedColumnName = "siteId",insertable= false, updatable= false)
private Site sites;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Site getSites() {
return sites;
}
public void setSites(Site sites) {
this.sites = sites;
}
}
I have three entities Blog, Comments, ParentChildComment.
Comment is mapped using ManyToOne relationship to Blog.
ParentChildComment has two columns to store id value of parent_comment and child_comment (this is done to store the info regarding which comment is a reply to another one) and both these columns are mapped using OneToOne relationship to Comment table which I guess is the sourcee of problem.
PROBLEM
When deleting a blog, comments are deleted due to cascade delete, but the parent_child table is still referncing to table comments which throw error org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [fkf3i44d11sgikshmo17q4fq1a4]; nested exception is org.hibernate.exception.ConstraintViolationException
The whole trace :
SQL Error: 0, SQLState: 23503
2021-05-19 22:31:07.123 ERROR 16445 --- [nio-8080-exec-6] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: update or delete on table "comments" violates foreign key constraint "fkf3i44d11sgikshmo17q4fq1a4" on table "parent_child_comment"
Detail: Key (id)=(4) is still referenced from table "parent_child_comment".
2021-05-19 22:31:07.124 INFO 16445 --- [nio-8080-exec-6] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
2021-05-19 22:31:07.133 ERROR 16445 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [fkf3i44d11sgikshmo17q4fq1a4]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
org.postgresql.util.PSQLException: ERROR: update or delete on table "comments" violates foreign key constraint "fkf3i44d11sgikshmo17q4fq1a4" on table "parent_child_comment"
Detail: Key (id)=(4) is still referenced from table "parent_child_comment".
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2553) ~[postgresql-42.2.19.jar:42.2.19]
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2285) ~[postgresql-42.2.19.jar:42.2.19]
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:323) ~[postgresql-42.2.19.jar:42.2.19]
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:481) ~[postgresql-42.2.19.jar:42.2.19]
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:401) ~[postgresql-42.2.19.jar:42.2.19]
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:164) ~[postgresql-42.2.19.jar:42.2.19]
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:130) ~[postgresql-42.2.19.jar:42.2.19]
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61) ~[HikariCP-3.4.5.jar:na]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java) ~[HikariCP-3.4.5.jar:na]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3614) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3874) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:123) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[na:na]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:345) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:93) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1362) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:453) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3212) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2380) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:562) ~[spring-orm-5.3.6.jar:5.3.6]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743) ~[spring-tx-5.3.6.jar:5.3.6]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711) ~[spring-tx-5.3.6.jar:5.3.6]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654) ~[spring-tx-5.3.6.jar:5.3.6]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:407) ~[spring-tx-5.3.6.jar:5.3.6]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.6.jar:5.3.6]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.6.jar:5.3.6]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.6.jar:5.3.6]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.6.jar:5.3.6]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174) ~[spring-data-jpa-2.4.8.jar:2.4.8]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.6.jar:5.3.6]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.6.jar:5.3.6]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.6.jar:5.3.6]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.6.jar:5.3.6]
at com.sun.proxy.$Proxy116.deleteById(Unknown Source) ~[na:na]
at com.rv02.evolvFit.Controller.deleteBlog(Controller.java:47) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[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:566) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197) ~[spring-web-5.3.6.jar:5.3.6]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141) ~[spring-web-5.3.6.jar:5.3.6]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.6.jar:5.3.6]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.6.jar:5.3.6]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.6.jar:5.3.6]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.6.jar:5.3.6]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060) ~[spring-webmvc-5.3.6.jar:5.3.6]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962) ~[spring-webmvc-5.3.6.jar:5.3.6]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.6.jar:5.3.6]
at org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:931) ~[spring-webmvc-5.3.6.jar:5.3.6]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-9.0.45.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.6.jar:5.3.6]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.45.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.45.jar:9.0.45]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.6.jar:5.3.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.6.jar:5.3.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.6.jar:5.3.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.6.jar:5.3.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93) ~[spring-boot-actuator-2.4.5.jar:2.4.5]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.6.jar:5.3.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.6.jar:5.3.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.6.jar:5.3.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.45.jar:9.0.45]
at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]
Relevant code blocks :
Blog.java
package com.rv02.evolvFit;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
#Entity
#Table(name = "Blogs")
public class Blog {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
private int id;
#Column
#NotBlank(message = "title is required")
private String title;
#Column
#NotBlank(message = "Post text is required")
private String text;
#OneToMany(mappedBy = "blog", cascade =
{CascadeType.PERSIST, CascadeType.REMOVE},
orphanRemoval = true, fetch = FetchType.LAZY)
private List<Comment> comments;
public Blog() {
this.comments = new ArrayList<>();
}
public Blog(int id, String title, String text, List<Comment> comments) {
this.id = id;
this.title = title;
this.text = text;
this.comments = comments;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
}
Comment.java
package com.rv02.evolvFit;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
#Entity
#Table(name = "Comments")
public class Comment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
private int id;
#Column
#NotBlank(message = "comment cannot be blank")
private String text;
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "blog_id")
private Blog blog;
public Comment(int id, String text, Blog blog) {
this.id = id;
this.text = text;
this.blog = blog;
}
public Comment() {
}
public Comment(String text, Blog blog) {
this.text = text;
this.blog = blog;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Blog getBlog() {
return blog;
}
public void setBlog(Blog blog) {
this.blog = blog;
}
}
ParentChildComment.java
package com.rv02.evolvFit;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
#Entity
#Table(name = "Parent_Child_Comment")
public class ParentChildComment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonIgnore
private int id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "parent_comment_id", referencedColumnName = "id")
private Comment parentCommentID;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "child_comment_id", referencedColumnName = "id")
private Comment childCommentID;
public ParentChildComment(Comment parentCommentID, Comment childCommentID) {
this.parentCommentID = parentCommentID;
this.childCommentID = childCommentID;
}
public Comment getParentCommentID() {
return parentCommentID;
}
public void setParentCommentID(Comment parentCommentID) {
this.parentCommentID = parentCommentID;
}
public Comment getChildCommentID() {
return childCommentID;
}
public void setChildCommentID(Comment childCommentID) {
this.childCommentID = childCommentID;
}
}
Delete Blog Function
#DeleteMapping(path = "/blogs/{id}")
public Blog deleteBlog(#PathVariable int id) {
Blog blog = blogRepository.findById(id)
.orElseThrow(DataNotFoundException::new);
blogRepository.deleteById(id);
return blog;
}
Code blocks added/modified to make it work
Adding a custom function to ParentChildComment repository
#Query(
value = "select * from PARENT_CHILD_COMMENT where PARENT_COMMENT_ID in (select id from COMMENTS where BLOG_ID = ?1)",
nativeQuery = true
)
List<ParentChildComment> findBlogCommentRelationships(int id);
Modified deleteBlog()
#DeleteMapping(path = "/blogs/{id}")
public Blog deleteBlog(#PathVariable int id) {
Blog blog = blogRepository.findById(id)
.orElseThrow(DataNotFoundException::new);
parentChildCommentRepository.deleteAll(
parentChildCommentRepository.findBlogCommentRelationships(id)
);
blogRepository.deleteById(id);
return blog;
}
before invoking blogRepository.deleteById you should delete also ParentChildComment whose comments are in the Blog's collection of comments.
I'm coding an API that connects an online db to an android app and have gotten stuck on how to create a DTO that takes data from 3 tables that are connected with each other.
It's the first API I'm coding and I'm still trying to learn good practices so any suggestions are welcome.
I've reached the point where I really don't know where else to look for an answer, since all the answers I find are explaining how to use a query to take data from a single table(might be searching for it using the wrong terminology since I'm not a native English speaker)
These are the entities I create in the API:
Employees
#Entity
#Table(name = "employees")
public class Employees {
#Id
#Column(name = "eid")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int eid;
#Column(name = "first_name")
private String first_name;
#Column(name = "last_name")
private String last_name;
#Column(name = "birth_date")
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date birth_date;
#Column(name = "jid")
private int jid;
//Getters setters constructors
}
Jobs
#Entity
#Table(name = "jobs")
public class Jobs {
#Id
#Column(name = "jid")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int jid;
#Column(name = "job_name")
private String job_name;
//Getters setters constructors
}
Credentials
#Entity
#Table(name = "credentials")
#IdClass(CredentialsCID.class)
public class Credentials {
#Id
#Column(name = "username")
private String username;
#Id
#Column(name = "is_admin")
private byte is_admin;
#Column(name = "password")
private String password;
#Column(name = "eid")
private int eid;
//Getters setters constructors
}
And this is the dto class
EmployeesCustomDTO
package com.example.accessingdatamysql.dto;
import com.example.accessingdatamysql.model.Contracts;
import com.example.accessingdatamysql.model.Credentials;
import com.example.accessingdatamysql.model.Employees;
public class EmployeesCustomDTO {
private int eid;
private String first_name;
private String last_name;
private String jid;
private int hours;
private String type;
private byte is_admin;
public EmployeesCustomDTO() {
}
public EmployeesCustomDTO(int eid, String first_name, String last_name, String jid, int hours, String type, byte is_admin) {
this.eid = eid;
this.first_name = first_name;
this.last_name = last_name;
this.jid = jid;
this.hours = hours;
this.type = type;
this.is_admin = is_admin;
}
public int getEid() {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
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 getJob_name() {
return jid;
}
public void setJob_name(String job_name) {
this.jid = job_name;
}
public int getHours() {
return hours;
}
public void setHours(int hours) {
this.hours = hours;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public byte getIs_admin() {
return is_admin;
}
public void setIs_admin(byte is_admin) {
this.is_admin = is_admin;
}
public EmployeesCustomDTO convertToDTO(Employees employees, Credentials credentials, Contracts contracts){
EmployeesCustomDTO employeesCustomDTO = new EmployeesCustomDTO();
employeesCustomDTO.setEid(employees.getEid());
employeesCustomDTO.setFirst_name(employees.getFirst_name());
employeesCustomDTO.setLast_name(employees.getLast_name());
employeesCustomDTO.setJob_name(String.valueOf(employees.getJid())); // TODO: 19/12/2020 check if correct
employeesCustomDTO.setType(contracts.getType());
employeesCustomDTO.setHours(contracts.getHours());
employeesCustomDTO.setIs_admin(credentials.getIs_admin());
return employeesCustomDTO;
}
}
Then I added the following query to the EmployeesRepo (which works as I want it to when I try it on MySQL workbench)
#Repository
public interface EmployeesRepo extends JpaRepository<Employees, Integer> {
#Query(value = "SELECT employees.eid,employees.first_name,employees.last_name,employees.jid,contracts.hours,contracts.type,credentials.is_admin " +
"FROM employees,credentials,contracts " +
"WHERE employees.eid = credentials.eid AND contracts.eid = employees.eid", nativeQuery = true)
List<EmployeesCustomDTO> getCustomErgazomenoi();
}
and the following method in its service
#Override
public List<EmployeesCustomDTO> getCustomErgazomenoi() {
return employeesRepo.getCustomErgazomenoi();
}
which I then call in the controller
#GetMapping("/custom-employees")
public List<EmployeesCustomDTO> getAllCustomEmployees(){return employeesService.getCustomErgazomenoi();}
When I send the request to the endpoint I get the following error:
From Postman:
{
"timestamp": "2020-12-22T16:40:28.542+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "",
"path": "/employees/custom-employees"
}
From the terminal in intellij
2020-12-22 18:40:28.527 ERROR 2948 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.core.co
nvert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.example.accessingdatamysql.dto.EmployeesCustomDTO]] with root cause
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.example.accessingdatamysql.dto.EmployeesCusto
mDTO]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322) ~[spring-core-5.3.1.jar:5.3.1]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-5.3.1.jar:5.3.1]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175) ~[spring-core-5.3.1.jar:5.3.1]
at org.springframework.data.repository.query.ResultProcessor$ProjectingConverter.convert(ResultProcessor.java:309) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:225) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:236) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:156) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:158) ~[spring-data-jpa-2.4.1.jar:2.4.1]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:143) ~[spring-data-jpa-2.4.1.jar:2.4.1]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:152) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:131) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.4.1.jar:2.4.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:371) ~[spring-tx-5.3.1.jar:5.3.1]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:134) ~[spring-tx-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:145) ~[spring-data-jpa-2.4.1.jar:2.4.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.1.jar:5.3.1]
at com.sun.proxy.$Proxy120.getCustomErgazomenoi(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:62) ~[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:564) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.1.jar:5.3.1]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.1.jar:5.3.1]
at com.sun.proxy.$Proxy77.getCustomErgazomenoi(Unknown Source) ~[na:na]
at com.example.accessingdatamysql.services.impl.EmployeesServiceImpl.getCustomErgazomenoi(EmployeesServiceImpl.java:45) ~[classes/:na]
at com.example.accessingdatamysql.controllers.EmployeesController.getAllCustomEmployees(EmployeesController.java:28) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[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:564) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197) ~[spring-web-5.3.1.jar:5.3.1]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141) ~[spring-web-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:807) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1061) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:961) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.1.jar:5.3.1]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.1.jar:5.3.1]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.39.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.1.jar:5.3.1]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.39.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.1.jar:5.3.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar:5.3.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.1.jar:5.3.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar:5.3.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.1.jar:5.3.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar:5.3.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]
Even though I've found some answers on how to fix this problem I can't seem to get it to work on my API. Any suggestions?
Can you provide the code for EmployeesCustomDTO class? It looks like you are trying to perform a DTO projection which would require you to map the SQL result to the properties in the DTO.
If you are using hibernate you can create an appropriate constructor on the DTO and update query to use the new constructor:
#Query(value = "SELECT com.example.accessingdatamysql.dto.EmployeesCustomDTO(employees.eid,employees.first_name,employees.last_name,employees.jid,contracts.hours,contracts.type,credentials.is_admin) " +
"FROM employees,credentials,contracts " +
"WHERE employees.eid = credentials.eid AND contracts.eid = employees.eid")
List<EmployeesCustomDTO> getCustomErgazomenoi();
For a detailed explanation see - https://vladmihalcea.com/the-best-way-to-map-a-projection-query-to-a-dto-with-jpa-and-hibernate/
Either way, you must provide the mapping from the SQL result set to your DTOs properties. If you are following standard naming conventions in SQL and Java the names are likely not identical - e.g. your query references first_name but I assume your DTO will be firstName.
Looks like you can also provide the mapping via #SqlResultSetMapping if you are using native queries: https://thorben-janssen.com/dto-projections/#DTO_projections_for_native_SQL_queries
Similar Stackoverflow post:
Spring JPA native query with Projection gives "ConverterNotFoundException"
I'm trying to build a question answer website like Stack Overflow, to learn how RESTful web services work, it is my first time writing web services, I have already made the controller for asking the questions and answering them.
But there's a problem, which I had when I was making a REST Endpoint for the upvote, so whenever a user upvotes a question, I have to update the number of votes a question has in the questions table (at the start it is zero) but when I'm trying to hit the Endpoint for Upvote the update query which I have written throws an error and shows me the error page.
The error thrown:
org.postgresql.util.PSQLException: No results were returned by the query.
at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:107) ~[postgresql-42.2.5.jar:42.2.5]
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52) ~[HikariCP-3.2.0.jar:na]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java) ~[HikariCP-3.2.0.jar:na]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:60) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.loader.Loader.getResultSet(Loader.java:2167) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1930) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1892) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.loader.Loader.doQuery(Loader.java:937) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:340) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.loader.Loader.doList(Loader.java:2689) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.loader.Loader.doList(Loader.java:2672) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2506) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.loader.Loader.list(Loader.java:2501) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:338) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2223) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1069) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:170) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1505) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1553) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:221) ~[spring-data-jpa-2.1.9.RELEASE.jar:2.1.9.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91) ~[spring-data-jpa-2.1.9.RELEASE.jar:2.1.9.RELEASE]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:136) ~[spring-data-jpa-2.1.9.RELEASE.jar:2.1.9.RELEASE]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125) ~[spring-data-jpa-2.1.9.RELEASE.jar:2.1.9.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) ~[spring-data-jpa-2.1.9.RELEASE.jar:2.1.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at com.sun.proxy.$Proxy100.vote(Unknown Source) ~[na:na]
at com.demo.beans.controller.QuestionController.upvoteQuestion(QuestionController.java:222) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) ~[spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) ~[spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:151) ~[spring-session-core-2.1.7.RELEASE.jar:2.1.7.RELEASE]
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:85) ~[spring-session-core-2.1.7.RELEASE.jar:2.1.7.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.21.jar:9.0.21]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_91]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_91]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.21.jar:9.0.21]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91]
Code for the QuestionRepository which is used to update the votes:
package com.demo.beans.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.demo.beans.Question;
#Repository
public interface QuestionRepository extends JpaRepository<Question, Long> {
#Query(value = "SELECT * from questions where pr_key=:pr_key", nativeQuery = true)
public Question findByPrKey(#Param("pr_key") String prKey);
#Query(value = "UPDATE questions SET questionvotes=:questionvotes where pr_key=:pr_key", nativeQuery=true)
public void changeVotes(#Param("questionvotes") int questionVotes, #Param("pr_key") String prKey);
}
Here the second query is responsible for updating the votes.
I'm calling this function in the QuestionsController in this method:
#RequestMapping("/upvoteQuestion")
public String upvoteQuestion(#CookieValue(value = "username", defaultValue = "null") String username,
#CookieValue(value = "password", defaultValue = "null") String password, #Valid QuestionVote questionVote) {
System.out.println("works" + questionVote.getQuestionPrKey() + " " + questionVote.getUserPrKey());
if (!username.equals("null") && !password.equals("null")) {
// checks whether there is user with the username and password given
// by the cookie
if (userRepository.checkWhetherAccountExists(username, password).get(0) != null) {
questionVote.setUserPrKey(userRepository.findUsingUsername(username).getPrKey());
if (questionVoteRepository.checkUpvote(questionVote.getQuestionPrKey(), questionVote.getUserPrKey()).equals("false")) {
questionVoteRepository.vote("true", "false", questionVote.getQuestionPrKey(),questionVote.getUserPrKey());
System.out.println("Question PrKey: " + questionVote.getQuestionPrKey());
questionRepository.changeVotes(13, questionVote.getQuestionPrKey());
}
}
}
return "redirect:/questions/"+questionVote.getQuestionPrKey();
}
In the above code, the following line throws the error:
questionRepository.changeVotes(13, questionVote.getQuestionPrKey());
My Question class looks like this:
package com.demo.beans;
import java.sql.Time;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
#Entity
#Table(name = "questions")
public class Question {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "PR_KEY")
private String prKey;
#Column(name = "postedby")
private String postedBy; // pr_key of the person who posted the question
#Column(name = "postedbyusername")
private String postedByUsername; // username of the person who posted the
// question
#Column(name = "title", columnDefinition = "varchar(1000)")
private String title; // title of the question
#Column(name = "content", columnDefinition = "varchar(10000)")
private String content; // content of the question
#Column(name = "code", columnDefinition = "varchar(10000)")
private String code; // code (if included) of the question
#Column(name = "viewscount")
private int views_count; // views count of the question
#Column(name = "answercount")
private int answer_count; // answers count of the question
#Column(name = "tag")
private String tag; // tag which a question is tagged
#Column(name = "questionaskedtime")
private String questionAskedTime; // time at which the question was asked
#Column(name = "questionlastactivetime")
private String questionLastActiveTime; // time at which the question was
// active the last time
#Column(name = "questionvotes")
private int questionVotes; // number of votes on the question
#Column(name = "acceptedanswerstatus")
private String acceptedAnswerStatus; // whether the question has an accepted
// answer
#Column(name = "questionlink")
private String questionLink;
public Question() {
}
public Question(String postedBy, String title, String content, String code, int views_count, int answer_count,
String tag, String questionAskedTime, String questionLastActiveTime, int questionVotes,
String acceptedAnswerStatus, String questionLink, String postedByUsername) {
super();
this.title = title;
this.content = content;
this.code = code;
this.views_count = views_count;
this.answer_count = answer_count;
this.tag = tag;
this.questionAskedTime = questionAskedTime;
this.questionLastActiveTime = questionLastActiveTime;
this.questionVotes = questionVotes;
this.acceptedAnswerStatus = acceptedAnswerStatus;
this.questionLink = questionLink;
this.postedByUsername = postedByUsername;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public int getViews_count() {
return views_count;
}
public void setViews_count(int views_count) {
this.views_count = views_count;
}
public int getAnswer_count() {
return answer_count;
}
public void setAnswer_count(int answer_count) {
this.answer_count = answer_count;
}
public String getTags() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getQuestionAskedTime() {
return questionAskedTime;
}
public void setQuestionAskedTime(String questionAskedTime) {
this.questionAskedTime = questionAskedTime;
}
public String getQuestionLastActiveTime() {
return questionLastActiveTime;
}
public void setQuestionLastActiveTime(String questionLastActiveTime) {
this.questionLastActiveTime = questionLastActiveTime;
}
public int getQuestionVotes() {
return questionVotes;
}
public void setQuestionVotes(int questionVotes) {
this.questionVotes = questionVotes;
}
public String getAcceptedAnswerStatus() {
return acceptedAnswerStatus;
}
public void setAcceptedAnserStatus(String acceptedAnswerStatus) {
this.acceptedAnswerStatus = acceptedAnswerStatus;
}
public String getPrKey() {
return prKey;
}
public void setPrKey(String prKey) {
this.prKey = prKey;
}
public String getPostedByUsername() {
return postedByUsername;
}
public void setPostedByUsername(String postedByUsername) {
this.postedByUsername = postedByUsername;
}
public String getQuestionLink() {
return questionLink;
}
public void setQuestionLink(String questionLink) {
this.questionLink = questionLink;
}
}
And yes I have data in the table. What am I doing wrong, and how can I resolve it?
I have tried adding #Modifying too, still it throws the same error.
Edit
I have used the UPDATE Query to update other fields in a different table and it works, don't know why this doesn't work.
questionVoteRepository.vote("true", "false", questionVote.getQuestionPrKey(),questionVote.getUserPrKey());
check the above line of code in the method upvoteQuestion which added above, this lines works perfectly, updating the question_votes table.
The QuestionVote POJO looks like this:
package com.demo.beans;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
#Entity
#Table(name="question_votes")
public class QuestionVote {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "PR_KEY")
private String prKey;
#Column(name="question_pr_key")
private String questionPrKey;
#Column(name="user_pr_key")
private String userPrKey;
#Column(name="upvote")
private String upvote;
#Column(name="downvote")
private String downvote;
public QuestionVote() {
}
public QuestionVote(String prKey, String questionPrKey, String userPrKey, String upvote, String downvote) {
super();
this.prKey = prKey;
this.questionPrKey = questionPrKey;
this.userPrKey = userPrKey;
this.upvote = upvote;
this.downvote = downvote;
}
public String getPrKey() {
return prKey;
}
public void setPrKey(String prKey) {
this.prKey = prKey;
}
public String getQuestionPrKey() {
return questionPrKey;
}
public void setQuestionPrKey(String questionPrKey) {
this.questionPrKey = questionPrKey;
}
public String getUserPrKey() {
return userPrKey;
}
public void setUserPrKey(String userPrKey) {
this.userPrKey = userPrKey;
}
public String getUpvote() {
return upvote;
}
public void setUpvote(String upvote) {
this.upvote = upvote;
}
public String getDownvote() {
return downvote;
}
public void setDownvote(String downvote) {
this.downvote = downvote;
}
}
When a question is added I add a row in the question_votes table too and set the upvote and downvote column for that row as false, false. When the question is upvoted I update the two tables questions and question_votes the question_votes table gets updated successfully but the questions table doesn't gets updated.
The QuestionVoteRepository looks like this:
package com.demo.beans.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.demo.beans.QuestionVote;
#Repository
public interface QuestionVoteRepository extends JpaRepository<QuestionVote, Long>{
#Query(value = "SELECT exists (SELECT 1 from question_votes where question_pr_key=:question_pr_key and user_pr_key=:user_pr_key)", nativeQuery=true)
public String checkWhetherRowExists(#Param("question_pr_key") String questionPrKey,
#Param("user_pr_key") String userPrKey);
#Query(value = "SELECT upvote from question_votes where question_pr_key=:question_pr_key and user_pr_key=:user_pr_key", nativeQuery=true)
public String checkUpvote(#Param("question_pr_key") String questionPrKey, #Param("user_pr_key") String userPrKey);
#Query(value = "SELECT downvote from question_votes where question_pr_key=:question_pr_key and user_pr_key=:user_pr_key", nativeQuery=true)
public String checkDownvote(#Param("question_pr_key") String questionPrKey, #Param("user_pr_key") String userPrKey);
#Query(value = "UPDATE question_votes SET upvote=:upvote, downvote=:downvote where question_pr_key=:question_pr_key and user_pr_key=:user_pr_key", nativeQuery=true)
public void vote(#Param("upvote") String upvote, #Param("downvote") String downvote,
#Param("question_pr_key") String questionPrKey, #Param("user_pr_key") String userPrKey);
}
You need to add #Modifying to changeVotes method in the repository to mark that this is an update query and no results are expected back.
https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/Modifying.html
In my Spring Boot application, I am using JWT and a custom UserDetailsService. My AuthenticationManager is configured in a class annotated with #Configuration using the following method:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
auth
.userDetailsService(userDetailsService)
.and()
.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder());
}
Even though I specified a UserDetailsService, I am faced with the following problem: When my JWTLoginFilter intercepts the login request, and getAuthenticationManager().authenticate(token)
is called, I get the following exception:
org.springframework.security.authentication.InternalAuthenticationServiceException: PreparedStatementCallback; bad SQL grammar [select username,password,enabled from users where username = ?]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'butler-test.users' doesn't exist
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:126)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:144)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
at org.kehrbusch.butler.apigate.jwt.JWTLoginFilter.attemptAuthentication(JWTLoginFilter.java:35)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:89)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:784)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [select username,password,enabled from users where username = ?]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'butler-test.users' doesn't exist
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:231)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:684)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:716)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:726)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:776)
at org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl.loadUsersByUsername(JdbcDaoImpl.java:217)
at org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl.loadUserByUsername(JdbcDaoImpl.java:174)
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:114)
... 53 common frames omitted
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'butler-test.users' doesn't exist
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
at com.mysql.jdbc.Util.getInstance(Util.java:387)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:942)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3966)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3902)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2526)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2673)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2549)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1962)
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:692)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633)
... 60 common frames omitted
Setting a query using usersByUsernameQuery(query) on my AuthenticationManagerBuilder solves this problem, but is this the only solution? Shouldn't the UserDetailsService provide the information needed to retrieve the UserDetails for a username?
In case it helps, here is a snippet from the JWTLoginFilter:
#Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
AccountCredentials credentials = new ObjectMapper().readValue(httpServletRequest.getInputStream(), AccountCredentials.class);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword());
return getAuthenticationManager().authenticate(token);
}
This is my user entity (there are subclasses for specific users):
#Entity
#Table(name = "u_userdetails")
#Inheritance(strategy = InheritanceType.JOINED)
public class BasicUser implements UserDetails {
/**
*
*/
private static final long serialVersionUID = -109962402457721028L;
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(name = "id", columnDefinition = "BINARY(16)")
private UUID id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
public boolean isLocked() {
return locked;
}
#JsonDeserialize(using=LocalDateDeserializer.class)
#JsonSerialize(using=LocalDateSerializer.class)
#Column(name = "registration_date")
private LocalDate registrationDate;
#Column(name = "locked")
private boolean locked;
#Column(name = "enabled")
private boolean enabled;
#Column(name = "activation_key")
private String activationKey;
#Column(name = "email")
private String email;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "u_user_group",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "group_id", referencedColumnName = "id")
)
private List<Group> groups;
#ElementCollection
#CollectionTable(name="u_user_role", joinColumns=#JoinColumn(name="id"))
#Column(name="role")
private List<String> roles;
protected BasicUser() {}
public BasicUser(
#JsonProperty("id") UUID id,
#JsonProperty("username") String username,
#JsonProperty("password") String password,
#JsonProperty("registrationDate") LocalDate registrationDate,
#JsonProperty("locked") boolean locked,
#JsonProperty("enabled") boolean enabled,
#JsonProperty("activationKey") String activationKey,
#JsonProperty("email") String email,
#JsonProperty("roles") List<String> roles) {
this.id = id;
this.username = username;
this.password = password;
this.registrationDate = registrationDate;
this.locked = locked;
this.enabled = enabled;
this.activationKey = activationKey;
this.email = email;
this.roles = roles;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public static List<GrantedAuthority> getAuthorities(List<String> roles) {
List<GrantedAuthority> res = new ArrayList<>();
for(String role : roles) {
res.add(new BasicGrantedAuthority(role));
}
return res;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return !locked;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return enabled;
}
public LocalDate getRegistrationDate() {
return registrationDate;
}
public UUID getId() {
return id;
}
public void setPassword(String password) {
this.password = password;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return getAuthorities(roles);
}
public void setLocked(boolean locked) {
this.locked = locked;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getActivationKey() {
return activationKey;
}
public void setActivationKey(String activationKey) {
this.activationKey = activationKey;
}
}
Your configuration is wrong. You defined 2 authentication mechanisms, one is a user details service, and the second is a JDBC authentication.
In order to authenticate a user you only need one kind of mechanism to do that.
Your JVM "complains" about a bad SQL grammar, and if you'll examine the exception more closely you'll see that in particular JVM "complains" that he can't find the users table in your DB.
It seems that your JDBC authentication kicks in and tries to find the user credentials in the users DB table.
When you use this kind of authentication (JDBC) that is where and how Spring will try to authenticate the users, by trying to find a matching record within the users table in your DB.
You obviously mixing 2 authentications mechanisms by trying to read from:
#Table(name = "u_userdetails")
If you want to use JDBC authentication make sure to read the credentials from users table.
And not from:
#Table(name = "u_userdetails")