Autowired bean giving Null Pointer Exception - spring

I am using Autowired annotation in a Service class to inject Dao dependency. The code I have written is:
public interface Service {
public List<String> getAllCountries() ;
}
public class ServiceImpl implements Service {
#Autowired
private TestDao testDao;
public TestDao getTestDao() {
return testDao;
}
public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
public List<String> getAllCountries() {
// TODO Auto-generated method stub
System.out.println("coming in here:" + testDao);
return testDao.getAllCountries();
}
}
public interface TestDao {
List<String> getAllCountries() ;
}
public class TestDaoImpl implements TestDao{
#Override
public List<String> getAllCountries() {
// TODO Auto-generated method stub
List<String> ls = new ArrayList<>();
ls.add("test1");
return ls;
}
}
And a controller
public class TestController {
public void doSth() {
Service service = new ServiceImpl();
try {
System.out.println("service obj:" + service);
List<String> list = service.getAllCountries();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Beans.xml:
<context:annotation-config/>
<bean id="controller" class="org.test.TestController"/>
<bean id="testDao" class="org.test.TestDaoImpl"/>
And a main class:
ApplicationContext context = new
ClassPathXmlApplicationContext("beans4.xml");
TestController obj= (TestController) context.getBean("controller");
obj.doSth();
But it is throwing NullPointerException in ServiceImpl class. These all classes are in the same package.
Can somebody help me understand what exactly is the issue?
Solution:
public class TestController {
#Autowired
Service service;
//remaining code as it is
}

Your Service class is not managed by Spring . Hence, the dependency is getting injected.
To make your service class managed,
You can use #Service stereo type annotation and do a component scan.
I mean,
package com;
#Service
public class ServiceImpl implement XXXX{
//Your changes
}
and in spring config file:
<context:component-scan base-package="com"/>

I did not see any bean declaration or annotation for the ServiceImpl.
//You canot do it like the following
#controller
class A{
ServiceImpl simp=new ServiceImpl();
}
class ServiceImpl{
#Autowired
Adao adoa;//throws NPE
}
//it should be like this
#Controller
class A{
#autowired
ServiceImpl simp;
}
#Service
class ServiceImpl{
#Autowired
Adao adoa;
}
#Repository
class Adao{
}

Your testDao dependency bean has not been injected and you need the Spring container that you are using annotations and also specify which packages need to be scanned for Autowiring by adding the following:
<context:annotation-config />
<context:component-scan base-package="org.test" />
You can look here on how you can auto wire spring beans.

Related

How to use #TestConfiguration

How to override #Configuation which is present under src/main/java with #TestConfiguration during unit tests?
#Configuration
public class AppConfig {
#Bean
public EmployeeService employeeService(){
return new EmployeeService();
}
}
#Component
public class ServerStartSetup implements CommandLineRunner {
#Autowired
private EmployeeService employeeService;
public void run(String... args) {
// do something with employee service
}
}
I would like to override the above bean with some below custom bean for testing purposes.
#TestConfiguration
public class TestAppConfig {
#Bean
public EmployeeService employeeService(){
return new FakeEmployeeService();
}
}
#SpringBootTest
#Import(TestAppConfig.class)
public class UnitTest {
}
However AppConfig does not seem to be skipped. That is , it throws an error saying that there is a bean with same name employeeService. If I rename bean method name in the TestAppConfig, it injects the bean created via AppConfig.
How to fix this.?
Note: One possible solution is using #Profile. I am looking for anything other than using Profiles.
I tested locally and found that changing the method name or #Bean to #Bean("fakeEmployeeService") and adding the #Primary annotation works.
#SpringBootTest
class DemoApplicationTests {
#Autowired
private EmployeeService employeeService;
#TestConfiguration
static class TestConfig {
//#Bean("fakeEmployeeService")
#Bean
#Primary
public EmployeeService employeeServiceTest() {
return new EmployeeService() {
#Override
public void doSomething() {
System.out.println("Do something from test...");
}
};
}
}
...
}
If we want to override a bean definition in #TestConfiguration, we need:
To use the same name as the overridden bean. (Otherwise it would be an "additional" bean and we could get conflict/'d have to qualify/primary)
Since spring-boot:2.1: spring.main.allow-bean-definition-overriding=true (set this in tests ONLY!plz!)
#ref
Then, with:
#TestConfiguration
public class TestAppConfig {
#Bean // when same name, no #Primary needed
public EmployeeService employeeService(){ // same name as main bean!
return new FakeEmployeeService();
}
}
We can do that:
#Import(TestAppConfig.class)
#SpringBootTest(properties = "spring.main.allow-bean-definition-overriding=true")
public class UnitTest {
... // EmployeeService will be "fake", the rest is from "main config"
You can mock the AppConfig bean in your test like this:
#MockBean
private AppConfig config;
Or, like you said, just use profiles.

Defining constructor in prototype bean

Using SpringBoot, I have a Component bean that is defined as #Scope("protoype"). It also injects another prototype bean
The class is defined as
#Component
#Scope("prototype")
public class MyClass{
#Autowired
public BeanFactory beanFactory
private InjectedBean injectedBean
public MyClass(DataObj data) {
this.injectedBean = beanFactory.getBean(InjectedBean.class, data)
}
}
However, IntelliJ complains about the data field on the constructor: Could not autowire. No beans of 'DataObj' type found.. But DataObj is a POJO. I pass it in at runtime in order to create the bean. Am I defining the constructor incorrectly?
Update
Had the same problem doing it this way. It still wants to treat DataObj as a bean on the factory constructor class. Doesn't matter if I annotate the class with #Component or #Configuration
#Component
public class MyClass{
#Autowired
public BeanFactory beanFactory
private InjectedBean injectedBean
public MyClass(InjectedBean injectedBean) {
this.injectedBean = injectedBean;
}
#Bean
#Scope("prototype")
public MyClass myClass(DataObj data) {
InjectedBean injectedBean = beanFactory.getBean(InjectedBean.class, data)
return new MyClass(injectedBean);
}
}
Also tried this example from that same link:
#Configuration
public class ServiceConfig {
#Bean
public Function<DataObj, MyClass> thingFactory() {
return data-> myClass(data); //
}
#Bean
#Scope(value = "prototype")
public MyClass myClass(DataObj data) {
return new MyClass(data);
}
}
Update
I think I resolved this with some information in Spring Java Config: how do you create a prototype-scoped #Bean with runtime arguments?. Part of my problem is that I tried to put the factory bean in the Component itself, which doesn't work
In other words
#Component
public class MyClass{
#Autowired
public BeanFactory beanFactory
private InjectedBean injectedBean
public MyClass(InjectedBean injectedBean) {
this.injectedBean = injectedBean;
}
#Bean
#Scope("prototype")
public MyClass myClass(DataObj data) {
InjectedBean injectedBean = beanFactory.getBean(InjectedBean.class, data)
return new MyClass(injectedBean);
}
}
In this cass, Spring tries to create a MyClass bean because of the #Component annotation, but another MyClass bean due to the #Bean annotation.
So I moved the #Bean to another class
#Configuration
public class ServiceConfig {
#Bean
public Function<DataObj, MyClass> thingFactory() {
return data-> myClass(data); //
}
#Bean
#Scope(value = "prototype")
public MyClass myClass(DataObj data) {
return new MyClass(data);
}
}
This appears to work, but IntelliJ still complains about DataObj. This might be an Intellij issue

Spring: Cannot get bean by using #Component and #Bean

I'm new in Spring framework.
I try to config 2 beans with #Bean annotation within #Component.
After that, I try to getBean (by name), I got a NoSuchBeanDefinitionException.
Please help me to resolve it.
Here is my code:
- The component:
package com.example.component;
#Component
public class FactoryMethodComponent {
private static int i;
#Bean
#Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
#Bean
#Qualifier("tb1")
public TestBean1 publicInstanceTB1() {
return new TestBean1(publicInstance());
}
}
-The xml configuration file: app-context.xml.
<beans ...>
<context:component-scan base-package="com.example.*" />
</beans>
-The test code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:app-context.xml" })
public class ComponentBeanTest {
#Test
public void test() {
System.out.println(((TestBean1)context.getBean("tb1")).getTestBean().getMethodName());
System.out.println(publicTestBean.getMethodName());
}
}
-Exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean
named 'tb1' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:577)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1111)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:276)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1127)
at com.example.proxy.ComponentBeanTest.test(ComponentBeanTest.java:38)
Replace #Component with #Configuration which indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
#Configuration
public class FactoryMethodComponent {
private static int i;
#Bean
#Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
#Bean
#Qualifier("tb1")
public TestBean1 publicInstanceTB1() {
return new TestBean1(publicInstance());
}
}

how to autowire spring beans from a non-bean object created at runtime?

I have some Jpa repositories and several Entity class. I need to create a helper object for one of my Entity. Inside that helper I use #Autowire to access the Jpa repositories.
#Entity
class A {
#Transient
Helper helper;
...
}
class Helper {
A a;
#Autowired
CRepository repo;
public Helper(A a) {
this.a = a;
}
}
However, the repo is always null. I've tried using SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this) and #Configurable, but both of them failed. Can anybody provide some hint for me?
BTW, A is instantiated inside a rest controller.
Thanks!.
You can use a BeanUtil class to get any bean that created in Springl
#Service
public class BeanUtil implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
Then you can get the bean.
MyBean obj = BeanUtil.getBean(MyBean.class);
Use constructor injection instead of field injection; this is a best practice all the time anyway. Then it's trivial to inject your A into the controller and pass it as a constructor argument.
#Configurable annotation works fine, but you need to use #EnableSpringConfigured annotation in any configuration class in order to make it work. Read my answer in other stackoverflow post: spring autowiring not working from a non-spring managed class
Entity class should not contain any helpers, even if transient. For a clean design you need to separate concerns, so the entity should not be aware of your business logic. I cannot help you more since I don't know which is the goal of that helper, but here you have other alternatives:
ALTERNATIVE 1 (based on your description seems that helper is an stateful bean, so it is not candidate to be a #Service, which I personally think it should be)
#Controller
public MyController {
#RequestMapping(...)
public void processRequest() {
A a = new A();
...
Helper helper = new Helper(a); // CRepository is successfully autowired
}
}
#Configurable(autowire = Autowire.BY_TYPE)
public class Helper {
A a;
#Autowired
CRepository repo;
}
#Configuration
#EnableSpringConfigured
public Application {
...
}
ALTERNATIVE 2 (make your Helper class stateless so that spring is aware of your beans without the need of extra stuff like #Confgurable/#EnableSpringConfigured)
#Controller
public MyController {
#Autowired Helper helper; // CRepository is correctly autowired
#RequestMapping(...)
public void processRequest() {
A a = new A();
...
helper.doSomething(a);
}
}
#Service
public class Helper {
// A a; remove dependency to A to make it stateless
#Autowired
CRepository repo;
public Helper() {
}
public void doSomething(A a) {
...
repo.save(a);
}
}
You cannot autowire nothing in your Helper class because it isn't managed by Spring.
You can use this approach:
public class HelperManager {
#Autowired
private ApplicationContext context;
public Helper getHelper(A a) {
return context.getBean(Helper.class, a);
}
Configure Helper to be a prototype bean:
#Configuration
public class MyConfiguration {
#Bean
public HelperManager helperManager() {
return new HelperManager();
}
#Bean
#Scope("prototype")
public Helper helper(A a) {
return new Helper(a);
}
}
And finally in your controller:
#Controller
public class MyController {
#Autowired
private HelperManager helperManager;
public someMethodWhereToInstanceYourHelper(A a) {
...
Helper helper = helperManager.getHelper(a);
...
}
}

Spring #Autowired annotated object value is null

// My Factory class
#Component
public class UserRewardAccountValidatorFactory {
#Autowired
private VirginAmericaValidator virginAmericaValidator;
private static class SingletonHolder {
static UserRewardAccountValidatorFactory instance = new UserRewardAccountValidatorFactory();
}
public static UserRewardAccountValidatorFactory getInstance() {
return SingletonHolder.instance;
}
private UserRewardAccountValidatorFactory() {}
public PartnerValidator getPartnerValidator(Partner partner){
return virginAmericaValidator;
}
}
// My Validator class
#Service
public class VirginAmericaValidator implements PartnerValidator {
#Override
public void validate(String code) throws InvalidCodeException{
//do some processing if processing fails throw exception
if (code.equals("bad".toString())){
throw new InvalidCodeException();
}
}
}
//Usage:
PartnerValidator pv = UserRewardAccountValidatorFactory.getInstance().getPartnerValidator(partner);
if (pv != null){
try {
pv.validate(userRewardAccount);
} catch (InvalidCodeException e){
return buildResponse(ResponseStatus.INVALID_USER_REWARD_ACCOUNT, e.getMessage());
}
}
My package scan level is at much higher level. Whats happening is my virginAmericaValidator is always empty. Why is #Autowired annotation not working.
Your current approach will not work with Spring as you are ultimately using new UserRewardAccountValidatorFactory to create the instance which essentially bypasses Spring context altogether. Two approaches that should possibly work are these:
a. Using a factory-method and using xml to define your bean:
<bean class="package.UserRewardAccountValidatorFactory" name="myfactory" factory-method="getInstance"/>
This will essentially return the instance that you are creating back as a Spring bean and should get autowired cleanly.
b. Using Java #Configuration based mechanism:
#Configuration
public class MyBeanConfiguration {
#Bean
public UserRewardAccountValidatorFactory myFactory() {
return UserRewardAccountValidatorFactory.getInstance();
}
}

Resources