I am using JBoss EAP 6.4.10 in a project and I have set up a #Singleton with #Startup. This singleton is #Injected into an #Interceptor because I use some methods from it in the interceptor.
So far so good, it basically works, but what I noticed is that the #PostConstruct method of the #Singleton is not called once, nay it is called 496 times. So I wonder why this is happening. Cant I inject a singleton in an interceptor?
I figured out the problem. I had imported import javax.ejb.Singleton; instead of import javax.inject.Singleton;
Related
I have a Quarkus project where I have most of the business logic placed in services, aka injectable beans using #ApplicationScoped annotations, where all of the CRUD operations take place. In the JAX-RS resource files themselves, the bulk of the logic is just validation, often using whole validation beans. This has meant that we needed to mock our injected services when we tested the resources, to prevent the unit tests from becoming essentially integration tests. We do this having a structure like this (example project);
The file MockGreetingService.java in turn looks like this:
import io.quarkus.test.Mock;
import javax.enterprise.context.ApplicationScoped;
#Mock
#ApplicationScoped
public class MockGreetingService extends GreetingService {
#Override
public String sayHello(String name) {
return String.format("Hello %s, your id is %s", name, "1234");
}
}
Our actual project is a bit more sophisticated than this in the way that the mocks always return our DTO classes regardless of input, but the principle is the same as above. They work flawlessly for our JAX-RS resource tests. However, trying to test the actual service beans themselves means problems with this setup. I built a service test, which uses the same annotations and flow as the code below:
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
#QuarkusTest
public class GreetingServiceTest {
#Inject
GreetingService greetingService;
#Test
void checkReturnsHello () {
String result = greetingService.sayHello();
System.out.println(result);
Assertions.assertEquals("hello Martin! Your country is Italy", result);
}
}
With the dependency injection in the class above, which we don't do in our resource tests, I expected Quarkus to understand that we want to use the original service in this test. How foolish of me. A simple log has shown that the mock service methods indeed still run in the latter test above.
Now I wonder - is it a way to disable the mock for this latter test? Preferably without having to modify or remove the mock classes, although I realize that might not be possible in the way I imagine it to be. Thanks in advance!
Sounds like a use case for qualifiers, which enable you to have different implementation beans, and to choose at the injection point which type of bean you prefer:
https://jakarta.ee/specifications/cdi/2.0/cdi-spec-2.0.html#qualifiers
As an alternative, you may also decide to instantiate your service on your own, not using cdi in any way.
Good day, guys. I have a question about autowiring services into my classes when using Springboot. All of the examples I have seen on the Internet as well as in the Springboot specification do something of the like (taking an excerpt from the Springboot version 1.5.7 specification):
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class DatabaseAccountService implements AccountService {
private final RiskAssessor riskAssessor;
#Autowired
public DatabaseAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
This is a class that injects a property through its constructor, by means of #Autowiring the constructor. Another form is to #Autowire the property like this:
#Autowired
private final RiskAssessor riskAssessor
But, where I work, for these two methods to work, I have been told that I need to use this method:
applicationContext.getAutowireCapableBeanFactory().autowireBean(Object.class)
They have told me that I need this in order for the #Autowired annotation to work.
Now my question to you is: why is there no simple annotation that allows the #Autowire to function correctly? (Something like #AutowiredClass). The above method is too verbose and hard to remember, so surely there must be a better way to make #Autowired work on classes in order to inject services, just like we do in Grails where we just say def someService and it is automatically injected.
If you want properly use #Autowired in your spring-boot application, you must do next steps:
Add #SpringBootApplicationto your main class
Add #Service or #Component annotation to class you want inject
Use one of two ways that you describe in question, to autowire
If you don't have any wiered package structure and the main class package includes all other classes you want spring to instantiate (directly or in the subpackages) a simple annotation #ComponentScan on your main class will help you save all those boiler plate code. Then spring will do the magic, it will go and scan the package(and subpackages) and look for classes annotated with #Service, #Component etc and instantiate it.
Even better, use #SpringBootApplication in your main class, this will cover #Configuration as well. If it is a green field project , I would encourage to start from start.spring.io - a template generation/scaffolding tool for spring
Now my question to you is: why is there no simple annotation that allows the #Autowire to function correctly?
There is: #SpringBootApplication
If you put this at the root of your application (file that contains the main class) and as long as your services are at the same package or a sub-package, Spring will auto-discover, instantiate, and inject the proper classes.
There's an example in this walk-through: REST Service with Spring Boot
As described in that page:
#SpringBootApplication is a convenience annotation that adds all of the following:
#Configuration tags the class as a source of bean definitions for the application context.
#EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.
#ComponentScan tells Spring to look for other components, configurations, and services in the hello package, allowing it to find the controllers.
You need to annotate the implementation of RestService as a #Service or #Component so Spring would pick it up.
#Service
public class MyRiskAssessorImpl implements RiskAssessor {
///
}
#Autowired almost works out of the box. Just do your component scanning of the class you want to autowire and you are done. Just make sure your main class (or main configuration class) uses #ComponentScan("{com.example.app}") or #SpringBootApplication (main class). The docs explain this stuff pretty good
I use Jersey 2 on a standalone Grizzly webserver. HK2 is used for CDI. I'd like to get a service with #PerLookup-scope injected into a jersey ContainerRequestFilter.
The service:
import org.glassfish.hk2.api.PerLookup;
import org.jvnet.hk2.annotations.Service;
#Service
#PerLookup
public class SessionManager {
[...]
}
The filter:
import javax.annotation.Priority;
import javax.inject.Inject;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.ext.Provider;
#Provider
#Priority(Priorities.AUTHENTICATION)
#PreMatching
public class HttpSessionFilter implements ContainerRequestFilter {
#Inject
private javax.inject.Provider<org.glassfish.grizzly.http.server.Request> requestProvider;
#Inject
private SessionManager sessionManager;
[...]
}
My problem is this:
the filter is instantiated once (at startup)
the service is injected once (at filter-startup)
everything downstream from there is happening effectively at singleton scope
Question: how can I get the service injected per-request?
Update
The suggested approach using #Inject javax.inject.Provider<SessionManager> sessionManagerProvider makes logical sense to me, but sessionManagerProvider.get() returns null.
The hk2 serviceLocator is populated through the inhabitant-generator. It reports:
SystemDescriptor(
implementation=com.skalio.skaliopush.http.SessionManager
contracts={com.skalio.skaliopush.http.SessionManager}
scope=org.glassfish.hk2.api.PerLookup
qualifiers={}
descriptorType=CLASS
descriptorVisibility=NORMAL
metadata=
rank=0
loader=null
proxiable=null
proxyForSameScope=null
analysisName=null
id=31
locatorId=0
identityHashCode=494317290
reified=false)
And if I add the explicit binding, then it is also found like this:
SystemDescriptor(
implementation=com.skalio.skaliopush.http.SessionManager
contracts={com.skalio.skaliopush.http.SessionManager}
scope=org.glassfish.jersey.process.internal.RequestScoped
qualifiers={}
descriptorType=CLASS
descriptorVisibility=NORMAL
metadata=
rank=0
loader=org.glassfish.hk2.utilities.binding.AbstractBinder$2#78b729e6
proxiable=null
proxyForSameScope=null
analysisName=null
id=39
locatorId=0
identityHashCode=2041416495
reified=false)
2nd Update
I am using two service locators: One created explicitly, and populated through the HK2 inhabitant generator; and the one that Jersey creates. They are joined through a BridgingInjectionResolver.
#peeskillet's response works, when I add the explicit binding to Jersey's service locator. Adding the binding to the other service locator results in the above (sessionManagerProvider.get() returns null).
It should work if you also use javax.inject.Provider<SessionMananger>. The default scope is per lookup. But I guess you need to load it lazily.
Not sure how it differs functionally from RequestScoped in Jersey. I thought that in a PerLookup scope, it would get created twice if I inject it once into the filter and once into the resource class, but just testing right now, even in PerLookup scope, it was still only created once for each request.
Alternatively, just to be sure, you may just want to bind it in a RequestScoped if that is what you really want.
register(new AbstractBinder(){
protected void configure() {
bind(SessionManager.class).to(SessionManager.class)
.in(RequestScoped.class);
}
});
I'm new to Java and Spring, coming from C# and the .NET world, so bear with me - what I am attempting to do may be off the mark...
I am attempting to configure Spring DI using Java configuration and annotations, not XML configuration, however I am having a few issues. This is for a standalone application, not a web app. I have worked through the springsource documentationand as far as I can tell my very basic configuration should be correct...but isn't. Please take a look at the code below:
Java Configuration Annotated Class:
package birdalerter.common;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import birdalerter.process.ISightingsProcessor;
import birdalerter.process.SightingsProcessor;
#Configuration
#ComponentScan({"birdalerter.process", "birdalerter.common"})
public class AppConfig {
#Bean
#Scope("prototype")
public ISightingsProcessor sightingsProcessor(){
return new SightingsProcessor();
}
}
Configure Component implementing the ISightingsProcessor interface:
package birdalerter.process;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import org.springframework.stereotype.Component;
import birdalerter.domainobjects.IBirdSighting;
#Component
public class SightingsProcessor implements ISightingsProcessor{
private LinkedBlockingQueue<IBirdSighting> queue;
private List<ISightingVisitor> sightingVisitors = new ArrayList<ISightingVisitor>();
public SightingsProcessor(){
}
...
}
Configure Factory Component:
package birdalerter.process;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
public class ProcessorFactory {
private ISightingsProcessor sightingsProcessor;
#Autowired
#Required
private void setSightingsProcessor(ISightingsProcessor sightingsProcessor){
this.sightingsProcessor = sightingsProcessor;
}
public ISightingsProcessor getSightingsProcessor(){
return this.sightingsProcessor;
}
}
Wire up the AnnotationConfigApplicationContext and test:
#Test
public void testProcessingDI(){
#SuppressWarnings("resource")
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
context.refresh();
ISightingsProcessor processor = new ProcessorFactory().getSightingsProcessor();
System.out.println(processor);
Assert.assertTrue(processor != null);
}
The SightingsProcessor is not being setter injected and the assert is failing as the returned object is null. Hopefully I have missed something very obvious.
Thanks in advance.
Edited in Response to Meriton:
Thanks for the answer Meriton.
Why would Spring not know about the newly created object? Does Spring not maintain dependencies throughout the application lifecycle and inject as appropriate when new objects are created that are configured as beans?
I don't want to directly use context.getBean(ISightingsProcessor.class) if I can help it to be honest, I would like the dependency injected in the setter method without having manual intervention - it just seems cleaner.
I am using the ProcessorFactory as the ISightingsProcessor interface extends Runnable - the implementing object is to be started as a thread. The application will be configurable to have n* threads, with each being started within a loop iteration. I don't think it is possible (I may be wrong, please advise if so) to have #Autowired annotations within method declarations, hence I use the factory to supply a new instance of the injected ISightingsProcessor concrete class.
Yes I've just had a look regarding the #Scope annotation - you are right, that needs moving to the AppConfig #Bean declaration (which I've done in this edit), thanks for that.
ISightingsProcessor processor = new ProcessorFactory().getSightingsProcessor();
This calls the constructor of ProcessorFactory, and then the getter of the instance the constructor created. Spring can not know about that newly created object, and therefore not inject its dependencies. You should ask Spring for the ProcessorFactory instead, for instance with
ProcessorFactory pf = context.getBean(ProcessorFactory.class);
ISightingsProcessor processor = pf.getSightingsProcessor();
That said, I don't know why you need class ProcessorFactory at all. You might just as well get the ISightingsProcessor directly:
ISightingsProcessor processor = context.getBean(ISightingsProcessor.class);
Additionally, "Java Based Configuration" and component scanning are independent ways to declare beans. Currently, you are therefore declaring the ISightingsProcessor twice: Once with the #Bean-annotated factory method, and once with the component scan and the #Component annotation on the class. Doing either of that will do. In fact, doing both might cause one bean definition to override the other.
Oh, and the #Scope annotation is for bean definitions (those you annotate with #Bean or #Component). It will likely be ignored on injection points (#Autowired).
I am trying to do something at startup using a startup ejb. But my bean is never called.
This is my bean:
import javax.annotation.PostConstruct;
import javax.ejb.Startup;
import javax.inject.Singleton;
#Singleton
#Startup
public class StartupBean {
#PostConstruct
public void doSomething(){
System.out.println("why??");
}
}
I am using jboss 7.1.1.
What am i doing wrong? You can find my source code at bitbucket: https://bitbucket.org/cremersstijn/jee/src/9e22ed2b798a/simple-startup-bean
You're importing the wrong Singleton. If you want to create a singleton session bean, use javax.ejb.Singleton.
http://docs.oracle.com/javaee/6/api/javax/ejb/Singleton.html
vs.
http://docs.oracle.com/javaee/6/api/javax/inject/Singleton.html