I have a maven multi module project. When trying to Access a injected bean i get a Nullpointer Exception.
this is the main Function that startsthe application
public class App {
public static void main(String[] args) {
System.out.println("Startpoint");
DecisionMaker decisionMaker = new DecisionMaker();
decisionMaker.run();
}
}
this is what i do in the DecisionMaker
public class DecisionMaker {
#Inject
GameListener gm;
#Inject
BasicProductionManager basicProductionManager;
public DecisionMaker() {
System.out.println("this is the decisionmaker");
System.out.println(gm.toString());
}
so this is not an bean but a normal pojo
the gamelistener is a Applicationscoped bean which i want to inject.
#Named
#ApplicationScoped
public class GameListener extends DefaultBWListener {
#Inject
Event<OnFrameEvent> onFrameEvent;
public Mirror mirror = new Mirror();
public Game game;
public Player self;
#PostConstruct
public void init() {
System.out.println("init listener");
}
the nullpointer gets thrown in the constructor of the DecisionMaker. The #PostConscrutct init method is not called
I looked into similar question but all i found is that i needthe PostConstruct method which i already have.
you can't instantiate DecisionMaker yourself. the whole point of CDI is to give it control of creating and managing beans.
check out this article to see how to use CDI in JAVA SE.
Related
I tried constructor based Dependency injection in TestAppListener class which implements ServletContextListener.
I got this error
Exception sending context initialized event to listener instance of class [com.example.listener.TestAppListener].
I searched stack overflow but I couldn't find any solution for this scenario. Please any one help me in sort out this. I placed Implementation classes in META-INF.services folder also. My understanding is there is some problem in constructor dependency injection but this way of DI is need for my situation, because in real time I want to create datasource connection inside startup method.
Find all my classes below which i'm using,
#WebListener
public class TestAppListener implements ServletContextListener {
private static TestDao dao;
public TestAppListener(TestDao dao){
this.dao = dao;
}
public TestAppListener(){}
#Override
public void contextInitialized(ServletContextEvent sce) {
dao = ServiceLoader.load(TestDao.class).iterator().next();
dao.startUp();
System.out.println("Context initialized method called");
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("Context destroyed method called");
dao.shutDown();
}
}
public interface TestDao {
void startUp();
void shutDown();
}
public class TestDaoImpl implements TestDao {
#Override
public void startUp() {
System.out.println("Database is initialized");
}
#Override
public void shutDown() {
System.out.println("Database is initialized");
}
}
#Configuration
public class SpringConfig {
public SpringConfig() {
}
#Bean
public ServletListenerRegistrationBean<ServletContextListener> listenerRegistrationBean() {
ServletListenerRegistrationBean<ServletContextListener> bean = new ServletListenerRegistrationBean<>();
bean.setListener(new TestAppListener());
return bean;
}
}
The Servlet #WebListeners are handled by Servlet containers(tomcat/Jetty) when the container is starting. So they know nothing about Spring.
For more details, see discussion in this issue.
A workaround solution is replace the #WebListener with Spring's #Component, thus you can inject Spring beans(declare your Dao as spring beans) into the listeners directly.
BTW, you have to add #ServletComponentScan on your Spring Boot application class to activate it.
I created an example project to demo #WebServlet, #WebFilter and #WebListener.
Change private static TestDao dao to private final TestDao dao. Spring doesn't allow statics to be used as targets for injection. Also, your TestDaoImpl class needs to be a component or a bean defined in a Spring configuration file.
I have a particular class used to interface with a service that requires initialization. In the application lifecycle, the only place this makes sense is in the start of the application because the rest of the spring application cannot run without it. I had the idea to do this:
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
try {
MyRequiredService mrs = new MyRequiredService();
mrs.connect(); // This will throw if it fails
run(MyApplication.class, args);
} catch(MyException e) {
System.out.println("Failed to connect to MyRequiredService!");
}
}
}
This will launch the service and attempt to connect but I have one big problem. How do I pass this class around the application? I need it's functions in the service endpoints I am writing.
I didn't see anything obvious and searching "passing class instance in spring boot application" turns up a bunch of unrelated topics.
Is there a smart, clean way to do this in spring boot? I apologize for a contrived example. The names of the service are unique enough I didn't want to violate any agreements.
You can make Spring do this for you. First, you need to annotate your class with #Service, so Spring will pick it up when scanning for classes.
Then, define an init() method and annotate it with #PostConstruct. Spring will instantiate your MyRequiredService class and call init()
#Service
public class MyRequiredService {
#PostConstruct
public void init() {
connect();
}
public void connect() {
// ...
}
}
You could call connect() from the constructor, but I don't like to define objects that may throw exceptions out of the constructor.
And then, you can use MyRequiredService in some other class by injecting it via the #Autowired annotation:
#Component
public class MyOtherClass {
private final MyRequiredService service;
public MyOtherClass(final MyRequiredService service) {
this.service = service;
}
// Other methods here.
}
This has the same overall effect as what you're trying to do above. If MyRequiredService fails, the application will not start up.
Make it a bean. Then it will be in the ApplicationContext which then you can pass to your desired other classes through the constructor
#Configuration
public class ApplicationConfiguration
{
#Bean
public MyRequiredService myRequiredService()
{
MyRequiredService mrs = new MyRequiredService();
try {
mrs.connect(); // This will throw if it fails
return mrs;
} catch(MyException e) {
log.error("Failed to connect to MyRequiredService!");
throw new IllegalStateException("MyRequiredService failed connection. Stopping startup");
}
}
#Bean
public SomeOtherService someOtherService(MyRequiredService mrs) {
return new SomeOtherService(mrs);
}
}
IMHO Instead of catching the error and logging it. I would throw it and stop the application from starting, but to keep with your example I added the throw IllegalStateException after the log.
Doing it this way Spring will create your MyRequiredService bean in the ApplicationContext then you can see I added as a parameter needed by the bean below that. Spring will grab that bean out of the ApplicationContext and supply it to the bean. If Spring doesn't find the bean in the ApplicationContext it will throw an error and stop the application from startup.
a class implements BeanFactoryPostProcessor which is init before normal bean
#Configuration
public class MyRequiredService implements BeanFactoryPostProcessor,
PriorityOrdered, InitializingBean {
#Override
public int getOrder() {
return Integer.MIN_VALUE;
}
public void connect() {
// ...
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
#Override
public void afterPropertiesSet() throws Exception {
connect();
}
}
I have a simple Spring boot application that initialize a CLI game.
import com.rpg.game.rpggame.client.RpgGameClient;
#SpringBootApplication
public class RpgGameApplication {
public static void main(String[] args) {
SpringApplication.run(RpgGameApplication.class, args);
RpgGameClient.runGame();
}
}
The runGame() uses some of my services (spring beans).
public class RpgGameClient {
#Autowired
private static GameService gameService;
public static void runGame() {
gameService.createNewGame();
}
}
But I have a NullPointerException when using my service, since Spring can not successfully inject it on my RpgGameClient class.
How can I solve it?
1) RpgGameClient is not declared as a bean candidate. So Spring ignores it.
You can do it by annotating the class with #Component for example (the simplest way) or by declaring a #Bean method that returns the instance of the class.
2) Even with that, it will not work still as #Autowired doesn't work for static fields. Spring injects dependencies into a bean and a bean is an instance of a class.
I think that runGame() should also be non static. Make all static for a bean spring makes no sense. It is the same thing for the Spring boot application class.
3) Constructor injection should be favored to field injection.
So it should be better :
#Component
public class RpgGameClient {
private GameService gameService;
public RpgGameClient(GameService gameService){
this.gameService = gameService;
}
public void runGame() {
gameService.createNewGame();
}
}
And change the Spring Boot app class to use injection dependency such as :
#SpringBootApplication
public class RpgGameApplication {
#Autowired
RpgGameClient rpgGameClient;
#PostConstruct
public void postConstruct(){
rpgGameClient.runGame();
}
public static void main(String[] args) {
SpringApplication.run(RpgGameApplication.class, args);
}
}
I'm using Kinesis Client Library (KCL) and Spring boot. To use KCL, I have to implement a class (I named it RecordProcessor) for interface IRecordProcessor. And KCL will call this class and process records from kinesis. But when I tried to use dependency injection, I found it was not succeeded.
Here's the snippet for RecordProcessor:
#Component
public class RecordProcessor implements IRecordProcessor {
#Autowired
private SingleRecordProcessor singleRecordProcessor;
#Override
public void initialize(String shardId) {
...
}
#Override
public void processRecords(List<Record> records, IRecordProcessorCheckpointer checkpointer) {
...
}
}
I use Class SingleRecordProcessor to process single each record from kinesis. And this is my SingleRecordProcessor class snippet:
#Component
public class SingleRecordProcessor {
private Parser parser;
private Map<String, Table> tables;
public SingleRecordProcessor() {
}
#Autowired
private void setParser(Parser parser) {
this.parser = parser;
}
#Autowired
private void setTables(Map<String, Table> tables) {
this.tables = tables;
}
public void process(String record) {
...
}
}
I want to let spring framework automatically inject the SingleRecordProcessor instance into the class and use it. But I found that the field singleRecordProcessor is null.
Any idea why the dependency injection is failed? Or is it impossible to inject dependencies into a class which is called by other framework (in this case it's KCL)? Any suggestions will be appreciated! Really need some help please!!
[UPDATE]:
Sorry for not expressing the error clearly. The error was NullPointerException. I tried to inject singleRecordProcessor and call method process() on it. I think the injection was not successful so the instance singleRecordProcessor is null and there comes the NullPointerException.
More information is as follows:
I have a major class called Application
#SpringBootApplication
public class Application{
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.addListeners(new ApplicationPidFileWriter("./app.pid"));
ConfigurableApplicationContext ctx = application.run(args);
}
}
And I have the MainProcessor class which will call KCL.
#Service
public final class MainProcessor {
#EventListener(ApplicationReadyEvent.class)
public static void startConsumer() throws Exception {
init();
IRecordProcessorFactory recordProcessorFactory = new RecordProcessorFactory();
Worker worker = new Worker(recordProcessorFactory, kinesisClientLibConfiguration);
...
worker.run(); // this line will call KCL library and eventually call ProcessorRecord class.
}
}
[UPDATE2]
RecordProcessorFactory only has one method like this
#Component
public class RecordProcessorFactory implements IRecordProcessorFactory {
#Autowired
RecordProcessor recordProcessor;
#Override
public IRecordProcessor createProcessor() {
return recordProcessor;
}
}
It creates a new RecordProcessor instance for KCL to use it.
You should autowire an instance of this into your MainProcessor:
#Component
public class RecordProcessorFactory {
#Lookup IRecordProcessor createProcessor() { return null; }
}
Spring will instantiate a RecordProcessorFactory for you, and replace the implementation of createProcessor() in it with one that will return a new IRecordProcessor each time it's called. Both the factory and the processors will be Spring beans - which is what you want.
I am a guice newbie trying to figure out how to implement assisted inject in the guice using FactoryModuleBuilder. I consulted the guice java docs for implementing FactoryModuleBuilder.
I have done everything exactly as it says in the docs.
Its not injecting the factory.
I referred to this stack overflow question :Guice AssistedInject won't inject the factory
which had the same problem.
It talks about the field injection before constructor injection problem. I followed it and I am trying to call the Parent class using a caller class but I am still getting the null pointer exception. What is going wrong here?
Caller class
public class MAIN {
#Inject private static MyFactory factory;
public static void main(String[] args){
ParentClass newbie = new ParentClass(factory);
}
}
I am still getting the exception:
Exception in thread "main" java.lang.NullPointerException
at com.pkg.ParentClass.<init>(ParentClass.java:19)
at com.pkg.MAIN.main(MAIN.java:10)
Parent Class
public class ParentClass {
private final Foo test;
#Inject
public ParentClass(MyFactory factory){
test = factory.create(new HashMap<String,Object>());
}
}
Module Implementation: ParentModule
public class ParentModule extends AbstractModule{
#Override
protected void configure() {
install(new FactoryModuleBuilder()
.implement(Foo.class, FooImpl.class)
.build(MyFactory.class));
}
}
Factory Interface: MyFactory
public interface MyFactory {
Foo create(Map<String,Object> map);
}
Class Interface : Foo
public interface Foo{
}
Class:FooImpl
public class FooImpl implements Foo {
private final Map<String,Object> mapA;
#AssistedInject
public FooImpl(#Assisted Map<String,Object> map){
mapA=map;
}
}
You have two problems here.
First and most important, you are not creating Injector anywhere. Obviously, without an injector nothing will work. You have to create an injector instance using your module:
Injector injector = Guice.createInjector(new ParentModule());
Your second problem is that you want to inject your factory into a static field:
#Inject private static MyFactory factory;
Although Guice can work with static fields if you tell it explicitly, it is considered very bad practice. You should never inject into static fields unless you are working with some legacy code.
What you really want is something like this:
public class Main {
#Inject
private MyFactory factory;
public void run() {
ParentClass newbie = new ParentClass(factory);
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new ParentModule());
Main main = injector.getInstance(Main.class);
main.run();
}
}
Note that program entry point (main) is now creates an injector and then uses it to create an instance of Main class, which will have its field injected automatically. And then it calls method run() on the instance which performs actual work.
Note, however, that this is all really valid only for illustrative purposes for assisted injection. You should not structure your real code like this. For example, you're using new operator to create classes whose constructors are annotated with #Inject. Don't ever do this! If you mark some class (i.e. its constructors or fields) as #Injectable, then this class should be used only by the means of injection. Your Main code can be shortened to the following:
public class Main {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new ParentModule());
ParentClass newbie = injector.getInstance(ParentClass.class);
}
}
Here newbie will automatically receive an instance of MyFactory into its constructor since it is annotated with #Inject.
And I already wrote about statics.