Spring Null Pointer Exception in #Autowired Object - java

Hello I am kind of new in Spring in Dependency Injection.
I have made few config files which has beans inside it and I am injecting those beans using #Autowired annotation.
Configs:
#Configuration
#Component
public class FirstConfig {
#Bean
A getA() {
return new A(secondConfig.getB());
}
#Autowired
SecondConfig secondConfig;
}
SecondConfig
#Configuration
public class SecondConfig {
#Bean
B getB() {
return new B();
}
}
And Last Config
#Configuration
public class ThirdConfig {
#Bean
D getD() {
return new D();
}
}
Here is the service using A()
#Component
public class XYZService
{
private C c;
#Autowired
private A a;
public XYZService()
{
this.c = a.doSomething("Hello world");
}
}
Also, if this helps,
#Component
public class B implements someInteface
{
#Autowired
private D d;
}
I am getting NPE on this line: this.c = a.doSomething("Hello world");
Any idea what's wrong?

You can't use autowired properties in the class consturctor since Spring just inject the #Autowired properties after the creation of that class. However you can use the autowired properties in the method with annotation #PostConstruct which will run right after the constructor run.
#Component
public class XYZService
{
private C c;
#Autowired
private A a;
public XYZService()
{
// Move the initialization to #PostConstruct
}
#PostConstruct
private void init() {
this.c = a.doSomething("Hello world");
}
}

To use one configuration into another you can Import the configuration using #Import(ConfigurationClass.class) annotation. In your case -
#Configuration
#Component
#Import(SecondConfig.class)
public class FirstConfig {
#Bean
A getA() {
return new A(secondConfig.getB());
}
#Autowired
SecondConfig secondConfig;
}
You could also use #ComponentScan annotation to let your configuration automatically detect components from your Configuration file like shown below. This is particularly useful when you want to use a class as a bean
#Configuration
#Component
#ComponentScan(basepackages = "com.yourBasePackage")
public class FirstConfig {
#Bean
A getA() {
return new A(secondConfig.getB());
}
#Autowired
SecondConfig secondConfig;
}

Related

Can't access #Value in Spring project accross different packages and Environment doesn't contain the values either

I cannot access #Value("${app.version}") or event environment.getProperty("app.version") or any property in my controllers or services.
My project structure looks like this
src/main/java
-configuration/
AppConfig.java
EnvConfig.java
JpaConfig.java
UiConfig.java
ServicesConfig.java
UiAppInitializer.java
-repositories/
....
-models/
....
-services/
....
-controllers/
....
My UiAppInitializer is pretty straight forward,
getRootConfigClassess() returns AppConfig.class and getServletConfigClasses() returns UiConfig.class
AppConfig.java
#Configuration
#Import({
EnvConfig.class,
UiConfig.class,
ServicesConfig.class
})
public class AppConfig{}
EnvConfig
#Configuration
public class EnvConfig implements InitializingBean {
#Value("${app.version}")
private String appVersion
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
pc.setLocations(new ClassPathResource("application.properties"));
return pc;
}
#Override
public void afterpropertiesSet() throws Exception {
log.debug("App Version is " + appVersion);
}
}
A simple controller
#RestController
#RequestMapping(value = "/version")
public class VersionContoller {
#Value("${app.version}")
private String version;
#GetMapping()
public String getVersion() {
return version;
}
}
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {
"my.packages.path.ui"
})
public class UiConfig implements WebMvcConfigurer {
....
}
The controller just returns "${app.version}" but the afterpropertiesSet correctly logs the version.
What am I doing wrong here? I have other controllers that connect to the repository successfully which was setup in JpaConfig that usues #Value for all the properties also
Note not using Spring Boot
It seems the controller is getting initialised as a bean before the properties() bean has had setLocations() called.
You could remove classpath scanning (I assume you have it on to find the controller bean?) and in your EnvConfig declare a new method that is a bean declaration for the Controller that passes in the version String. Obviously requiring a change to the controller constructor too
#Configuration
public class EnvConfig implements InitializingBean {
#Value("${app.version}")
private String appVersion
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
pc.setLocations(new ClassPathResource("application.properties"));
return pc;
}
#Bean
public VersionContoller controller() {
return new VersionController(appVersion);
}
#Override
public void afterpropertiesSet() throws Exception {
log.debug("App Version is " + appVersion);
}
}

how to load #Configuration classes in an order in spring boot

i would like to load #Configuration classes in an order. i have two configuration classes. i am having a requirement of loading my SampleProperties class before sampleconfiguration class.
I have tried the following annotations but it is not working as expected.
#AutoConfigureAfter(SampleProperties.class )
#AutoConfigureBefore(SampleConfiguration.class)
I have put my congiurations class in diff package in order to read configurations classes in an order.using #Import function, i am including my configuration classes into my application
My Main Class:
#Import({SampleProperties.class,SampleConfiguration.class,})
public class SampleApplication{
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
My SampleProperties Class
#Configuration
#AutoConfigureBefore(SampleConfiguration.class)
#ConfigurationProperties("demo")
#Data
public class SampleProperties {
private String team;
private int teamSize;
private String teamLeader;
}
My sampleconfiguration Class:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef="sampleEntityManager",
transactionManagerRef="sampleTransactionManager",
basePackages= {"com.example.demo.repo"})
#AutoConfigureAfter(SampleProperties.class)
public class SampleConfiguration {
#Autowired
Environment env;
#Bean(name="sampleDataSource")
#Primary
public DataSource dmsDataSource() {
// functions
return null;
}
#Primary
#Bean(name = "sampleEntityManager")
public LocalContainerEntityManagerFactoryBean dmsEntityManagerFactory(EntityManagerFactoryBuilder builder) {
// functions
return null;
}
#Primary
#Bean(name = "sampleTransactionManager")
public PlatformTransactionManager dmsTransactionManager(#Qualifier("sampleEntityManager") EntityManagerFactory entityManagerFactory) {
// functions
return null;
}
}
can anyone tell me what missing and where am making mistakes?
I think you have to use #Order annotation.
#Component
#Order(1)
public class SampleProperties {
// code
}
#Component
#Order(2)
public class SampleConfiguration {
// code
}

