I am studying Weld Event from jboss weld event tutorial and I want to write an example which observes an event and print helloword when it was fired.
this is my code:
//MyEvent when it was fired, print HelloWorld
public class MyEvent{}
//observe MyEvent and when it happen print HelloWorld
public class EventObserver {
public void demo(#Observes MyEvent event){
System.out.println("HelloWorld");
}
}
//Main Class fire Event in demo method
public class EventTest {
#Inject #Any Event<MyEvent> events;
public void demo(){
Weld weld = new Weld();
WeldContainer container = weld.initialize();
events.fire(new MyEvent());
container.shutdown();
}
public static void main(String[] args){
EventTest test = new EventTest();
test.demo();
}
}
it doesnt work and give below exception info:
Exception in thread "main" java.lang.NullPointerException
at weldLearn.event.EventTest.demo(EventTest.java:18)
at weldLearn.event.EventTest.main(EventTest.java:24)
it seems that there are no beans in container which can initialize
Event<MyEvent> events;
Then what should I do to make it running, my
beans.xml is empty
Maybe I should do something in beans.xml?
or I should write a java class implements Event interface?
anything will be apprecited.
Basically, your code fails because you're not using a managed instance of your class. Here's a better way to do it
#ApplicationScoped
public class EventTest {
#Inject Event<MyEvent> events;
public void demo(){
events.fire(new MyEvent());
}
public static void main(String[] args){
Weld weld = new Weld();
WeldContainer container = weld.initialize();
EventTest test = container.select(EventTest.class).get();
test.demo();
container.shutdown();
}
}
You start the container in main, and use a managed reference to your class. Injection points are only resolved when you're using managed references.
Related
I will simplify the code to make my question easier to understand. The code is something like that:
import sample.backend.*;
import sample.frontend.*;
public class Game {
public void run(){
GameBackendImpl gameBackend = new GameBackendImpl();
GameUIImpl gameUI = new GameUIImpl();
}
}
And this next would be my main code, which I have separated for easy testing.
public class Main {
public static void main(String[] args) {
Game game = new Game();
game.run();
}
}
My question here is to know if it is possible to inject a backend and a frontend instance into the Game class from the Main class, using dependency injection.
Thanks in advance
In this simplified case the dependency injection means just creating the instances of the classes you need in the main() method and passing them to the constructor of the Game class:
public class Game {
privat final GameBackend backend;
privat final GameUI ui;
public Game(GameBackend gameBackend, GameUI gameUI) {
this.backend = gameBackend;
this.ui = gameUI;
}
public void run(){
...
}
}
Main class:
public class Main {
public static void main(String[] args) {
GameBackend gameBackend = new GameBackendImpl();
GameUI gameUI = new GameUIImpl();
Game game = new Game(gameBackend, gameUI);
game.run();
}
}
But this approach, of course, doesn't bring the advantages of the Dependency Injection/Inversion of Control.
I guess you are looking for the possibility to inject your dependencies automatically and to be able to configure them according to your needs (different implementations for different environments etc.). In this case you can use a framework like Spring which will take control on the program flow, instantiating and injecting the dependencies into corresponding classes.
The simple implementation using Spring Boot would be the following:
GameBackend.java:
public interface GameBackend {
String getVersion();
}
GameUI.java:
public interface GameUI {
String getVersion();
}
GameBackendImpl.java:
#Component
public class GameBackendImpl implements GameBackend {
#Override
public String getVersion() {
return "Backend_v1";
}
}
GameUiImpl.java:
#Component
public class GameUiImpl implements GameUI {
#Override
public String getVersion() {
return "UI_v1";
}
}
Game.java:
#Component
public class Game {
private final GameBackend backend;
private final GameUI ui;
#Autowired
public Game (GameBackend backend, GameUI ui) {
this.backend = backend;
this.ui = ui;
}
public void run() {
System.out.println("Game bean instantiated with the UI '"+this.ui.getVersion()+"' and Backend '"+this.backend.getVersion()+"' versions");
}
}
SpringBootDemoApp.java:
#SpringBootApplication
public class SpringBootDemoApp implements CommandLineRunner {
#Autowired
ApplicationContext applicationContext;
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApp.class, args);
}
#Override
public void run(String... args) {
((Game)(applicationContext.getBean("game"))).run();
}
}
What happens here:
Spring scans classes in the package and finds Beans annotated with the #Component annotation.
Upon instantiating the Game class, Spring considers its constructor, which is annotated with #Autowired and requires exactly 2 parameters (dependencies), and looks for the candidates to be injected. In this case there is only one candidate per each type (you can create multiple different implementations of the GameBackend and GameUI interfaces). Thus, all the preparation work is done by the framework.
There is much more happening under the hood of course.
In the main class, we can check the result by getting the instance of the Game class (Bean with the name "game) from the ApplicationContext. Calling its run() method will print:
"Game bean instantiated with the UI 'UI_v1' and Backend 'Backend_v1' versions"
NOTE: getting and using the instance of the Game class from the main class doesn't bring any advantages and is done only for the demonstration.
There are more DI/IoC frameworks for Java (CDI in J2EE, Guice etc.)
I need to autowire a bean in a standalone main program as i need to set Up some data . Main program has a dependency on "MyDependencyClass" to set up some services.
I am unclear as to how to get the ApplicationContext as the "MyDependencyClass" is not declared in any spring xml,nor the class is annotated. Please help.
My main program :
public class Main {
#Autowired
private MyDependencyClass myDepClass
public static void main(String[] args) {
Main main1 = new Main();
main1.callDep();
}
private void callDep(){
myDepClass.setUp();
}
}
MyDependencyClass:
public class MyDependencyClass {
public void setUp() {
Sysout("Setting up");
}
}
IF you don't define beans in .xml you need to use #Component or #Repository annotation based on your class type. annotations
Im fairly new to Java Spring IoC and here's my problem
I have a FactoryConfig class with all beans and annotation #Configuration and #ComponentScan written as below.
import org.springframwork.*
#Configuration
#ComponentScan(basePackages="package.name")
public class FactoryConfig {
public FactoryConfig() {
}
#Bean
public Test test(){
return new Test();
}
//And few more #Bean's
}
My Test class has a simple Print method
public class Test {
public void Print() {
System.out.println("Hello Test");
}
}
Now in my Main Class Ive created an ApplicationContentext of FactoryConfig. (I'm expecting all of my #Beans in Factory config will be initialised. However, it returns null when I access the Test class using #Autowired
My Main Class
public class Main {
#Autowired
protected static Test _autoTest;
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ApplicationContext context =
new AnnotationConfigApplicationContext(FactoryConfig.class);
FactoryConfig config = context.getBean(FactoryConfig.class);
config.test().Print();
// _autoTest.Print(); <--- Im getting NULL Pointer Ex here
}
}
What is the correct way to #Autowire and use objects/beans? any clearer explanation would be much appreciated.
Only beans managed by Spring can have #Autowire annotations. Your main class is not managed by Spring: it's created by you and not declared in a Spring context: Spring doesn't known anything about your class, and doesn't inject this property.
You can just access in your main method the Test bean with :
context.getBean(Test.class).Print();
Usually, you get a "bootstrap" from the context, and call this bootstrap to start your application.
Moreover:
On Java, a method shouldn't start with an uppercase. Your Test class should have a print method, not Print.
If you start with Spring, you should maybe try Spring Boot
Spring does not manage your Main class, that's why you are getting Nullpointer Exception.
Using ApplicationContext to load beans, you can get your beans and access Methods as you are already doing -
ApplicationContext context =
new AnnotationConfigApplicationContext(FactoryConfig.class);
FactoryConfig config = context.getBean(FactoryConfig.class);
config.test().Print();
remove the static argument
protected Test _autoTest;
Your class
public class Test {
public void Print() {
System.out.println("Hello Test");
}
}
is not visible to Spring. Try adding an appropriate annotation to it, like #Component.
The reason is that your Main is not managed by Spring. Add it as bean in your configuration:
import org.springframwork.*
#Configuration
#ComponentScan(basePackages="package.name")
public class FactoryConfig {
public FactoryConfig() {
}
#Bean
public Test test(){
return new Test();
}
#Bean
public Main main(){
return new Main();
}
//And few more #Bean's
}
And then you can edit your main() as follows:
public class Main {
#Autowired
protected Test _autoTest;
public static void main(String[] args) throws InterruptedException {
ApplicationContext context =
new AnnotationConfigApplicationContext(FactoryConfig.class);
Test test = context.getBean(Test.class);
Main main = context.getBean(Main.class);
test.Print();
main._autoTest.Print();
}
}
I have the following main class:
public class Startup implements UncaughtExceptionHandler {
#Autowired
private MessageListener messageListener;
private static Startup startup;
public static void main(String[] args) {
Startup start = new Startup();
start.init(args);
}
public void init(String[] args) {
context = new ClassPathXmlApplicationContext("applicationContext.xml");
startup = (Startup) context.getBean( "startup" );
startup.start(); //here the messageListener is used
}
// here goes the main class that calls the method where messageListener is used
}
#Component
public class ProdMessageListener
extends AbstractMessageListener implements MessageListener {...}
and
public abstract class AbstractMessageListener
implements MessageListener {...}
as well as
#Component
public interface MessageListener extends QueueAware {...}
#Component
public interface QueueAware {...}
My Spring context uses to locate all the classes and interfaces.
However the bean is not recognized and I get:
No qualifying bean of type
[com.ware.messaging.listener.MessageListener] found for
dependency.
Any ideas why autowiring does not work?
Just make sure you have added your base package to the spring context configuration like below to allow spring to load all the components into the container
<context:component-scan base-package="pakage1.package2"/>
Do you know what the problem was? Spring does not seem to autowire static fields. Now everything works.
I'm trying to set up a very simple implementation of weld in java SE.
I have the extension class:
public class MyExtension implements Extension {
void beforeBeanDiscovery(#Observes BeforeBeanDiscovery bbd) {
System.out.println("Starting scan...");
}
<T> void processAnnotatedType(#Observes ProcessAnnotatedType<T> annotatedType, BeanManager beanManager) {
System.out.println("Scanning type: " + annotatedType.getAnnotatedType().getJavaClass().getName());
}
void afterBeanDiscovery(#Observes AfterBeanDiscovery abd) {
System.out.println("Finished the scanning process");
}
public void main(#Observes ContainerInitialized event) {
System.out.println("Starting application");
new Test();
}
}
I then have a simple class that I want to inject:
public class SimpleClass {
public void doSomething() {
System.out.println("Consider it done");
}
}
And lastly the class I want to inject it in:
public class Test {
#Inject
private SimpleClass simple;
#PostConstruct
public void initialize() {
simple.doSomething();
}
#PreDestroy
public void stop() {
System.out.println("Stopping");
}
}
The resulting output is:
80 [main] INFO org.jboss.weld.Version - WELD-000900 1.1.10 (Final)
272 [main] INFO org.jboss.weld.Bootstrap - WELD-000101 Transactional services not available. Injection of #Inject UserTransaction not available. Transactional observers will be invoked synchronously.
Starting scan...
Scanning type: test.Test
Scanning type: test.SimpleClass
Scanning type: test.MyExtension
640 [main] WARN org.jboss.weld.interceptor.util.InterceptionTypeRegistry - Class 'javax.ejb.PostActivate' not found, interception based on it is not enabled
640 [main] WARN org.jboss.weld.interceptor.util.InterceptionTypeRegistry - Class 'javax.ejb.PrePassivate' not found, interception based on it is not enabled
Finished the scanning process
Starting application
I would expect the simple class to be injected when Test() is constructed and the postconstruct method to be called which should output the expected text.
What exactly am I doing wrong?
There's two issues with your code:
Problem 1:
CDI does not manage beans created with new. For the most part you need to #Inject a bean in order for its life cycle to be managed by the container
Problem 2:
For the most part, you cannot inject bean instances into observers of container events. That's because the events are firing as the container is being initialized, aka before it can actually begin managing object life cycles.
You could hook the container initializer observer directly into your Test class. Something like this:
public class SimpleClass {
public void doSomething() {
System.out.println("Consider it done");
}
#PostConstruct
public void initialize() {
System.out.println("Starting");
}
#PreDestroy
public void stop() {
System.out.println("Stopping");
}
}
public class Test {
#Inject
private SimpleClass simple;
public void main(#Observes ContainerInitialized event) {
System.out.println("Starting application");
simple.doSomething();
}
}
What you're doing wrong is calling new Test(). This constructs a new instance of Test, but in the back of CDI. For CDI to inject your Test instance, CDI has to create it itself.
See the documentation for how to boostrap Weld in a Java SE environment.
Create a utils class with #ApplicationScoped. This class can produce objects of every type. In your case this is just like this:
#Produces
static SimpleClass generateSimpleClass(){
return new SimpleClass();
}
Otherwise, if simpleclass for you is going to be a unique class in the application, set its class as #ApplicationScoped. Problem is that weld does not know that the class belongs to the container if there is neither annotation nor producer