Field in Aspect injected after its first use, causing NullPointerException at startup - java

ABSTRACT:
I have some initialisation operations executed in #PostConstruct of #Service ServiceInitialiserFacsimile. Those operations include a call to a method after whose execution an Aspect (DoAttionalStuffAspect) is applied.
The Aspect is instantied through aspectOf, so it is handled by the Spring Container, but unfortunately its dependencies are injected AFTER the execution of ServiceInitialiserFacsimile #PostConstruct, resulting in a NullPointerException.
How can I tell the Spring Container to inject first the fields in the Aspect and then instantiate the ServiceInitialiserFacsimile ?
I tried with an Autowired constructor for the aspect, but I think in the end AspectJ requires the no-arg constructor, so it was no help
CODE
This is a Sample I created in order to reproduce the issue I have in a much more complicated app. Here is the project if you want to check it out. https://github.com/alessiop86/spring3-mvc-maven-xml-hello-world
Code below:
This is the initialisation class:
#Component
public class ServiceInitialiserFacsimile {
private final SampleService sampleService;
#Autowired
public ServiceInitialiserFacsimile(SampleService ss) {
this.sampleService = ss;
}
#PostConstruct
public void initialiseAllTheServices() {
this.sampleService.init();
}
}
This is the service with some custom logic that requires to be initialised by the ServiceInitialiserFacsimile #PostConstruct:
#Service
public class SampleService {
public void init() {
System.out.println("do some stuff");
try {
execute();
}
catch(Exception e) {
System.err.println("I do not want to block to whole framework initialisation");
}
}
#DoAdditionalStuff
public void execute() {
System.out.println("Phase 1");
}
}
This is the annotation I use in the aspect definition
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface DoAdditionalStuff {
}
This is the aspect
#Aspect
public class AdditionalStuffAspect {
private AdditionalStuffService service;
public AdditionalStuffService getService() {
return service;
}
public void setService(AdditionalStuffService service) {
this.service = service;
}
#Pointcut(value="execution(public * *(..))")
private void anyPublicMethod() { }
#AfterReturning("anyPublicMethod() && #annotation(doAdditionalStuff)")
public void afterReturning(JoinPoint jointPoint, DoAdditionalStuff doAdditionalStuff) {
System.out.println(jointPoint);
service.doStuff();
}
}
This is the service that is created, but not yet instantiated when the aspect is run:
#Service
public class AdditionalStuffService {
public void doStuff() {
System.out.println("Phase2: additional stuff");
}
}
Spring context xml configuration file:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="initialisation.mess"/>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<mvc:resources mapping="/resources/**" location="/resources/"/>
<mvc:annotation-driven/>
<bean class="initialisation.mess.aspects.AdditionalStuffAspect" factory-method="aspectOf">
<property name="service" ref="additionalStuffService" />
</bean>
</beans>

I was able to enforce a dependency on the ServiceInitialiserFacsimile from the Aspect by setting an id in the xml:
<bean id="myAspect" class="initialisation.mess.aspects.AdditionalStuffAspect" factory-method="aspectOf">
<property name="service" ref="additionalStuffService" />
</bean>
and then specifying the dependency of ServiceInitialiserFacsimile from the spring managed AdditionalStuffAspect with a #DependsOn annotation:
#Component
#DependsOn("myAspect")
public class ServiceInitialiserFacsimile {
private final SampleService sampleService;
#Autowired
public ServiceInitialiserFacsimile(SampleService ss) {
this.sampleService = ss;
}
#PostConstruct
public void initialiseAllTheServices() {
this.sampleService.init();
}
}

Related

