I am developing a REST API using Jersey 2 and I need some of my classes to be instantiated on start up and not just when some resource request triggers it.
So what I am asking is: how do I achieve that an instance of SomethingImpl defined below here is created on server start up and not just when someone hits the something resource? In Guice I would use .asEagerSingleton().
Application:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new AbstractBinder() {
#Override
protected void configure() {
bind(" else").to(String.class);
bind(SomethingImpl.class).to(Something.class).in(Singleton.class);
}
});
register(SomeResource.class);
}
}
Something:
public interface Something {
String something();
}
public class SomethingImpl implements Something {
#Inject
public SomethingImpl(final String something) {
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
System.out.println(something() + something);
try {
Thread.sleep(4000);
} catch (final InterruptedException e) {
break;
}
}
}
}).start();
}
#Override
public String something() {
return "Something";
}
}
Some resource:
#Path("/")
public class SomeResource {
private final Something something;
#Inject
public SomeResource(final Something something) {
this.something = something;
}
#GET
#Path("something")
public String something() {
return something.something();
}
}
In a later release of hk2 than is integrated with Jersey (but which will be integrated soon) you can have services that are marked #Immediate. These basically get started as soon as they are added to hk2. However, in order to make it work you will have to add the Immediate context to the system (e.g. https://hk2.java.net/2.2.0-b27/apidocs/org/glassfish/hk2/utilities/ServiceLocatorUtilities.html#enableImmediateScope%28org.glassfish.hk2.api.ServiceLocator%29)
It would be a good idea to lobby with the Jersey team to have this scope/context pair enabled by default (they already enable things like PerThread scope)
I have created this issue: https://java.net/jira/browse/JERSEY-2291 to request that Jersey enable #Immediate services by default
Write an implementation of a javax.servlet.ServletContextListener and add that listener to your web xml.
http://www.mkyong.com/servlet/what-is-listener-servletcontextlistener-example/
Besides what msknapp said, you can also use #WebListener for the servlet context listener so that you don't have to add the listener to web.xml. Then your listener will look like
#WebListener
public class SomethingListener implements ServletContextListener {
#Inject
private final Something something;
#Override
public void contextInitialized(ServletContextEvent sce) {
//put code about something here
}
}
Related
Let's say I have a custom ConstraintValidator:
public class FooValidator implements ConstraintValidator<ValidFoo, String> {
#Override
public void initialize(final ValidFoo foo) {
// No-op
}
#Override
public boolean isValid(final String foo, final ConstraintValidatorContext context) {
}
}
I'd like to be able to initialize this class by passing some configuration from the ServiceConfiguration in Dropwizard run or initialize.
Is this possible?
First, it's worth noting that the upcoming Dropwizard 2.0.0 release has built in support for this
For now, the process is a bit involved. You basically want to re-bootstrap the Hibernate validation but with a custom constraint validator factory that would support injection.
It's gonna involve about 4 custom classes, so bear with me. Here goes:
First, we start by registering a custom feature to wrap this functionality, into our Application class:
public void run(MainConfiguration config, Environment environment) throws Exception {
// ...
environment.jersey().register(InjectingValidationFeature.class);
}
Now we define the feature: InjectingValidationFeature - it basically registers our custom implementations within the service container:
public class InjectingValidationFeature implements Feature {
#Override
public boolean configure(FeatureContext context) {
context.register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(ValidatorFactory.class).to(Validator.class).in(Singleton.class);
bind(InjectingConfiguredValidator.class).to(ConfiguredValidator.class).in(Singleton.class);
bind(InjectingConstraintValidatorFactory.class).to(ConstraintValidatorFactory.class).in(Singleton.class);
}
});
return true;
}
}
Now we define those classes that we are registering above. Let's start with the core piece, the InjectingConstraintValidatorFactory which is what Hibernate Validator will actually use to create the constraint validators. Note that because we are registering them in the container, we can actually start injecting stuff already, here is our custom ConstraintValidatorFactory making use of the service locator to make dependency injection possible:
public class InjectingConstraintValidatorFactory implements ConstraintValidatorFactory {
private final ServiceLocator serviceLocator;
#Inject
public InjectingConstraintValidatorFactory(ServiceLocator serviceLocator) {
this.serviceLocator = serviceLocator;
}
#Override
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
return this.serviceLocator.createAndInitialize(key);
}
#Override
public void releaseInstance(ConstraintValidator<?, ?> instance) {
this.serviceLocator.preDestroy(instance);
}
}
Now our factory for the central javax.validation.Validator interface:
public class ValidatorFactory implements Factory<Validator> {
private final ConstraintValidatorFactory constraintValidatorFactory;
#Inject
public ValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) {
this.constraintValidatorFactory = constraintValidatorFactory;
}
#Override
public Validator provide() {
return Validation.byDefaultProvider().configure().constraintValidatorFactory(
this.constraintValidatorFactory).buildValidatorFactory()
.getValidator();
}
#Override
public void dispose(Validator instance) {
// Nothing
}
}
And finally, our InjectingConfiguredValidator, notice how it's just using DropwizardConfiguredValidator but with an #Inject which would allow us to receive the validator from our ValidatorFactory above:
public class InjectingConfiguredValidator extends DropwizardConfiguredValidator {
#Inject
public InjectingConfiguredValidator(Validator validator) {
super(validator);
}
}
That's it. With the above, we managed to both register an injection-aware Validator with Jersey and also into our service container so you can also #Inject Validator anywhere and use it however you like.
I'm trying to get the Guava EventBus as Singleton and session based in a Vaadin application with spring boot but i cannot get it working so far. The session based one works but not the singleton one.The idea is to implement a global notification service, so that specific users get informed in case of new events. I tried following:
public class Configuration{
#Scope("singleton")
#Bean
public EventBus globalEventBus(){
return new EventBus("globalEventBus");
}
#SessionScoped
#Bean
public EventBus eventBus(){
return new EventBus();
}
}
Hey I solved it like this:
I wrapped the Eventbus in a custom class in my case "TimeSaverEventBus"
In TimeSaverUI I added a private instance of TimeSaverEventBus and added the public static method getEventBus():TimeSaverEventbus
I added static methods to TimeSaverEventbus calling timeSaverUI.getEventbus() and then accessing the private Eventbus instance.
The Code looks like this:
#SpringUI
public class TimeSaverUI extends UI {
private TimeSaverEventBus eventBus = new TimeSaverEventBus();
#Override
protected void init(VaadinRequest vaadinRequest) {
TimeSaverEventBus.register(this);
updateContent();
}
private void updateContent() {
...
}
...
public static TimeSaverEventBus getTimeSaverEventbus() {
return ((TimeSaverUI) getCurrent()).eventBus;
}
}
and the EvenBusWrapper:
public class TimeSaverEventBus implements SubscriberExceptionHandler {
private final EventBus eventBus = new EventBus(this);
public static void post(final Object event) {
TimeSaverUI.getTimeSaverEventbus().eventBus.post(event);
}
public static void register(final Object object) {
TimeSaverUI.getTimeSaverEventbus().eventBus.register(object);
}
public static void unregister(final Object object) {
TimeSaverUI.getTimeSaverEventbus().eventBus.unregister(object);
}
#Override
public final void handleException(final Throwable exception,
final SubscriberExceptionContext context) {
exception.printStackTrace();
}
}
With implementing this in that way you are able to register and unregister event listeners or post events by calling the static methods of TimeSaverEventBus.
I really hope that is what you are looking for.
Cheers,
Felix
I think all you need to do is use a name for your beans. So it would work something like this.
public class Configuration{
#Scope("singleton")
#Bean(name="globalEventBus")
public EventBus globalEventBus(){
return new EventBus("globalEventBus");
}
#SessionScoped
#Bean(name="sessionEventBus")
public EventBus eventBus(){
return new EventBus();
}
}
Then when you want to autowire use this
#Autowired
#Qualifier("globalEventBus")
private EventBus globalEventBus;
#Autowired
#Qualifier("sessionEventBus")
private EventBus sessionEventBus;
Hi I've read through other posts but I am not being able to fix it. Basically my issue is that I call .inject and when I want to use the field it's still null.
I have this class:
public class Application extends Game implements IApplication {
#Inject IApplication app;
#Inject IRouter router;
public Application(IPlatformCode platformCode) {
}
#Override
public void create() {
initDagger();
System.out.println(app); //NULL
System.out.println(router); //NULL
router.showPage(Page.MenuPage); //NULL EXCEPTION
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 0.5f, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
super.render();
}
#Override
public void setPage(IPage page) {
setScreen(page);
}
protected void initDagger() {
ApplicationComponent.Initializer.init(this).inject(this);
RouterComponent.Initializer.init().inject(this);
}
}
I won't show the router because I'm doing the same in app.
My Application component looks like this:
#Singleton
#Component ( modules = {ApplicationModule.class })
public interface ApplicationComponent {
void inject(IApplication application);
IApplication getApplication();
static final class Initializer {
private Initializer(){}
public static ApplicationComponent init(IApplication app) {
return DaggerApplicationComponent
.builder()
.applicationModule(new ApplicationModule(app))
.build();
}
}
}
And this is the module:
#Module
public class ApplicationModule {
private IApplication app;
public ApplicationModule(IApplication app) {
this.app = app;
}
#Provides
#Singleton
public IApplication providesApplication(){
return app;
}
}
As far as I read after calling inject(IApplication) the #Inject IApplication should be injected and have a value but right now it's null.
The generated code looks like this:
public final class DaggerApplicationComponent implements ApplicationComponent {
private Provider<IApplication> providesApplicationProvider;
private DaggerApplicationComponent(DaggerApplicationComponent.Builder builder) {
assert builder != null;
this.initialize(builder);
}
public static DaggerApplicationComponent.Builder builder() {
return new DaggerApplicationComponent.Builder();
}
private void initialize(DaggerApplicationComponent.Builder builder) {
this.providesApplicationProvider = DoubleCheck.provider(ApplicationModule_ProvidesApplicationFactory.create(builder.applicationModule));
}
public void inject(IApplication application) {
MembersInjectors.noOp().injectMembers(application);
}
public IApplication getApplication() {
return (IApplication)this.providesApplicationProvider.get();
}
public static final class Builder {
private ApplicationModule applicationModule;
private Builder() {
}
public ApplicationComponent build() {
if(this.applicationModule == null) {
throw new IllegalStateException(ApplicationModule.class.getCanonicalName() + " must be set");
} else {
return new DaggerApplicationComponent(this);
}
}
public DaggerApplicationComponent.Builder applicationModule(ApplicationModule applicationModule) {
this.applicationModule = (ApplicationModule)Preconditions.checkNotNull(applicationModule);
return this;
}
}
}
Thanks in advance.
Your inject method
void inject(IApplication application);
needs to change to
void inject(Application application);
Note the change from IApplication to just Application. You can't use interfaces for inject methods, you need to use a class.
Typically, Dagger 2 component creation is done in a class extending one of Android's Application classes. This is primarily done to ensure that these components (and the dependencies they house) are only instantiated once. (see Dagger docs for more details: https://google.github.io/dagger/users-guide)
While I haven't seen anything that says you can't wire it up differently, I haven't found an example of it, either. I'm wondering if trying to wire the components on-the-fly with the Initializer.init() calls you're making is somehow bypassing Dagger's ability to setup Components for injection correctly. Would it be possible to refactor the instantiation of the Component classes into an Application implementation instead?
The code above looks like it should work (outside of getting a new DaggerApplicationComponent instance with every init() call instead of a Singleton), I can't really explain why it doesn't.
Is there any way to inject dependencies into manually created objects?
public class MyCommand {
#Inject Repository repository;
}
public Repository {
#Inject EntityManager em;
}
MyCommand command = new MyCommand();
Repository is properly registered the jersey ResourceConfig and can be injected in objects that are created through the CDI container for example a resource class.
But since I create the Command myself the #Inject annotation gets ignored.
Is there a way to get a registered class beside #Inject and #Context?
Something like Application.get(Repository.class)
public class MyCommand {
Repository repository;
public MyCommand() {
repository = Application.get(Repository.class);
}
}
----- EDIT -----
Thanks to your help and some rethinking I found a solution for my problem.
The first thing is that it's possible to inject the ServiceLocator without any preperation into you objects.
The second thing is that I moved from normal commands with a execute method to a a command bus system.
The reason for that is I have no controle over the creation of commands so there clean way to get dependencies injected.
The new approach looks like this:
class CommandBus {
private final ServiceLocator serviceLocator;
#Inject
public CommandBus(ServiceLocator serviceLocator) {
this.serviceLocator = serviceLocator;
}
public void dispatch(Command command) {
Class handlerClass = findHandlerClassForCommand(command);
CommandHandler handler = (CommandHandler) serviceLocator.getService(handlerClass);
handler.handle(command);
}
}
interface CommandHandler {
void handle(Command command);
}
interface Command {
}
class ConcreteCommand implements Command {
// I'm just a dto with getters and setters
}
class ConcreteHandler implements CommandHandler {
private final SomeDependency dependency;
#Inject
public ConcreteHandler(SomeDependency dependency) {
this.dependency = dependency;
}
#Override
public void handle(ConcreteCommand command) {
// do some things
}
}
And in my resources I have something like this:
#Path("/some-resource")
class Resource {
#Context
private CommandBus bus;
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void runCommand(ConcreteCommand command) {
bus.dispatch(command);
}
}
As pointed out by jwells - HK2 is an injection framework :)
I spent some time looking into it - I have to say, I find it much more complicated than say guice or spring. Maybe this is due to the fact that I use Dropwizard and it makes it not as easy to access the Service locators.
However, here is how you can do that.
First, you will have to get a reference to your ServiceLocator. It must be the same ServiceLocator that jersey is using as well. You can access it for example like:
How to get HK2 ServiceLocator in Jersey 2.12?
In my example code I will use an event listener, which is due to my Dropwizard Setup.
You now have 2 choices: Register your command with your Service Locator and have the injection framework handle creation, or pass the ServiceLocator to your command in order to use it.
I wrote up a quick example using Dropwizard and jersey:
public class ViewApplication extends io.dropwizard.Application<Configuration> {
#Override
public void run(Configuration configuration, Environment environment) throws Exception {
environment.jersey().register(new ApplicationEventListener() {
#Override
public void onEvent(ApplicationEvent event) {
if (event.getType() == ApplicationEvent.Type.INITIALIZATION_FINISHED) {
ServiceLocator serviceLocator = ((ServletContainer) environment.getJerseyServletContainer())
.getApplicationHandler().getServiceLocator();
ServiceLocatorUtilities.bind(serviceLocator, new AbstractBinder() {
#Override
protected void configure() {
bind(new Repository("test")).to(Repository.class);
bind(MyCommandInjected.class).to(MyCommandInjected.class);
}
});
MyCommandInjected service = serviceLocator.getService(MyCommandInjected.class);
MyCommandManual tmp = new MyCommandManual(serviceLocator);
}
}
#Override
public RequestEventListener onRequest(RequestEvent requestEvent) {
return null;
}
});
}
#Override
public void initialize(Bootstrap<Configuration> bootstrap) {
super.initialize(bootstrap);
}
public static void main(String[] args) throws Exception {
new ViewApplication().run("server", "/home/artur/dev/repo/sandbox/src/main/resources/config/test.yaml");
}
#Path("test")
#Produces(MediaType.APPLICATION_JSON)
public static class HelloResource {
#GET
#Path("asd")
public String test(String x) {
return "Hello";
}
}
public static class Repository {
#Inject
public Repository(String something) {
}
}
public static class MyCommandInjected {
#Inject
public MyCommandInjected(final Repository repo) {
System.out.println("Repo injected " + repo);
}
}
public static class MyCommandManual {
public MyCommandManual(final ServiceLocator sl) {
Repository service = sl.getService(Repository.class);
System.out.println("Repo found: " + service);
}
}
}
In the Run method, i get access to my ServiceLocator. I bind my classes in there (so there is an example of how to do that). You can alternatively also register Binders with jersey directly - they will use the correct ServiceLocator.
The 2 classes MyCommandInjected and MyCommandManual are examples of how you can create this command.
The relevant line for you is probably:
Repository service = sl.getService(Repository.class);
This asks the service locator for a new instance of the Repository.
Now, this is just a quick example. I am much more fond of the guice bridge than using HK2 directly :) I find it much easier to use and much clearer. Using the guice-jersey-bridge you can do everything through guice and it will automatically do the right thing.
Hope that brings some inside,
Artur
You can use the inject method of ServiceLocator in order to inject already created objects. ServiceLocator is the basic registry of HK2 and should be available in your resource.
I have a web project using Resteasy (which in turn uses Weld) and is deployed to Tomcat 7.0.22 (I put the specific version here in case this issue is particular to this version).
I have a ServletContextListener that looks like this:
#WebListener
public class ApplicationInitialisationListener implements ServletContextListener {
// create a logger here
#Inject
HealthCheck healthCheck;
#Override
public void contextInitialized(ServletContextEvent event) {
if (healthCheck == null) {
log.error("healthCheck is null");
}
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
After deploying to Tomcat, healthCheck is null was logged, and I also noticed this line in the log:
<2013-11-13 13:27:40,191> <pack> INFO pool-2-thread-1 org.jboss.weld.environment.tomcat7.Tomcat7Container - Tomcat 7 detected, CDI injection will be available in Servlets and Filters. Injection into Listeners is not supported
Question 1: why is CDI injection not available in Listeners?
I looked into this answer, and it says Load on startup via #Startup. There is currently no equivalent to this in CDI.
Question 2: is the issue described in Question 1 a consequence of this?
Question 3: I am using org.jboss.weld.servlet:weld-servlet:1.2.0.Beta1. Is there any update on startup support in later versions?
Related Questions I Looked
startup class in Weld
Here is a workaround I discovered that can inject CDI beans when an application starts.
The requirement of the problem can be summarized as:
inject a CDI bean when the application starts
do something with the bean
Solution outline line:
Create a WebListener that calls BeanManager.fireEvent(new SomeDummyEvent())
Create an ApplicationScoped bean that responds to SomeDummyEvent and injects the CDI bean
Example code:
#WebListener
public class ApplicationInitialisationListener implements ServletContextListener {
private static final Logger LOG = Logger.getLogger(ApplicationInitialisationListener.class);
#Override
public void contextInitialized(ServletContextEvent event) {
BeanManager beanManager = lookUpBeanManager();
if (beanManager != null) {
beanManager.fireEvent(new SomeDummyEvent());
LOG.info("beanManager fired SomeDummyEvent.");
} else {
LOG.error("beanManager is null. Cannot fire startup event.");
}
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
public BeanManager lookUpBeanManager() {
try {
// See reference below about how I came up with this
InitialContext iniCtx = new InitialContext();
BeanManager result = (BeanManager) iniCtx.lookup("java:comp/env/BeanManager");
return result;
} catch (NamingException e) {
LOG.error("Could not construct BeanManager.", e);
return null;
}
}
public static class SomeDummyEvent implements Serializable {
}
}
#ApplicationScoped
public class InitializationResourceBean {
private static final Logger LOG = Logger.getLogger(InitializationResourceBean.class);
#Inject
HealthCheck healthCheck;
public void listen(#Observes ApplicationInitialisationListener.SomeDummyEvent event) {
}
#PostConstruct
public void init() {
// Do something with healthCheck
}
#PreDestroy
public void destroy() {
// Do some other thing with healthCheck
}
}
References:
http://struberg.wordpress.com/tag/cdi/
From: http://docs.jboss.org/weld/reference/latest-master/en-US/html/environments.html#_tomcat
"Tomcat 7 and 8 are supported. Context activation/deactivation and dependency injection into Servlets and Filters works out of the box. Injection into Servlet listeners works on Tomcat 7.0.50 and newer."
So perhaps you can upgrade your Tomcat?
Now, all this is much easy to do with deltaspike servlet module
#ApplicationScoped
public class InitializationResourceBean {
#Inject
HealthCheck healthCheck;
public void onCreate(#Observes #Initialized ServletContext context) {
//Do initialisation stuff here.
if(HealthCheck != null) {
;
}
}
public void onDestroy(#Observes #Destroyed ServletContext context) {
System.out.println("Destroyed ServletContext: " + context.getServletContextName());
}
}
http://deltaspike.apache.org/documentation/servlet.html