I have migrated our project from Spring (5.2.x) to Spring 6 with Hibernate 5.6. I am using JDK17 and our application server is Tomee 9.1.1.
Now when I access one of the RestAPI, the beans(autowired) within the autowired beans are null due to which I am hitting on NPE. I see few of the beans are proxied using Spring CGLIB
Caused by: java.lang.NullPointerException: Cannot invoke "com.hp.nieto.services.system.NietoSystemSettingsService.isOTMMShowActiveSessionsEnforced()"
because "this.nietoSystemSettingsService" is null at com.hp.nieto.business.NietoConfigurationBusinessLogic.isOTMMShowActiveSessionsEnforced(NietoConfigurationBusinessLogic.java:1328)
~[nieto-business-logic-24.1.0.jar:?]at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
~[?:?]at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
~[?:?]at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]at java.lang.reflect.Method.invoke(Method.java:568)
~[?:?]at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:352) [spring-aop-6.1.2.jar:6.1.2]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:713) [spring-aop-6.1.2.jar:6.1.2]
Following is how I have added my RestAPI
Interface
@Controller
@Api(value = "Collections", description = "the Collections API")
public interface CollectionsApi
@Controller
public class CollectionsApiController implements CollectionsApi {
@Autowired
NietoOTMMSessionBussinesLogic nietoOTMMSessionBussinesLogic;
@Override
public ResponseEntity<PublishCollectionRestResponse> publishCollection(
@RequestHeader(value = "Authorization") String authorizationHeader,
@PathVariable("id") String collectionId,
@Valid @RequestBody PublishCollectionRestRequest publishRequest,
HttpServletRequest servletRequest, Locale locale) {
PublishCollectionRestResponse publishedCollection = new PublishCollectionRestResponse();
try {
NietoUser loggedUser = nietoOTMMSessionBussinesLogic.getNietoUser(authorizationHeader);
}
Note: I am able to call getNietoUser here as I am able to see that NietoOTMMSessionBusinessLogic is autowired properly.
@Service
public class NietoOTMMSessionBussinesLogic {
@Autowired
private NietoConfigurationBusinessLogic nietoConfigurationBusinessLogic;
public NietoUser getNietoUser(String authorizationHeader) throws NietoException {
if (nietoConfigurationBusinessLogic.isOTMMShowActiveSessionsEnforced()) {
UserSessionsResponse userSessionsResponse = client.getCurrentUserAllActiveSession();
user.setUserSessionsResponse(userSessionsResponse);
}
...
}
Note: I am able to trigger nietoConfigurationBusinessLogic.isOTMMShowActiveSessionsEnforced()) call as well
@Service
public class NietoConfigurationBusinessLogic {
@Autowired
NietoSystemSettingsService nietoSystemSettingsService;
}
public boolean isOTMMShowActiveSessionsEnforced() {
return nietoSystemSettingsService.isOTMMShowActiveSessionsEnforced();
}
}
Here nietoSystemSettingsService is null to call on the method. Hence getting the NPE exception here
Application Context file configuration is as follows:
<?xml version="1.0" encoding="UTF-8"?">
<context:component-scan base-package="com.hp.nieto.*" />
<context:annotation-config />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<!-- Session Factory -->
<bean id="sessionFactory"
class="com.hp.nieto.config.providers.jpa.NietoLocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.hbm2ddl.import_files"></prop>
<prop key="hibernate.show_sql">false</prop>
<!-- <prop key="hibernate.current_session_context_class"> -->
<!-- com.hp.nieto.config.providers.jpa.SpringSessionContext -->
<!-- </prop> -->
<!-- Connection pool -->
<prop key="hibernate.enable_lazy_load_no_trans">true</prop>
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.max_size">20</prop>
<prop key="hibernate.c3p0.timeout">300</prop>
<prop key="hibernate.c3p0.max_statements">50</prop>
<prop key="hibernate.c3p0.idle_test_period">3000</prop>
<!-- Turning on the second level cache in general -->
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<!-- Turning on the query cache regions. The query and timestamp cache
regions will be created and used -->
<prop key="hibernate.cache.use_query_cache">false</prop>
<!-- Hibernate will create separate cache regions for Hibernate caching,
instead of trying to reuse cache regions defined elsewhere in the application -->
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.jcache.internal.JCacheRegionFactory</prop>
<prop key="hibernate.jakarta.cache.provider">org.ehcache.jsr107.EhcacheCachingProvider</prop>
<prop key="hibernate.jakarta.cache.uri">/assetview-cache-config.xml</prop>
<prop key="hibernate.generate_statistics">false</prop>
<prop key="hibernate.allow_load_outside_transaction">true</prop>
</props>
</property>
<property name="packagesToScan" value="com.hp.nieto.model.*" />
</bean>
<bean id="dataSource" class="com.hp.nieto.config.providers.jpa.NietoDataSource">
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven proxy-target-class="true"
transaction-manager="transactionManager" />
<bean id="persistenceExceptionTranslationPostProcessor" class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<mvc:annotation-driven />
<context:load-time-weaver aspectj-weaving="on"/>
</beans>
Previous version of my project used to work without any issues.
I had tried adding @PostConstruct for autowiring the bean in CollectionsApiController and NietoConfigurationBusinessLogic but It didn't help in my situation. Not sure what is wrong with the configuration. It would be great if anyone can share their thought on this issue.
@Autowired ApplicationContext applicationContext;
@PostConstruct
public void init() {
if(applicationContext !=null) {
applicationContext.getAutowireCapableBeanFactory().autowireBean(this);
}
}
I had similar autowiring NPE issues while invoking any service using it's constructor.