Weld is not injecting - java

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

Related

Best way to call java interface methods after springboot application start up? [duplicate]

I want to run code after my spring-boot app starts to monitor a directory for changes.
I have tried running a new thread but the #Autowired services have not been set at that point.
I have been able to find ApplicationPreparedEvent, which fires before the #Autowired annotations are set. Ideally I would like the event to fire once the application is ready to process http requests.
Is there a better event to use, or a better way of running code after the application is live in spring-boot?
It is as simple as this:
#EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() {
System.out.println("hello world, I have just started up");
}
Tested on version 1.5.1.RELEASE
Try:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application extends SpringBootServletInitializer {
#SuppressWarnings("resource")
public static void main(final String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
context.getBean(Table.class).fillWithTestdata(); // <-- here
}
}
Have you tried ApplicationReadyEvent?
#Component
public class ApplicationStartup
implements ApplicationListener<ApplicationReadyEvent> {
/**
* This event is executed as late as conceivably possible to indicate that
* the application is ready to service requests.
*/
#Override
public void onApplicationEvent(final ApplicationReadyEvent event) {
// here your code ...
return;
}
}
Code from: http://blog.netgloo.com/2014/11/13/run-code-at-spring-boot-startup/
This is what the documentation mentions about the startup events:
...
Application events are sent in the following order, as your application runs:
An ApplicationStartedEvent is sent at the start of a run, but before
any processing except the registration of listeners and initializers.
An ApplicationEnvironmentPreparedEvent is sent when the Environment to be used in the context is known, but before the context
is created.
An ApplicationPreparedEvent is sent just before the refresh is started, but after bean definitions have been loaded.
An ApplicationReadyEvent is sent after the refresh and any related callbacks have been processed to indicate the application is ready to
service requests.
An ApplicationFailedEvent is sent if there is an exception on startup.
...
Why not just create a bean that starts your monitor on initialization, something like:
#Component
public class Monitor {
#Autowired private SomeService service
#PostConstruct
public void init(){
// start your monitoring in here
}
}
the init method will not be called until any autowiring is done for the bean.
The "Spring Boot" way is to use a CommandLineRunner. Just add beans of that type and you are good to go. In Spring 4.1 (Boot 1.2) there is also a SmartInitializingBean which gets a callback after everything has initialized. And there is SmartLifecycle (from Spring 3).
ApplicationReadyEvent is really only useful if the task you want to perform is not a requirement for correct server operation. Starting an async task to monitor something for changes is a good example.
If, however your server is in a 'not ready' state until the task is completed then it's better to implement SmartInitializingSingleton because you'll get the callback before your REST port has been opened and your server is open for business.
Don't be tempted to use #PostConstruct for tasks that should only happen once ever. You'll get a rude surprise when you notice it being called multiple times...
You can extend a class using ApplicationRunner , override the run() method and add the code there.
import org.springframework.boot.ApplicationRunner;
#Component
public class ServerInitializer implements ApplicationRunner {
#Override
public void run(ApplicationArguments applicationArguments) throws Exception {
//code goes here
}
}
Use a SmartInitializingSingleton bean in spring > 4.1
#Bean
public SmartInitializingSingleton importProcessor() {
return () -> {
doStuff();
};
}
As alternative a CommandLineRunner bean can be implemented or annotating a bean method with #PostConstruct.
Best way to execute block of code after Spring Boot application started is using PostConstruct annotation.Or also you can use command line runner for the same.
1. Using PostConstruct annotation
#Configuration
public class InitialDataConfiguration {
#PostConstruct
public void postConstruct() {
System.out.println("Started after Spring boot application !");
}
}
2. Using command line runner bean
#Configuration
public class InitialDataConfiguration {
#Bean
CommandLineRunner runner() {
return args -> {
System.out.println("CommandLineRunner running in the UnsplashApplication class...");
};
}
}
Providing an example for Dave Syer answer, which worked like a charm:
#Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(CommandLineAppStartupRunner.class);
#Override
public void run(String...args) throws Exception {
logger.info("Application started with command-line arguments: {} . \n To kill this application, press Ctrl + C.", Arrays.toString(args));
}
}
I really like the suggestion for usage of the EventListener annotation by #cahen (https://stackoverflow.com/a/44923402/9122660) since it is very clean. Unfortunately I could not get this to work in a Spring + Kotlin setup. What does work for Kotlin is adding the class as a method parameter:
#EventListener
fun doSomethingAfterStartup(event: ApplicationReadyEvent) {
System.out.println("hello world, I have just started up");
}
You have several choices:
Using CommandLineRunner or ApplicationRunner as a Bean definition:
Spring Boot executes these towards the end of the application startup process. In most circumstances, the CommandLineRunner will do the job. Following is an example of a CommandLineRunner implementation with Java 8:
#Bean
public CommandLineRunner commandLineRunner() {
return (args) -> System.out.println("Hello World");
}
Note that the args is the String array of arguments. You can also provide an implementation of this interface and define it as a Spring Component:
#Component
public class MyCommandLineRunner implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
System.out.println("Hello World");
}
}
You can use the ApplicationRunner if you need better argument management. ApplicationRunner takes an ApplicationArguments instance that has enhanced argument management options.
You can also order the CommandLineRunner and ApplicationRunner beans using Spring's #Order annotation:
#Bean
#Order(1)
public CommandLineRunner commandLineRunner() {
return (args) -> System.out.println("Hello World, Order 1");
}
#Bean
#Order(2)
public CommandLineRunner commandLineRunner() {
return (args) -> System.out.println("Hello World, Order 2");
}
Using Spring Boot's ContextRefreshedEvent:
Spring Boot publishes several events at startup. These events indicate the completion of a phase in the application startup process. You can listen to the ContextRefreshedEvent and execute custom code:
#EventListener(ContextRefreshedEvent.class)
public void execute() {
if(alreadyDone) {
return;
}
System.out.println("hello world");
}
ContextRefreshedEvent is published several times. Thus, ensure to put a check whether the code execution is already finished.
Try this one and it will run your code when the application context has fully started.
#Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent arg0) {
// EXECUTE YOUR CODE HERE
}
}
Spring boot provides an ApplicationRunner interface with a run() method to be invoked at application startup.
However, instead of raw String arguments passed to the callback method, we have an instance of the ApplicationArguments class.
#Component
public class AppStartupRunner implements ApplicationRunner {
#Override
public void run(ApplicationArguments args) throws Exception {
//some logic here
}
}
just implement CommandLineRunner for spring boot application.
You need to implement run method,
public classs SpringBootApplication implements CommandLineRunner{
#Override
public void run(String... arg0) throws Exception {
// write your logic here
}
}
you can use #Component
#RequiredArgsConstructor
#Component
#Slf4j
public class BeerLoader implements CommandLineRunner {
//declare
#Override
public void run(String... args) throws Exception {
//some code here
}
If you mean running peace of code once after the application started, you can use the CommandLineRunner as below:
#SpringBootApplication
public class SpringBootApplication
implements CommandLineRunner {
private static Logger LOG = LoggerFactory
.getLogger(SpringBootConsoleApplication.class);
public static void main(String[] args) {
LOG.info("STARTING THE APPLICATION");
SpringApplication.run(SpringBootConsoleApplication.class, args);
LOG.info("APPLICATION FINISHED");
}
#Override
public void run(String... args) {
// enter code you want to run after app loaded here
LOG.info("EXECUTING : command line runner");
for (int i = 0; i < args.length; ++i) {
LOG.info("args[{}]: {}", i, args[i]);
}
}
}
Otherwise, you can use the DevTools dependency, which help you to run new codes without manually restarting the application.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
don't forget to add these codes to your pom.xml to avoid version warnings:
<properties>
<java.version>17</java.version>
<spring-cloud.version>2021.0.3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
give it a thump up if this was helpful to you!
Best way you use CommandLineRunner or ApplicationRunner
The only difference between is run() method
CommandLineRunner accepts array of string and ApplicationRunner accepts ApplicationArugument.

How to enable eager singleton initialization for tests in Micronaut?

I have a case where I have a #Factory annotated class which creates a bean and invokes some code. I have enabled eager singleton initialization and the
bean factory method is invoked even though it is not used anywhere when the application is started. However for tests, the eager initialization does not work and the bean is not created :
Application :
public class Application {
public static void main(String[] args) {
Micronaut.build(args)
.eagerInitSingletons(true)
.mainClass(Application.class)
.start();
}
}
Config
#Factory
public class Config {
#Singleton
#Bean
public Response response() {
System.out.println("Invoked");
//invoking some code
return new Response("test");
}
}
and the test :
#MicronautTest(application = Application.class)
class ApplicationSpec extends Specification {
#Inject
EmbeddedApplication<?> application
void 'test it works'() {
expect:
application.running
}
}
so when the test is executed, the response method from Config class is not invoked even though eagerInitSingletons is enabled and it works when the application is started normally.
The question is : How to enable eager singleton initialization for micronaut tests?
Can you try using a custom context builder?
YourTest Class
#MicronautTest(contextBuilder = CustomContextBuilder.class)
Your CustomContextBuilder:
public class CustomContextBuilder extends DefaultApplicationContextBuilder {
public CustomContextBuilder() {
eagerInitSingletons(true);
}
}

Executing Spring Initializing Beans in Parallel

I have multiple Spring InitializingBean classes, which I'd like them to all run afterPropertiesSet() in parallel. When I run a small example, however, they are being executed synchronously. Is there any way to execute them in parallel?
Below is an example initializing bean which can be used to test out what I'm referring to. When creating multiple classes like this (i.e. InitBeanOne, InitBeanTwo, ...), the logs show that they are being run synchronously.
One idea which I had in mind was to have a single initializing bean asynchronously initialize the desired classes. This is a last resort option, though, as I'd like to take advantage of the initializing beans for each class individually, and not have other dependent classes.
#Component
public class InitBean implements InitializingBean {
private final static Logger LOGGER = LoggerFactory.getLogger(InitBean.class);
#Override
public void afterPropertiesSet() throws Exception {
LOGGER.info("BEGIN: InitBean");
TimeUnit.SECONDS.sleep(5);
LOGGER.info("END: InitBean");
}
}
You should relocate the code to an event listening method, and mark the method with #Async.
Make sure the Async functionality is correctly set up. See: How To Do #Async in Spring.
You should make the method be triggered when the Spring framework fires the ApplicationReadyEvent.
#Component
public class InitBean {
private final static Logger LOGGER = LoggerFactory.getLogger(InitBean.class);
#Async
#EventListener
public void onApplicationReady(ApplicationReadyEvent event) throws Exception {
LOGGER.info("BEGIN: onApplicationReady");
TimeUnit.SECONDS.sleep(5);
LOGGER.info("END: onApplicationReady");
}
}
Warning: By doing this, other methods may be called before/during the invocation of this method. If the method does any kind of initialization needed by those other methods, you need to handle that, e.g. using a CountDownLatch.
UPDATE
If you need for the application to delay the completion of the startup sequence until all asynchronous methods have completed, I think you need to handle it yourself.
Create interface AsyncInitializingBean with same method as InitializingBean, then create a #Component named AsyncBeanInitializer auto-wiring a AsyncInitializingBean[] (or List), then have it execute all the methods using an ExecutorService on ContextRefreshedEvent.
#Component
public class InitBean implements AsyncInitializingBean { // <== Change interface (only change needed)
private final static Logger LOGGER = LoggerFactory.getLogger(InitBean.class);
#Override
public void afterPropertiesSet() throws Exception {
LOGGER.info("BEGIN: InitBean");
TimeUnit.SECONDS.sleep(5);
LOGGER.info("END: InitBean");
}
}
public interface AsyncInitializingBean {
void afterPropertiesSet() throws Exception;
}
#Component
public class AsyncBeanInitializer {
private final static Logger LOGGER = LoggerFactory.getLogger(AsyncBeanInitializer.class);
#Autowired(required = false)
private AsyncInitializingBean[] beans;
#EventListener
public void onContextRefreshed(#SuppressWarnings("unused") ContextRefreshedEvent event) throws Exception {
if (this.beans == null || this.beans.length == 0)
return;
ExecutorService executorService = Executors.newWorkStealingPool();
try {
AtomicInteger failed = new AtomicInteger();
for (AsyncInitializingBean bean : beans) {
executorService.submit(() -> {
try {
bean.afterPropertiesSet();
} catch (Exception e) {
failed.incrementAndGet();
LOGGER.error("Async afterPropertiesSet() method failed: " + e, e);
}
});
}
executorService.shutdown();
executorService.awaitTermination(60, TimeUnit.MINUTES);
if (failed.get() != 0)
throw new RuntimeException(failed.get() + " Async afterPropertiesSet() methods failed. See log for details.");
} finally {
executorService.shutdownNow();
}
}
}

how to use event in weld (cdi)

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.

How to use #PostConstruct to create timers in a stateless bean EJB3?

I want to create a timer EJB3 when a stateless bean is created in the pool.
But if I use #PostConstruct I get the exception:
java.lang.IllegalStateException: [EJB:010193]Illegal call to EJBContext method. The bean is in "null" state. It cannot perform 'getting the Timer Service' action(s). Refer to the EJB specification for more details.
If container calls #PostConstruct, the bean ins't null. So, why I get this exception?
CLASS
#Stateless
public class TestBean implements TestLocal {
#Resource
TimerService timerService;
#PostConstruct
public void startTimer() {
if (timerService.getTimers().size() == 0) {
timerService.createTimer(1 * 1000, 1 * 1000, null);
}
}
#Override
public void test() {
}
}
INTERFACE
#Local
public interface TesteLocal {
void test();
}
SERVLET
public class TestServlet extends HttpServlet {
#EJB
private TestLocal test;
protected void doGet(....) throws .... {
test.test();
}
}
DETAILS
I'm using weblogic server 11g.
You can NOT use a #PostConstruct to create a timer in a stateless bean EJB 3. See this blog How to use EJB 3 timer in a weblogic 10 cluster environment for the explanation. Even the blog was talking about weblogic, but the explanation should apply to other app servers also.
Container will not allow for timerService in method annotated with #PostConstruct of Stateless Session Bean. If you want to use timerService in method annotated with #PostConstruct the go for Singleton session bean(#Singleton).
I'm not 100% sure but I think that the bean class must implement javax.ejb.TimedObject or have a method annotated with #Timeout to use EJB timers. Example:
#Stateless
public class TestBean implements TestLocal {
#Resource
TimerService timerService;
#PostConstruct
public void startTimer() {
if (timerService.getTimers().size() == 0) {
timerService.createTimer(1 * 1000, 1 * 1000, null);
}
}
#Timeout
#TransactionAttribute(value=REQUIRES_NEW)
public void timeoutCallback(Timer timer) {
...
}
}
Does WebLogic still complain with the above code?
PS: In any case, the error you currently get is very poorly reported, you should probably open a case.

Categories

Resources