Reputation: 7356
I have a simple SpringBoot application in which i am using the Environment.class
to access the properties under application.properties
file. The Environment
bean works when it is accessed in the main
method of the Application.class
@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = "com.cisco.sdp.cdx.consumers")
public class StreamingConsumerApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(StreamingConsumerApplication.class, args);
Environment env = context.getBean(Environment.class);
StreamingConsumerFactory factory = context.getBean(StreamingConsumerFactory.class);
StreamingConsumer streamingConsumer = factory.createStreamingConsumer(StreamType.valueOf(env.getRequiredProperty("streaming.application.type")));
streamingConsumer.consume();
}
}
When the same is used in a different class it throws NullPointerException
. I tried annotating the class with @Configuration
,@Component
,@Repository
,@Service
annotations but did not work.
I tried @Autowired
as well as @Resource
annotations. But, it didn't work.
@Component
public class InventoryStreamingConsumer implements StreamingConsumer {
@Autowired
private Environment env;
@Autowired
private JavaSparkSessionSingleton sparksession;
@Autowired
private StreamingContext _CONTEXT;
private final Map<String, String> kafkaParams = new HashMap<String, String>();
@Override
public void consume() {
if(env == null) {
System.out.println("ENV is NULL");
}
System.out.println(env.getRequiredProperty("kafka.brokerlist"));
kafkaParams.put("metadata.broker.list", env.getRequiredProperty("kafka.brokerlist"));
Set<String> topics = Collections.singleton(env.getRequiredProperty("kafka.topic"));
// Unrelated code.
}
I tried following the answers provided in the below questions
Spring Boot - Environment @Autowired throws NullPointerException
I am looking for suggestions on solving the issue.
Upvotes: 1
Views: 9216
Reputation: 3357
I have similar issue but read the properties from different file and different location like common/jdbc.properties. I solved this issue by doing this:
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
@Configuration
@PropertySource(value = {"classpath:common/jdbc.properties"})
public class ExternalConfig implements EnvironmentAware {
private Environment environment;
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
public String getJdbcUrl() {
return environment.getProperty("jdbc.url");
}
}
Upvotes: 1
Reputation: 1704
The @Configuration
annotation is misused here for InventoryStreamingConsumer
. Try @Component
, @Repository
or @Service
.
UPDATE
Another misuse is
StreamingConsumer streamingConsumer = factory.createStreamingConsumer(StreamType.valueOf(env.getRequiredProperty("streaming.application.type")));
@Autowired
or @Resource
can only work in bean
created by Spring
. the streamingConsumer
created by your StreamingConsumerFactory factory
cannot use @Autowired
for injection of its properties.
You should create an @Configuration
class, to tell Spring
to create streamingConsumer
from your factory. Like this
@Configuration
public class ConsumerCreator {
@Autowired
StreamingConsumerFactory factory;
@Bean
public StreamingConsumer streamingConsumer() {
return factory.createStreamingConsumer(StreamType.valueOf(env.getRequiredProperty("streaming.application.type")));
}
}
And use no annotation for InventoryStreamingConsumer
, meanwhile use
StreamingConsumer streamingConsumer = context.getBean(StreamingConsumer.class);
in your StreamingConsumerApplication.main()
method instead to retrieve streamingConsumer
Upvotes: 2
Reputation: 1465
First, please annotate the main class with only @SpringBootApplication
@SpringBootApplication
public class StreamingConsumerApplication {
}
@ComponentScan
is required if your packages are not within the same structure as main class with main class being outside the sub-package and inside parent package with every other class in the same or some sub-package of parent package.
Second, Please create a Configuration class and annotate it with @Configuration
separately and define a @Bean
there for StreamingConsumer streamingConsumer
and than it can be @Autowired
or injected in the InventoryStreamingConsumer
class.
Third, where is the @Bean
for JavaSparkSessionSingleton defined? Are you sure it can be AutoConfigured for injection
Fourth, InventoryStreamingConsumer
can be a @Component
, injecting Environment
with @Autowiring
will work once the above things are sorted.
Also, recommending to change your class to this for the sake depending on how consume()
method is used.
@Component
public class InventoryStreamingConsumer implements StreamingConsumer {
private final Environment env;
private final JavaSparkSessionSingleton sparksession;
private final StreamingContext _CONTEXT;
private final Map<String, String> kafkaParams = new HashMap<String, String>();
@Autowired
public InventoryStreamingConsumer(Environment env, JavaSparkSessionSingleton sparkSession, StreamingContext context) {
this.env = env;
this.sparksession = sparkSession;
this._CONTEXT = context;
}
@Override
public void consume() {
if(env == null) {
System.out.println("ENV is NULL");
}
System.out.println(env.getRequiredProperty("kafka.brokerlist"));
kafkaParams.put("metadata.broker.list", env.getRequiredProperty("kafka.brokerlist"));
Set<String> topics = Collections.singleton(env.getRequiredProperty("kafka.topic"));
// Unrelated code.
}
Upvotes: 1
Reputation: 7624
Try adding
@PropertySource("classpath:application.properties")
on InventoryStreamingConsumer class
This is how am using it
@Configuration
@ComponentScan({ "com.spring.config" })
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class HibernateConfiguration {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
@Autowired
private Environment env;
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
Upvotes: 0