#autowired annotation for service class is not working in #configure class spring boot

when i am using #autowire to inject my dependencies in Configuration
class its giving me as null please refer the code below .
#Configuration
public class DataSourceConfig {
#Autowired
AppService appService;
#Bean
public BeanDefinitionRegistryPostProcessor beanPostProcessor() {
return new BeanDefinitionRegistryPostProcessor() {
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanRegistry) throws BeansException {
createBeans(beanRegistry);
}
};
}
private void createBeans(BeanDefinitionRegistry beanRegistry,DataSourceConfigService ds) {
appService.getDbDetails();
appService is null here if i will call it using this way
BeanDefinitionRegistryPostProcessor beanPostProcessor(AppService
appService) then in AppServiceImpl class AppDao dependency will be null
}
}
//// Service
#Service
public class AppServiceImpl implements AppService{
#Autowired
AppDao ds;
#Override
public List<A> getDatabaseConfiguration() {
return ds.getDbDetails(); // here ds is null
}
}
//dao
#Repository
public class AppDaoImpl implements AppDao {
#Qualifier("nameParamJdbcTemplate")
#Autowired
public NamedParameterJdbcTemplate nameParamJdbcTemplate;
#Override
public List<A> getDbDetails() {
return nameParamJdbcTemplate.query(SELECT_QUERY, new DataSourceMapper()); // nameParamJdbcTemplate is null
}
// datasource config
#Configuration
public class DataSourceBuilderConfig {
#Bean(name = "dbSource")
#ConfigurationProperties(prefix = "datasource")
#Primary
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
#Bean(name = "nameParamJdbcTemplate")
#DependsOn("dbSource")
#Autowired
public NamedParameterJdbcTemplate jdbcTemplate1(#Qualifier("dbSource") DataSource dbSource) {
return new NamedParameterJdbcTemplate(dbSource);
}
}
What i want is when ever my beanPostProcessor()
is executed i want all my dependent beans should be instantiated ie
#Autowired
AppService appService;
#Autowired
AppDao ds;
#Qualifier("nameParamJdbcTemplate")
#Autowired
public NamedParameterJdbcTemplate nameParamJdbcTemplate;
I am new to spring so any help or working examples would be great. Thanks
It is null because this #Configuration class also defines a BeanDefinitionRegistryPostProcessor that forces the context to create that bean very early on.
Because you are using field injection, the context has to resolve AppService bean but it can't yet because the post-processor have to be applied first.
Your configuration looks very complex so you may want to simplify it a bit:
Separate low-level infrastructure configuration from main configuration
Always define such post processor as public static method so that the context can invoke the #Bean method without having to construct the class first.

Access to properties from created bean

I have that class as you can see below:
#Configuration
#PropertySource("classpath:sample.properties")
public class SampleConfig {
#Value("${attr1.prop}")
private String attr1;
#Value("${attr2.prop}")
private String attr2;
#Bean
public SampleService sampleService() {
return new SampleService(attr1);
}
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
I created SampleService bean with parameter attr1. Is possible get access to that properties which I load with #PropertySource later? For example after #Autowired.
Here is code of of using that bean:
#Service
public class SuperHotServiceImpl {
#Autowired
SampleService sammpleService;
public void fooFunc() {
// here I need some magic to get value of attr2.prop
sammpleService.setAttr(attr2);
}
}
Can you tell if it is possible an how? Thanks
If I understand properly your question, then this should help:
#Service
public class SuperHotServiceImpl {
#Autowired
private SampleConfig sammpleConfig;
public void fooFunc() {
System.out.println(sampleConfig.getAttr2());
}
}
Supposed that SampleConfig is annotated as #Component and that you provide the getter.

How to enable #ConditionalOnProperty in spring-boot on runtime changeable property

I have two class which depends on config variable:
#Component
#ConditionalOnProperty("config.db")
public class DatabaseTokenStore implements TokenStore {
}
#Component
#ConditionalOnMissingBean(DatabaseTokenStore.class)
public class SimpleTokenStore implements TokenStore {
}
so when db is true then DatabaseTokenStore class is autowired when false then SimpleTokenStore is autowired. Problem is that I can change this property in runtime with CRaSH. Then this mechanic will not work. Is there some way how to change implement of interface in runtime ?
Initialize both TokenStores on startup. And create a resolver to inject into classes where you need to work with them. Like so:
#Component
public class HelloStoreResolver {
#Autowired
private HelloStore oneHelloStore;
#Autowired
private HelloStore twoHelloStore;
public HelloStore get() {
if (condition) {
return oneHelloStore;
} else {
return twoHelloStore;
}
}
}
#Component
public class HelloController {
#Autowired
private HelloStoreResolver helloResolver;
//annotations omitted
public String sayHello() {
return helloResolver.get().hello();
}
}

Categories

Resources