I encountered a stackoverflow error when I implement audit using AuditorAware. The code successfully gets the login username. However, @CreatedBy and @ModifiedBy should be the primary key of the user record and not the login username. I tried two versions of the code but both of them results to stackoverflow.
Version 1: Autowiring UserService
public class SpringSecurityAuditorAware implements AuditorAware<String> {
@Autowired
UserService userService;
@Override
public Optional<String> getCurrentAuditor() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.isAuthenticated()) return null;
String loginName = auth.getPrincipal().toString();
UserDto user = userService.getUser(loginName);
return Optional.of(user.getUserPk());
}}
Version 2: Using application context to get the bean
public class SpringSecurityAuditorAware implements AuditorAware<String> {
@Override
public Optional<String> getCurrentAuditor() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.isAuthenticated()) return null;
String loginName = auth.getPrincipal().toString();
UserService userService = (UserService)SpringApplicationContext.getBean("userServiceImpl");
UserDto user = userService.getUser(loginName);
return Optional.of(user.getUserPk());
}
}
Here is the UserService code:
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserRepository userRepository;
@Override
public UserDto getUser(String loginId) {
UserEntity userEntity = userRepository.findByUserLoginId(loginId);
if (userEntity == null) throw new UsernameNotFoundException(loginId);
ModelMapper modelMapper = new ModelMapper();
UserDto returnValue = modelMapper.map(userEntity, UserDto.class);
return returnValue;
}}
I included the screenshots of the debug for reference. Debug at Line: UserDto user = userService.getUser(loginName); Debug at Line: UserEntity userEntity = userRepository.findByUserLoginId(loginId); Basically, the code moves between these two lines, causing the infinite loop. Also, the error occurs when saving one-to-many or many-to-many entities (i.e., master-detail). There is no error when saving one-to-one bi-directional entities and a single entity.
Below is the error log:
java.lang.StackOverflowError: null
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152) ~[spring-tx-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:145) ~[spring-data-jpa-2.5.6.jar:2.5.6]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.12.jar:5.3.12]
at jdk.proxy2/jdk.proxy2.$Proxy116.findByUserLoginId(Unknown Source) ~[na:na]
at ph.com.absi.iibsv5.ws.service.impl.UserServiceImpl.getUser(UserServiceImpl.java:73) ~[classes/:na]
at ph.com.absi.iibsv5.ws.SpringSecurityAuditorAware.getCurrentAuditor(SpringSecurityAuditorAware.java:28) ~[classes/:na]
at jdk.internal.reflect.GeneratedMethodAccessor82.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.12.jar:5.3.12]
at jdk.proxy2/jdk.proxy2.$Proxy127.getCurrentAuditor(Unknown Source) ~[na:na]
at java.base/java.util.Optional.map(Optional.java:260) ~[na:na]
at org.springframework.data.auditing.AuditingHandler.getAuditor(AuditingHandler.java:109) ~[spring-data-commons-2.5.6.jar:2.5.6]
at org.springframework.data.auditing.AuditingHandler.markModified(AuditingHandler.java:104) ~[spring-data-commons-2.5.6.jar:2.5.6]
at org.springframework.data.jpa.domain.support.AuditingEntityListener.touchForUpdate(AuditingEntityListener.java:112) ~[spring-data-jpa-2.5.6.jar:2.5.6]
at jdk.internal.reflect.GeneratedMethodAccessor83.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.hibernate.jpa.event.internal.ListenerCallback.performCallback(ListenerCallback.java:35) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.jpa.event.internal.CallbackRegistryImpl.callback(CallbackRegistryImpl.java:95) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.jpa.event.internal.CallbackRegistryImpl.preUpdate(CallbackRegistryImpl.java:69) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.internal.DefaultFlushEntityEventListener.invokeInterceptor(DefaultFlushEntityEventListener.java:369) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.internal.DefaultFlushEntityEventListener.handleInterception(DefaultFlushEntityEventListener.java:351) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.internal.DefaultFlushEntityEventListener.scheduleUpdate(DefaultFlushEntityEventListener.java:302) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:171) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:99) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:229) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:93) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:50) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
I hope you can help me with this error. Thank you for your time.