NPE while accessing through #Autowired [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 2 years ago.
I have the below code in my SpringBoot project which is throwing NPE at a specific line mentioned.
Exception in thread "main" java.lang.NullPointerException
at com.temp.controller.Controller.triggerJob(Controller.java:15)
at com.temp.Application.main(Application.java:19)
Application.java
#Configuration
#SpringBootApplication
#ImportResource({"classpath:applicationContext.xml"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
Controller controller = new Controller();
controller.triggerJob();
}
}
Controller.java
#Controller
public class Controller {
#Autowired
private Service Service;
public void triggerJob() {
Service.selectRecords();
}
}
Service.selectRecords(); is where the NPE is being thrown
Service.java
public interface Service {
List<VO> selectRecords();
}
ServiceImpl.java
#Service
public class ServiceImpl implements Service {
#Autowired
private Dao dao;
#Override
public List<VO> selectRecords() {
return dao.selectRecords();
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<util:properties id="configProperties"
location="file:${app.config.home}/config/config-${spring.profiles.active}.properties" />
<context:property-placeholder
location="file:${app.config.home}/config/config-${spring.profiles.active}.properties" />
<bean id="crypt" class="com.temp.util.MyUtil">
<property name="userId" value="${username}"></property>
<property name="password" value="${password}"></property>
<property name="key" value="123456789012345678901234"></property>
</bean>
<bean id="datasource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${connection}" />
<property name="username" value="#{crypt.userId}" />
<property name="password" value="#{crypt.password}" />
</bean>
<bean id="namedJdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="datasource" />
</bean>
</beans>
I have a similar project like this and have compared the configuration of both and they are the same except for 2 things.
The spring boot starter version is 2.4.2 for this project and 1.5.3 for the other project.
Java version is 11 for this project and 1.8 for the other project.
Not sure where I'm going wrong.
Am I missing something? Kindly help.
You are creating new instance
Controller controller = new Controller();
manually and this instance is not in Spring context. Therefore, the injected (autowired) instance of Service is null. #Autowired only works when the instance exists in Spring context.
The best approach is to keep Controller testable is injection via constructor:
#Configuration
#SpringBootApplication
#ImportResource({"classpath:applicationContext.xml"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
Controller controller = new Controller(new ServiceImpl(new DaoImpl()));
controller.triggerJob();
}
}
Inject the instance via constructor:
#Controller
public class Controller {
private final Service Service;
public Controller(final Service Service) {
this.service = service;
}
public void triggerJob() {
Service.selectRecords();
}
}
And also inject the Dao dependency via constructor:
#Service
public class ServiceImpl implements Service {
private final Dao dao;
public ServiceImpl(final Dao dao) {
this.dao = dao;
}
#Override
public List<VO> selectRecords() {
return dao.selectRecords();
}
}
For Spring version above 4.3, #Autowired could be omitted from top of the constructor, Spring scans the injection automatically and injects the dependency via constructor.
For Spring version below 4.3, add #Autowired on top of constructors i.e.:
#Controller
public class Controller {
private final Service Service;
#Autowired
public Controller(final Service Service) {
this.service = service;
}
public void triggerJob() {
Service.selectRecords();
}
}

How to use #Required annotation in setter injection in spring?

