I have a resource in my Jersey REST api that has a private instance variable:
#Path("test")
public class TestResource implements ServletContextListener
{
private String someString;
#GET
public void test()
{
System.out.println("someString " + someString);
}
#Override
public void contextDestroyed(ServletContextEvent ctxt) {
System.out.println("Destroying context");
}
#Override
public void contextInitialized(ServletContextEvent ctxt) {
System.out.println("TestResource initialized!");
someString = "SET";
System.out.println("someString has been set. someString: " + someString);
}
}
On server startup/restart the instance variable someString is initialized during contextInitialized() and is correctly printed out. However when I set a GET request to http://localhost:8080/myapp/api/test (i.e. invoke the test() method above) the variable someString is null.
How can I prevent that?
From the JAX-RS specification:
By default a new resource class instance is created for each request to that resource.
So, any state you set on your resource class instance is meaningless, since the instance is never used again. If you want to persist a value, place it in the ServletContext’s attributes:
// All classes in the web app share a ServletContext, so attribute names
// need to start with package names to prevent collisions.
private static final String SOME_ATTRIBUTE = TestResource.class.getName() + ".someAttribute";
#Override
public void contextInitialized(ServletContextEvent ctxt) {
System.out.println("TestResource initialized!");
String someString = "SET";
System.out.println("someString has been set. someString: " + someString);
ctxt.getServletContext().setAttribute(SOME_ATTRIBUTE, someString);
}
#GET
public void test(#Context ServletContext context) {
System.out.println("someString " + context.getAttribute(SOME_ATTRIBUTE));
}
Storing values in static fields will require you to implement thread safety and will not work in a distributed production environment.
I believe this should be a comment but I don't have enough reputation. So I am writing as an answer.
This question gives an example for #Singleton annotation. It provides a cleaner approach.
Related
In a setup as described in the docs:
public class MyWireMockResource implements QuarkusTestResourceLifecycleManager {
WireMockServer wireMockServer;
#Override
public Map<String, String> start() {
wireMockServer = new WireMockServer(8090);
wireMockServer.start();
// create some stubs
return Map.of("some.service.url", "localhost:" + wireMockServer.port());
}
//...
}
How can I access the value returned in in the start() method.
The javadoc says:
A map of system properties that should be set for the running test
Why "should be"?
I would like to set some values that I can later used in my productive code.
I have tried: System.getProperty("some.service.url")
I have also tried:
#ConfigProperty(name = "some.service.url")
String serviceUrl;
But the value is not set.
Any help is appreciated.
The system properties mentioned in the javadoc is confusing. The returned map will as expected override the configurations.
It was not working for me to access it with the #ConfigProperty annotation because I was reading the value in the constructor and not in the method annotated with #PostConstruct.
#ApplicationScoped
public class SomeBean {
#ConfigProperty(name = "some.service.url")
String serviceUrl;
public SomeBean() {
// we are too early here, value is null:
System.out.println("value in constructor: " + serviceUrl);
}
#PostConstruct
void init() {
System.out.println("value in init: " + serviceUrl);
}
}
I have some validation code that should run on server startup and make sure various conditions are met so whoever deploys the server don't messes up the DB or start the server with bad security configurations etc. To do that I created a bean
#Component
public class ApplicationStartupConditionsValidationBean {
static class ServerInitializationError extends Error{
public ServerInitializationError(String msg){
super(msg);
}
}
private Environment springEnv;
private String datasourceURL;
private String ddlAuto;
private static final Logger logger = LogManager.getLogger();
#Autowired
public ApplicationStartupConditionsValidationBean(Environment springEnv) throws Exception {
this.springEnv = springEnv;
this.datasourceURL = springEnv.getProperty("spring.datasource.url");
this.ddlAuto = springEnv.getProperty("spring.jpa.hibernate.ddl-auto");
validateStartupConditions();
}
public boolean isDBLocal(){
return datasourceURL.startsWith("jdbc:postgresql://localhost:");
}
private String disallowedParamMsg(String optionName, String optionValue){
return "option " + optionName + "=" + optionValue + " not allowed in production";
}
private void reject(String msg) throws ServerInitializationError{
String rejectionMsg = "startup conditions validation failed with msg: " + msg;
logger.error(rejectionMsg);
throw new ServerInitializationError(rejectionMsg);
}
private void reject(String paramName, String paramValue) throws ServerInitializationError{
reject(disallowedParamMsg(paramName, paramValue));
}
private void validateDatasourceParams(){
if(!isDBLocal() &&
!ddlAuto.equals("validate")){
reject("ddl-auto", ddlAuto);
}
}
public void validateStartupConditions() throws Exception{
logger.info("validating startup conditions");
validateDatasourceParams();
// more validation logic...
logger.info("startup conditions validation succeeded, proceeding with boot");
}
}
The way I would have wanted to use this class is to define what beans this must come before. In the example here I would have wanted to make sure this bean would be created before the DataSource bean is created, so that "ddl-auto=create" doesn't slip in production. I Know about the #DependsOn annotation but I would have wanted to do the reverse, and declare that this bean #HappensBefore a list of other beans. Is there any way to do this?
Thanks!
To run code before "normal" beans get created, you can use a BeanFactoryPostProcessor.
To declaratively add additional dependencies among beans, you could also use a BeanPostProcessor, but that sounds needlessly cumbersome for your use case.
Does this have a proper name?
public class SomethingFactory {
private final String someParameter;
public SomethingFactory(String someParameter) {
this.someParameter = someParameter;
}
public Something create(String anotherParameter) {
return new Something(someParameter, anotherParameter);
}
}
public class Something {
public final String someParameter;
public final String anotherParameter;
public Something(String someParameter, String anotherParameter) {
this.someParameter = someParameter;
this.anotherParameter = anotherParameter;
}
}
What's different from a regular factory is that you have to specify a parameter at runtime to create() whenever you need to create an object.
That way you can make a singleton factory within Spring context for example, configuring first half of parameters there, and then finish with the rest of parameters at runtime when you call create().
Why I need that in the first place if you're curious:
I used to have regular singleton objects in Spring context and it was fine in thread-per-request applications, but now my whole app is non-blocking and I can't use ThreadLocal to keep stuff throughout entire request processing. For example, to keep info on timings with something like Apache StopWatch.
I needed to find a way to implement a "request scope" in a multithreading, non-blocking environment without having to supply the object representing the scope in every method (that would be silly) of my code.
So I thought let's make every (service) class take this scope object in constructor and let's create those classes on every request, but that goes against the singletons. The singletons we're talking are like, UserService that logs a user in, or a CryptoService that generates digital signatures. They're configured once in Spring, injected wheneven needed and everything's ok. But now I need to create those service classes in every method where they're needed, instead of just referencing an injected singleton instance.
So I thought let's call those singletons "templates" and whenever you need an actual instance you call create() supplying the said scope object. That way every class has the scope object, you just have to keep supplying it into other template service constructors. The full thing would look like this:
public class UserService {
private final Scope scope;
private final Template t;
private UserService(Template t, Scope scope) {
this.t = t;
this.scope = scope;
}
public void login(String username) {
scope.timings.probe("before calling database");
t.database.doSomething(username);
scope.timings.probe("after calling database");
}
public static class Template { /* The singleton configured in Spring */
private Database database;
public void setDatabase(Database database) { /* Injected by Spring */
this.database = database;
}
public UserService create(Scope scope) {
return new UserService(this, scope);
}
}
}
public class LoginHttpHandler { /* Also a Spring singleton */
private UserService.Template userServiceT;
public void setUserServiceT(UserService.Template userServiceT) { /* Injected by Spring */
this.userServiceT = userServiceT;
}
public void handle(HttpContext context) { /* Called on every http request */
userServiceT.create(context.scope).login("billgates");
}
}
In Spring you'd just describe a UserService.Template bean with the appropriate dependencies it needs and then inject that bean whenever a UserService is needed.
I just call that a "template". But like always I feel it's already been done. Does it have any name?
That is almost the example given for Guice's AssistedInject:
public class RealPaymentFactory implements PaymentFactory {
private final Provider<CreditService> creditServiceProvider;
private final Provider<AuthService> authServiceProvider;
#Inject
public RealPaymentFactory(Provider<CreditService> creditServiceProvider, Provider<AuthService> authServiceProvider) {
this.creditServiceProvider = creditServiceProvider;
this.authServiceProvider = authServiceProvider;
}
public Payment create(Date startDate, Money amount) {
return new RealPayment(creditServiceProvider.get(), authServiceProvider.get(), startDate, amount);
}
}
public class RealPayment implements Payment {
public RealPayment(
CreditService creditService, // from the Injector
AuthService authService, // from the Injector
Date startDate, // from the instance's creator
Money amount) // from the instance's creator
{
...
}
}
Assisted injection is used to "create classes that need extra arguments at construction time".
Also, this is similar to partial application, so you could have a PartialUserService that creates a UserService.
I have a problem trying to inject a contract with two services bound to it.
I'm using Jersey, and extending ResourceConfig to configure my app, where I'm binding two different implementations (classes FooImpl1 and FooImpl2) to a same contract (interface Foo), ranking them differently. Each of these implementations is annotated with #Named and its name.
In one of my controllers I want to have access to both implementations, so I inject an IterableProvider<Foo> fooProvider.
If I do not specify anything, the implementation with the highest rank is injected always, which is what I want.
The problem appears when I want a concrete implementation, one of them. When I call fooProvider.named( nameOfTheClass ).get(), is returning me null, but if I iterate over the fooProvider, I can have access to both implementations, so they are injected.
Anybody has an idea of what could I be missing?
Thanks a lot for your help.
Yeah so I'm not sure why it doesn't work with the #Named annotation value, as that's what's stated int the javadoc, but without the need for any annotations, we can configure the name when we do our bindings. We can do so with the named method.
register(new AbstractBinder(){
#Override
public void configure() {
bind(Foo1Impl.class).named("foo1").to(Foo.class);
bind(Foo2Impl.class).named("foo2").to(Foo.class);
}
});
UPDATE
So the above solution has been tested. If you are having problems still, post a complete runnable example that demonstrates it not working, like below (which is working)
Interface and Implementations
public interface Greeter {
String getGreeting(String name);
}
public class EnglishGreeter implements Greeter {
#Override
public String getGreeting(String name) {
return "Hello " + name + "!";
}
}
public class SpanishGreeter implements Greeter {
#Override
public String getGreeting(String name) {
return "Hola " + name + "!";
}
}
Resource
#Path("greeting")
public class GreetingResource {
#Inject
private IterableProvider<Greeter> greeters;
#GET
public Response getResponse(#QueryParam("lang") String lang,
#QueryParam("name") String name) throws Exception {
Greeter greeter = greeters.named(lang).get();
String message = greeter.getGreeting(name);
return Response.ok(message).build();
}
}
Binding. I did it in a Feature, but in a ResourceConfig, it's all the same.
#Provider
public class GreetingFeature implements Feature {
#Override
public boolean configure(FeatureContext context) {
context.register(new AbstractBinder(){
#Override
public void configure() {
bind(EnglishGreeter.class).named("english")
.to(Greeter.class).in(Singleton.class);
bind(SpanishGreeter.class).named("spanish")
.to(Greeter.class).in(Singleton.class);
}
});
return true;
}
}
Result
Is it possible to use CDI to inject parameters into method calls? The expected behaviour would be similar to field injection. The preferred producer is looked up and the product is used.
What I would like to do is this:
public void foo(#Inject Bar bar){
//do stuff
}
or this (with less confusing sytax):
public void foo(){
#Inject
Bar bar;
//do stuff
}
This syntax is illegal in both cases. Is there an alternative? If no - would this be a bad idea for some reason if it were possible?
Thank you
EDIT - I may have made my requirements not clear enough - I would like to be able to call the method directly, leaving the initialization of the bar variable to the container. Jörn Horstmann's and Perception's answer suggest that it is not possible.
Injection points are processed for a bean when it is instantiated by the container, which does limit the number of uses cases for method level injection. The current version of the specification recognizes the following types of method injection:
Initializer method injection
public class MyBean {
private Processor processor;
#Inject
public void setProcessor(final Processor processor) {
this.processor = processor;
}
}
When an instance of MyBean is injected, the processor instance will also be injected, via it's setter method.
Event Observer Methods
public class MyEventHandler {
public void processSomeEvent(#Observes final SomeEvent event) {
}
}
The event instance is injected into the event handling method directly (though, not with the #Inject annotation)
Producer Methods
public class ProcessorFactory {
#Produces public Processor getProcessor(#Inject final Gateway gateway) {
// ...
}
}
Parameters to producer methods automatically get injected.
If what you REALLY want is not something as the parameter of the method (which should be provided by the caller), but a properly initialized instance of a CDI bean each time when the method is called, and fully constructed and injected, then check
javax.inject.Provider<T>
Basically, first inject a provider to the class
#Inject Provider<YourBean> yourBeanProvider;
then, in the method, obtain a new instance
YourBean bean = yourBeanProvider.get();
Hope this helps :)
This question came up when I originally did a search on this topic, and I have since learned that with the release of CDI 1.1 (included in the JavaEE 7 spec), there is now a way to actually do what the OP wanted, partially. You still cannot do
public void foo(#Inject Bar bar){
//do stuff
}
but you can "inject" a local variable, although you do not use #Inject but rather programmatically look up the injected instance like this:
public void foo() {
Instance<Bar> instance = CDI.current().select(Bar.class);
Bar bar = instance.get();
CDI.current().destroy(instance);
// do stuff with bar here
}
Note that the select() method optionally takes any qualifier annotations that you may need to provide. Good luck obtaining instances of java.lang.annotation.Annotation though. It may be easier to iterate through your Instance<Bar> to find the one you want.
I've been told you need to destroy the Instance<Bar> as I have done above, and can verify from experience that the above code works; however, I cannot swear that you need to destroy it.
That feature of CDI is called an "initializer method". The syntax differs from your code in that the whole method is annotated with #Inject, the method parameters can further be annotated by qualifiers to select a specific bean. Section 3.9 of JSR 299 shows the following example, with #Selected being a qualifier that can be omitted if there is only one bean implementation.
#Inject
void setProduct(#Selected Product product) {
this.product = product;
}
Please note that
The application may call initializer methods directly, but then no parameters will be passed to the method by the container.
You can use the BeanManager API in your method to get contextual references, or depending on your ultimate goal you could inject an
Instance<Bar>
outside of the method and use it in the method.
If your goal is to call the method via reflection, it is possible to create an InjectionPoint for each parameter.
Here's an example using CDI-SE:
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanManager;
public class ParameterInjectionExample {
public static class Foo {
// this method will be called by reflection, all parameters will be resolved from the BeanManager
// calling this method will require 2 different Bar instances (which will be destroyed at the end of the invocation)
public void doSomething(Bar bar, Baz baz, Bar bar2) {
System.out.println("got " + bar);
System.out.println("got " + baz);
System.out.println("got " + bar2);
}
}
#Dependent
public static class Bar {
#PostConstruct
public void postConstruct() {
System.out.println("created " + this);
}
#PreDestroy
public void preDestroy() {
System.out.println("destroyed " + this);
}
}
#ApplicationScoped
public static class Baz {
#PostConstruct
public void postConstruct() {
System.out.println("created " + this);
}
#PreDestroy
public void preDestroy() {
System.out.println("destroyed " + this);
}
}
public static Object call(Object target, String methodName, BeanManager beanManager) throws Exception {
AnnotatedType<?> annotatedType = beanManager.createAnnotatedType(target.getClass());
AnnotatedMethod<?> annotatedMethod = annotatedType.getMethods().stream()
.filter(m -> m.getJavaMember().getName().equals(methodName))
.findFirst() // we assume their is only one method with that name (no overloading)
.orElseThrow(NoSuchMethodException::new);
// this creationalContext will be valid for the duration of the method call (to prevent memory leaks for #Dependent beans)
CreationalContext<?> creationalContext = beanManager.createCreationalContext(null);
try {
Object[] args = annotatedMethod.getParameters().stream()
.map(beanManager::createInjectionPoint)
.map(ip -> beanManager.getInjectableReference(ip, creationalContext))
.toArray();
return annotatedMethod.getJavaMember().invoke(target, args);
} finally {
creationalContext.release();
}
}
public static void main(String[] args) throws Exception {
try (SeContainer container = SeContainerInitializer.newInstance().disableDiscovery().addBeanClasses(Bar.class, Baz.class).initialize()) {
System.out.println("beanManager initialized");
call(new Foo(), "doSomething", container.getBeanManager());
System.out.println("closing beanManager");
}
}
}