Why can't java.util.Random be injected ? - java

When injecting java.util.Random into a Bean, deployment fails:
CDI deployment failure:WELD-001408: Unsatisfied dependencies for type Random with qualifiers #Default at injection point [BackedAnnotatedField] #Inject myPackage.MyBean.random
Question: Why can't an instance of the java.util.Random class be injected ?
I created a class A with similar properties (like having a final method with default visibility) that injects without problems. Here's the code:
#Named
#SessionScoped
public class MyBean implements Serializable {
#Inject private java.util.Random random; // (R)
#Inject private A a;
...
}
public class A implements Serializable {
int n;
public A() { System.out.println("A"); }
public A(int n) { this.n = n; }
final int nextInt(int bound) { return bound -n; }
}
If line (R) is commented out, everything deploys and runs fine.

You cannot inject java.util.Random as a bean because your application does not recognize any bean or producer of that given type.
You have beans.xml with discovery all - meaning CDI will go over classes within your application and turn them into beans if possible (if they meet the requirements set by CDI specification). java.util.Random is not withing your application and hence CDI knows no way to instantiate such bean for you and throws an exception. On the other hand your A bean is within your application and since you have discovery to all and it meets the requirements, CDI will consider it a bean (of #Dependent scope with #Any and #Default qualifiers).
To be able to inject java.util.Random, you need to tell CDI how to do that. You can achieve that fairly easily with a producer method. Note that producer method must be declared inside CDI bean in order for CDI to find it.
#Produces
#Dependent //choose desired scope, or none and it will be dependeny
// you can also add qualifiers, optional
public Random produceRandom() {
return new Random();
}
With the above producer, CDI will not detect it and be able to create such object when you need to #Inject it.

For a class to be discovered as a bean, it has to be deployed in a bean archive, see http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#bean_archive
As far as I understand, this also includes something like target/classes, but not the contents of rt.jar.
As I think that your question is only about the general mechanics and not about "how-to-inject-Random", I'll leave it at that. See the other answers on how to make Random injectable by a producer method.

Your class has to be discovered by CDI as a bean. For that you have to do something like this:
Put a bean defining annotation on it. As #Model is a stereotype it's why it does the trick. A qualifier like #Named is not a bean defining annotation, probably the reason why it doesn't work.

Related

CDI Scope and Producers

Can someone explain the role of CDI Scope annotations when it comes to Producers? They don't seem to accomplish anything.
#Produces
public Thing thingMaker() {
System.out.println("Making thingmaker");
return new ThingBean("thingMaker");
}
#Produces
#RequestScoped
public Thing thingMakerReq() {
System.out.println("Making thingmakerReq");
return new ThingBean("thingMakerReq");
}
These, naturally, give this (elided) error on startup.
WELD-001409: Ambiguous dependencies for type Thing.
Possible
dependencies:
Producer Method [Thing] with qualifiers [#Any #Default] declared as [[BackedAnnotatedMethod] #Produces public
pkg.test.ThingProducer.thingMaker()],
Producer Method [Thing] with qualifiers [#Any #Default] declared as [[BackedAnnotatedMethod] #Produces #RequestScoped public
pkg.test.ThingProducer.thingMakerReq()]
So, even though the `RequestScoped is noted as part of the producer method, they're not qualifiers.
So I'm just not sure what their role is when it comes to producer methods.
CDI scope annotations on producer methods define the scope of the produced bean; so:
#Produces // produces Thing in the default scope, i.e. #Dependent
public Thing thingMaker() {
System.out.println("Making thingmaker");
return new ThingBean("thingMaker");
}
#Produces // produces Thing in request scope
#RequestScoped
public Thing thingMakerReq() {
System.out.println("Making thingmakerReq");
return new ThingBean("thingMakerReq");
}
If it was only these two methods, they would be able to coexist peacefully. The problem arises when you want to inject a Thing, as:
#Inject
private Thing thing;
CDI searches its namespace and finds more than one bean that can satisfy this injection point; not knowing what to do, it fails (with WELD-001409 in the specific case where Weld is the CDI implementation). The following would be perfectly legal for example:
#Inject
private Instance<Thing> things;
Instance can give you a collection of beans that satisfy the injection point and you can pick any of them to work with.
Now, qualifiers are a different thing, related to how CDI finds beans that satisfy an injection point.
First, to get the misunderstanding out of the way: scope annotations are not qualifiers. You can notice that in CDI's message, "with qualifiers [#Any #Default] declared as [[... #RequestScoped ...]". This also means that you cannot request a bean from a specific scope in an injection point. And the scope of the bean containing the injection point does not play any role in the selection of the injected bean either. Scope is an implementation detail of the bean: let's say you have an #ApplicationScoped bean, then at some point you realize that it needs request-level information to implement some functionality. You can change its scope and the beans using it should not care, they will continue working without change.
Qualifiers are a way to disambiguate dependencies, when the type is not enough, like in your case. A frequent example is when having many configuration properties, represented as strings. Let's say a DB user name and password, both of type String: (WARNING: naive example, qualifier with binding attributes would be more appropriate, see e.g. Microprofile config)
#Inject
#DbUsername // this is the qualifier
private String dbUsername;
#Inject
#DbPassword // this is the qualifier
private String dbPassword;

CDI / WELD Constructor injection best practices

In a "monolitic" Jakarta-EE 8 application we want to use JSF in combination with CDI. The following graph gives an example on how the view and classes depend on each other:
JSF-View -> ViewController -> BeanA --> BeanA1
\-> BeanA2
In this case the ViewController is #Named + #ViewScoped and all other beans (BeanA, BeanA1, BeanA2) are #SessionScoped.
We want to use constructor injection as a best practice. Based on this our classes looks like this:
#Named
#ViewScoped
public class ViewController implements Serializable {
private final BeanA bean;
#Inject
public ViewController(final BeanA bean) {
this.bean = bean;
}
}
#SessionScoped
public class BeanA implements Serializable {
private final BeanA1 bean1;
private final BeanA2 bean2;
#Inject
public BeanA(final BeanA1 bean1, final BeanA2 bean2) {
this.bean1 = bean1;
this.bean2 = bean2;
}
}
When deploying this as a WAR to Wildfly 20 we end with the following error / exception:
"BeanA is not proxyable because it has no no-args constructor".
Since we do not plan to run the server in a cluster I do not get why we need a non-args constructor (no serialization needed at all).
Adding the META-INF/org.jboss.weld.enableUnsafeProxies file solves the problem and we can deploy and run the application without any error.
I ask myself if this is a good practice or if we miss anything?
First, the quickest possible answer: any bean that is in a normal scope must have a non-private, zero-argument constructor. In addition, such classes must not be final and must not have non-private, virtual final methods. #SessionScoped is a normal scope.
If you follow the link, you'll see that the reason for this in the CDI specification is not (perhaps primarily) because of serialization but because of proxying.
The property you refer to is a Weld-specific feature. If you know you are going to continue using Weld for your CDI implementation then you may of course continue to use this property, but strictly speaking your CDI application is now non-portable. This may or may not matter to you.
The most pragmatic, real-world solution to this problem that I've found is to define a package-private zero argument constructor that is #Deprecated that sets fields to null.

Passivation of CDI SessionBean with Constructor Injection

I have following CDI Bean:
#SessionScoped
public class ReportService implements Serializable {
private static final long serialVersionUID = 1L;
private MyDao myDao;
#Inject
public ReportService(MyDao myDao) {
this.myDao = myDao;
}
}
#RequestScoped
public class MyDao extends AbstractDao<Order> {
protected MyDao() {
}
#Inject
public MyDao(EntityManager em) {
super(em);
}
}
If i start my webapplication (Tomcat with Weld) the following Exception is thrown:
WELD-001435: Normal scoped bean class
com.myorg.ReportService is not proxyable because it
has no no-args constructor - Managed Bean [class
com.myorg.ReportService] with qualifiers [#Any
#Default].
How is it possible to use constructor injection in a SessionScoped Bean?
Is it safe just to add a package-visible no-args constructor?
I already searched a lot, but i did not find any information about passivating a CDI Bean whitch uses Constructor Injection.
The error you are getting is based on CDI specification requirements, namely the need to have no-args constructor. When instantiating the object, CDI will of course prioritize a constructor annotated with #Inject, so don't worry about that.
The real reason why you need no-args one is for proxies. Weld/CDI will try to create one or more proxies of your object, which are basically an enriched delegates. In order to instantiate them, you want to invoke no-arg constructor - think of it as Java limiation, you shouldn't be instantiating objects without calling constructors. Therefore the spec mandates the need for no-arg constructor. As a matter of fact, Weld itself allows you to bypass this need in certain cases, but I strongly suggest against it.
Is it safe just to add a package-visible no-args constructor?
Yes, go ahead and do that.

The bean could not be injected as a 'Type' because it is a JDK dynamic proxy that implements: reactor.fn.Consumer

My Spring 4 application, which uses Reactor 2, fails to start with:
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'orderHandlerConsumer' could not be injected as a 'fm.data.repository.OrderHandlerConsumer' because it is a JDK dynamic proxy that implements:
reactor.fn.Consumer
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
The OrderHandlerConsumer is really simple:
#Service
#Order(Ordered.HIGHEST_PRECEDENCE)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
#Override
public void accept(Event<OrderEnvelope> event) {
event.getData().getLatch().countDown();
}
}
Any ideas what might be going awry?
In your application class file where you define it as Spring application, add underneath it.
#SpringBootApplication
#EnableCaching(proxyTargetClass = true)
While the accepted answer will solve this issue, I think it will be more appropriate for me to explain why appling proxyTargetClass = true will fix this.
First of all, Spring, as a framework, utilizes proxing in order to supply the bean with some extended functionality, such as declaritive transactions via #Transactional, or caching by the means of #Cacheable and e.t.c. There are, in general, 2 ways(*) Spring can create proxy on top of your bean:
Jdk dynamic proxing
CGLib proxing
Offical documentation on this, in case you are interested.
Spring can create jdk dynamic proxy of the bean (in case proxing is required for this bean of course) if original class of the bean implements at least one interface. So spring basically create another implementation of this interface at runtime with some additional logic on top of original class.
What is the problem: if the bean is proxied by the means of jdk dynamic proxing , then you cannot inject this bean via its original class. So something like this:
#SpringBootApplication
#EnableTransactionManagement(proxyTargetClass = false)
public class StackoverflowApplication {
#Autowired private SomeService service;
public static void main(String[] args) {
SpringApplication.run(StackoverflowApplication.class, args);
}
}
#Service
class SomeService implements SomeInterface {
#Override
#Transactional
public void handle() { }
}
interface SomeInterface {
void handle();
}
wont work. Why? Well, becuase #Transactional tells Spring that it needs to create proxy of SomeService at runtime, and within #EnableTransactionManagement I specifically asked Spring to make it by the means of jdk dynamic proxy - spring will succeed, since jdk dynamic proxy can be created, but the problem is at runtime there is not bean of type SomeService, there is only a bean of type SomeInterface (by the way, if you inject service here not by the class, but by the interface - it will work, I assume you understand the reason by reading explaination above).
Solution: by applying #EnableTransactionManagement(proxyTargetClass = true) (notice true value here) you force spring to create CGlib proxy (this rule is applicable only for beans that utilize declarative transaction management, i.e. via annotations). In case of CgLib proxing, Spring will try to extend the original class, and add additional functionality at runtime in the generated child class. And in this case injection by class will work - because the bean extends class SomeService, so
#Autowired
private SomeService someService;
will work perfectly fine. But, in general, if possible, inject bean by interface, not by class. In this case both Cglib and jdk dynamic proxy will work. So, be aware of proxing mechanisms spring can use. Hope it helped, have a nice day.
You can assign a bean name to your OrderHandlerConsumer class so that Autowire resolution will be easier, Moreover, Instead of Autowiring with the concrete class, try to auto-wire with the interface. So that you can change #Service annotation to,
#Service(value="orderHandlerConsumer")
and try to Autowire with the interface type,
#Autowire
reactor.fn.Consumer orderHandlerConsumer;
Please try autowiring as below
class Test{
#Autowired
private Consumer orderHandlerConsumer;
}
If the target object to be proxied implements at least one interface
then a JDK dynamic proxy will be used. All of the interfaces
implemented by the target type will be proxied. If the target object
does not implement any interfaces then a CGLIB proxy will be created.
https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html
You can call it two ways.
1st way is without mentioning the proxy [with default proxy], you can Autowire it by the interface like below.
#Autowired
private Consumer orderHandlerConsumer;
Spring AOP will create an instance for OrderHandlerConsumer.
2nd way is, mention the proxy in the bean as ScopedProxyMode.TARGET_CLASS.
then you can Autowire an instance without the interface [based on the class].
#Service
#Order(Ordered.HIGHEST_PRECEDENCE)
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
#Override
public void accept(Event<OrderEnvelope> event) {
event.getData().getLatch().countDown();
}
}
and Autowire by the class like below.
#Autowired
private OrderHandlerConsumer orderHandlerConsumer;

Spring How to autowire a component without using #Component or other derivatives

I would like to autowire a component (still using the #Autowired annotation), but not require it to have the #Component (or other similar annotations) on it. How would I do this?
public class A {
#Autowired
private class B b;
}
#Component
public class B {
}
This would be convenient in order to allow autowiring of class A without requiring the creation of A, unless we needed it (in otherwise on the fly by reflection using the class name).
Injection and autowiring do not require #Component. They require beans. #Component states that the annotated type should have a bean generated for it. You can define beans in other ways: with a <bean> declaration in an XML context configuration, with a #Bean method in a #Configuration class, etc.
Your last sentence doesn't make much sense. You can't process injection targets in a bean without creating a bean. You also can't inject a bean without creating it. (Applied to scopes, bean may refer to the target source/proxy and not the actual instance.) Perhaps you want #Lazy.
I don't sure, If I correctly understood to your question. But if you want inject bean B without marking bean A via some annotation, or xml definition, you can use SpringBeanAutowiringSupport
public class A {
#Autowired
private class B b;
public A{
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
}

Categories