#required annotation usage. I tried giving this above setter method and tried to find the bean from context without setting this dependency. I got the object with the dependency is set null, my expectation was spring will throw some exception. Please guide me where I am doing wrong?
#Required to make it mandatory that the dependency has to be injected
Let us example:
We need to use RequiredAnnotationPostProcessor which checks whether #Required dependencies have been injected or not
public class BankService {
private CustomerService customerService;
private BillPaymentService billPaymentService;
#Required
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
#Required
public void setBillPaymentService(BillPaymentService billPaymentService) {
this.billPaymentService = billPaymentService;
}
}
The configuration is like
<bean id="custService" class="xml.CustomerServiceImpl" />
<bean id="billingService" class="xml.BillPaymentServiceImpl" />
<bean id="bankService" class="xml.BankServiceImpl">
<property name="customerService" ref="custService" />
<property name="billPaymentService" ref="billingService" />
</bean>
<bean class=”o.s.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
If we don’t set both the properties we will get an error for the BankService configuration as both are #Required.
I hope this helps!!
Same anwer by bmt - just adding here what i did to verify.
package com.requiredAnnotation;
import org.springframework.beans.factory.annotation.Required;
public class BankService {
private CustomerService customerService;
private BillPaymentService billPaymentService;
#Required
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
#Required
public void setBillPaymentService(BillPaymentService billPaymentService) {
this.billPaymentService = billPaymentService;
}
public BillPaymentService getBillPaymentService() {
return billPaymentService;
}
public CustomerService getCustomerService() {
return customerService;
}
}
package com.requiredAnnotation;
public class CustomerService {
}
package com.requiredAnnotation;
public class BillPaymentService {
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="customerService" class="com.requiredAnnotation.CustomerService" />
<bean id="billPaymentService" class="com.requiredAnnotation.BillPaymentService" />
<bean id="bankService" class="com.requiredAnnotation.BankService">
<property name="customerService" ref="customerService" />
<!-- <property name="billPaymentService" ref="billPaymentService" /> -->
</bean>
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
</beans>
package com.requiredAnnotation;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:com/requiredAnnotation/beans-required.xml");
BankService bankService = applicationContext.getBean(BankService.class);
System.out.println("bankService got.");
System.out.println("getCustomerService - " + bankService.getCustomerService());
System.out.println("getBillPaymentService - " + bankService.getBillPaymentService());
}
}

Overriding transactional Annotation Spring + hibernate

I have this DAO:
#Transactional("transactionManager")
public class DAO{
public void save(String a){...}
}
I have this class:
public class test{
...
#Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void save(){
DAO.save("a");
DAO.save("b");
}
}
I want the "save" method to rollback when it throws an exception, but it doesn't seem to work when an exception occurs it does not rollback, what is the proper approach for this? All the other methods in the DAO are transactional. Is there a way I can override the transactional settings of the override?
EDIT:
I have updated to be, and it is still not working when throwing exception:
public class test{
...
public void save(){
Service.test(a,b);
}
}
public class Service{
#Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void testSave(object a, object b){
dao.updateEntry(a);
dao.updateEntry(b);
}
}
Remove the Transactional annotation from the Dao layer and place a Transactional annotation in your service layer. Take a look at my code:-
#Transactional
#Service
public class Service {
#Autowired
private Dao1 dao1;
#Autowired
private Dao2 dao2;
public Dao1 getDao1() {
return dao1;
}
public void setDao1(Dao1 dao1) {
this.dao1 = dao1;
}
public Dao2 getDao2() {
return dao2;
}
public void setDao2(Dao2 dao2) {
this.dao2 = dao2;
}
public void insertData(){
dao1.insert1();
dao2.insert2();
}
In above code, if dao2.insert2() fails then dao1.insert1() will rollback.
In case when you have multiple methods in service class with different transaction properties :
You can define the #Transactional annotation on your public methods with below rule:-
When using proxies, you should apply the #Transactional annotation
only to methods with public visibility. If you do annotate protected,
private or package-visible methods with the #Transactional annotation,
no error is raised, but the annotated method does not exhibit the
configured transactional settings.
Link1: Transactional annotation on whole class + excluding a single method
Transaction support configuration setup:-
1) spring-config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.concept" />
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
</beans>

Spring lookup-method and abstract class

Would like to understand how Spring creates a bean from an abstract class, as if it is instantiating an Abstract class, as it is known that is not possible. Would like to know, what is getting instantiated for the "abstractLookupBean" bean.
Thank you.
public abstract class AbstractLookupDemoBean implements DemoBean {
public abstract MyHelper getMyHelper();
public void someOperation() {
getMyHelper().doSomethingHelpful();
}
}
DemoBean class
public interface DemoBean {
public MyHelper getMyHelper();
public void someOperation();
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="helper" class="com.rami.methodlookup.helper.MyHelper" scope="prototype"/>
<bean id="abstractLookupBean" class="com.rami.methodlookup.helper.AbstractLookupDemoBean">
<lookup-method name="getMyHelper" bean="helper"/>
</bean>
<bean id="standardLookupBean" class="com.rami.methodlookup.helper.StandardLookupDemoBean">
<property name="myHelper">
<ref local="helper"/>
</property>
</bean>
</beans>
main class
public static void main(String[] args) {
GenericXmlApplicationContext ctx = null;
try{
ctx = new GenericXmlApplicationContext();
ctx.load("applicationContext.xml");
ctx.refresh();
DemoBean abstractBean = (DemoBean) ctx.getBean("abstractLookupBean"); //What is getting instantiated?
}finally{
ctx.close();
}
Please see spring documentation here
...If the method is abstract, the dynamically-generated subclass will implement the method. Otherwise, the dynamically-generated subclass will override the concrete method defined in the original class...

How to make spring inject value into a static field

I know this may looks like a previously asked question but I'm facing a different problem here.
I have a utility class that has only static methods. I don't and I won't take an instance from it.
public class Utils{
private static Properties dataBaseAttr;
public static void methodA(){
}
public static void methodB(){
}
}
Now I need Spring to fill dataBaseAttr with database attributes Properties.Spring config is:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<util:properties id="dataBaseAttr"
location="file:#{classPathVariable.path}/dataBaseAttr.properties" />
</beans>
I already done it in other beans but the problem here in this class (Utils) isn't a bean, And if I make it a bean nothing changes I still can't use the variable since the class will not be instantiated and variable always equals null.
You have two possibilities:
non-static setter for static property/field;
using org.springframework.beans.factory.config.MethodInvokingFactoryBean to invoke a static setter.
In the first option you have a bean with a regular setter but instead setting an instance property you set the static property/field.
public void setTheProperty(Object value) {
foo.bar.Class.STATIC_VALUE = value;
}
but in order to do this you need to have an instance of a bean that will expose this setter (its more like an workaround).
In the second case it would be done as follows:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="foo.bar.Class.setTheProperty"/>
<property name="arguments">
<list>
<ref bean="theProperty"/>
</list>
</property>
</bean>
On you case you will add a new setter on the Utils class:
public static setDataBaseAttr(Properties p)
and in your context you will configure it with the approach exemplified above, more or less like:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="foo.bar.Utils.setDataBaseAttr"/>
<property name="arguments">
<list>
<ref bean="dataBaseAttr"/>
</list>
</property>
</bean>
I've had a similar requirement: I needed to inject a Spring-managed repository bean into my Person entity class ("entity" as in "something with an identity", for example an JPA entity). A Person instance has friends, and for this Person instance to return its friends, it shall delegate to its repository and query for friends there.
#Entity
public class Person {
private static PersonRepository personRepository;
#Id
#GeneratedValue
private long id;
public static void setPersonRepository(PersonRepository personRepository){
this.personRepository = personRepository;
}
public Set<Person> getFriends(){
return personRepository.getFriends(id);
}
...
}
.
#Repository
public class PersonRepository {
public Person get Person(long id) {
// do database-related stuff
}
public Set<Person> getFriends(long id) {
// do database-related stuff
}
...
}
So how did I inject that PersonRepository singleton into the static field of the Person class?
I created a #Configuration, which gets picked up at Spring ApplicationContext construction time. This #Configuration gets injected with all those beans that I need to inject as static fields into other classes. Then with a #PostConstruct annotation, I catch a hook to do all static field injection logic.
#Configuration
public class StaticFieldInjectionConfiguration {
#Inject
private PersonRepository personRepository;
#PostConstruct
private void init() {
Person.setPersonRepository(personRepository);
}
}
As these answers are old, I found this alternative. It is very clean and works with just java annotations:
To fix it, create a “none static setter” to assign the injected value for the static variable. For example :
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class GlobalValue {
public static String DATABASE;
#Value("${mongodb.db}")
public void setDatabase(String db) {
DATABASE = db;
}
}
https://www.mkyong.com/spring/spring-inject-a-value-into-static-variables/

Categories