CDI bean is not injected but can be looked up - java

So, I wrote an extension which registers bean I am trying to create. The bean gets scanned by CDI and I can get it using:
MyInterface myInterface = CDI.current().select(MyInterface.class).get();
And I can then access myInterface.myMethod();
However, when I try to inject my bean using:
#Inject
#MyBean
MyInterface myInterface;
it is not injected and is null.
What I want to achieve is that I specify interface, which defines some methods,then my code generates instance of this interface and returns proxy of interface type:
// defined interface
#RegisterAsMyBean
interface MyInterface {
void myMethod();
}
// usage in code:
#Inject
#MyBean
MyInterface myInterface;
I declared my bean like this:
public class MyExtension implements Extension {
public void register(#Observes #WithAnnotations(RegisterAsMyBean.class) ProcessAnnotatedType<?> aType) {
Class<?> typeDef = aType.getAnnotatedType().getJavaClass();
if(typeDef.isInterface()) {
proxyTypes.add(typeDef);
aType.veto();
}
}
}
public class BeanCreator implements Bean<Object> {
#Override
public Object create(CreationalContext<Object> creationalContext) {
// my instance building logic
}
// ... other overriden methods
}
Also in META-INF/services/javax.enterprise.inject.spi.Extension I put reference to MyExtension

The problem was in bean creation lifecycle - i was trying to create bean in processAnnotatedType cycle, while I should have done that during afterBeanDiscovery cycle.
After moving my bean creation logic to appropriate cycle the bean is created and properly injected.

Related

Java Spring: getting the generic type

I have a parameterized class that implements the FactoryBean interface:
public class DogFactory<T extends Dog> implements FactoryBean<T> {
// ...
}
What I want is to use this factory for spawning objects of different classes (all of these classes extend Dog). So I imagined that I could do something like the following:
public class ShepherdService {
private DogFactory<Shepherd> shepherdFactory;
public ShepherdService(
#Autowired
DogFactory<Shepherd> shepherdFactory
) {
this.shepherdFactory = shepherdFactory;
}
// ...
}
Alas, I get the following error: Couldn't autowire. No beans of DogService<Shepherd> type found. :-(
How to inject it and use as DogFactory<Shepherd> or DogFactory<Corgi> (not just DogFactory)?
And another question. I also need to pass the Shepherd.class (or Corgi.class) to this bean, so it could "know" at run-time, objects of what exactly class should it produce. Is there a way to do that?
Or should I forget about FactoryBean and instantiate the factory as a regular class? Of course, I could do it this way:
DogFactory<Shepherd> shepherdFactory = new DogFactory<Shepherd>(Shepherd.class);
It would work perfectly, but I'd like to use FactoryBean as I use it for other factories in this project, so I would like to stick to FactoryBean.
Thanks in advance!
Update 1
Maybe I should clarify it more precise. What I need is a factory that could produce objects of different classes. All these classes should be extensions of the certain class (e.g., Shepherd and Corgi - all these classes extend Dog). And as the final result I actually need something like that:
public class DogService<T extend Dog> {
private DogFactory<T> dogFactory;
#Autowired
public DogService(DogFactory<T> dogFactory) {
this.dogFactory = dogFactory;
}
public T spawnDog(Color color) {
T dog = DogFactory.getObject(color);
return dog;
}
}
But it seems that I can't make a "universal" factory with the FactoryBean interface, so I can't do something like that:
public class DogFactory<T extends Dog> implements FactoryBean<T> {
// ...
}
Instead of that I have to do something like the following:
public class ShepherdFactory implements FactoryBean<Shepherd> {
// ...
}
public class CorgiFactory implements FactoryBean<Corgi> {
// ...
}
Is that true?
Thanks!
What I want is to instantiate this factory in another class
If you mean "having the factory injected in the class instead of the bean it creates", you could inject the factory by prefixing its name with an ampersand:
public class ShepherdService {
private DogFactory<Shepherd> shepherdFactory;
#Qualifier("&dogFactory")
public ShepherdService(DogFactory<Shepherd> shepherdService) {
this.shepherdService = shepherdService;
}
}
From the Spring documentation (section 3.8.3):
When you need to ask a container for an actual FactoryBean instance
itself, not the bean it produces, you preface the bean id with the
ampersand symbol & (without quotes) when calling the getBean method of
the ApplicationContext. So for a given FactoryBean with an id of
myBean, invoking getBean("myBean") on the container returns the
product of the FactoryBean, and invoking getBean("&myBean") returns
the FactoryBean instance itself.
Furthermore, my guess is that the FactoryBean is not picked up as a Spring bean as your snippets did not contain an XML config section, a Java config section, or a #Component annotation. I would explicitly declare the factory bean in a #Configuration annotated class, or annotate the factory class with #Component.
[edit]
But it seems that I can't make a "universal" factory with the
FactoryBean interface, so I can't do something like that:
You could still have a single Configuration class in which you declare all the factory beans.
#Configuration
public class DogFactoryConfig {
#Bean
public DogFactory<Shepherd> shepherdFactory() {
return new DogFactory<Shepherd>();
}
#Bean
public DogFactory<Corgi> corgiFactory() {
return new DogFactory<Corgi>();
}
}
And remove the #Component annotation from your DogFactory if it is present.

How can I inject for generic inherited types?

I spent a plenty of time for finding any answers, but I think I have to ask.
I'm using Weld-SE for testing my entities.
I prepared entity randomizer for testing.
abstract class BaseEntityRandomizer<T extends BaseEntity>
implements Randomizer<T> {
#Override public T getRandomValue() {
...
}
}
class MySomeOtherEntityRandomizer
extends BaseEntityRandomizer<MySomeOther> {
#Override public MySomeOther getRandomValue() {
...
}
}
Now, with my test class, I want to inject those randomizers which each matches generic parameters
#ExtendWith(WeldJunit5Extension.class)
#AddPackages({BaseEntityRandomizer.class})
abstract class BaseEntityTest<T extends BaseEntity> {
#Test void doSome() {
}
#Inject
private BaseEntityRandomizer<T> entityRandomizer;
}
class MySomeOtherTest extends BaseEntityTest<MySomeOther> {
...
// I expect an instance of MySomeOtherRandomizer in injected
// into the entityRandomizer field.
}
Subclasses of randomizers and tests are prepared.
But I failed to make it work.
How can I make it work?
I tried with following factory class
class BaseEntityRandomizerFactory {
#Produces
public BaseEntityRandomizer<MySome> produceMySomeRandomizer() {
return new MySomeRandomizer();
}
}
I got
org.jboss.weld.exceptions.IllegalArgumentException:
WELD-001408: Unsatisfied dependencies for type BaseEntityRandomizer<T extends BaseEntity> with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject protected transient ....BaseEntityTest.entityRandomizer
at ....BaseEntityTest.entityRandomizer(BaseEntityTest.java:0)
One way to achieve this is to use CDI Programmatic lookup. In your case, I'd start with #Inject Instance<Object> and then you can use subsequent calls to select() and get() methods to pick up whichever bean you desire. Usage looks something like this (assumes existence of beans with types Foo, Bar and List<String>):
#Inject
private Instance<Object> instance;
#Test void doSome() {
// selecting and obtaining instances of beans
Foo foo = entityRandomizer.select(Foo.class).get();
Bar bar = entityRandomizer.select(Bar.class).get();
// in case you need to select a parameterized type from instance, use TypeLiteral
List<String> listBean = entityRandomized..select( new TypeLiteral<List<String>>(){}).get()
}

Inject spring bean dynamically

In a java-spring web-app I would like to be able to dynamically inject beans.
For example I have an interface with 2 different implementations:
In my app I'm using some properties file to configure injections:
#Determines the interface type the app uses. Possible values: implA, implB
myinterface.type=implA
My injections actually loaded conditionally relaying on the properties values in the properties file. For example in this case myinterface.type=implA wherever I inject MyInterface the implementation that will be injected will be ImplA (I accomplished that by extending the Conditional annotation).
I would like that during runtime - once the properties are changed the following will happen (without server restart):
The right implementation will be injected. For example when setting myinterface.type=implB ImplB will be injected where-ever MyInterface is used
Spring Environment should be refreshed with the new values and re-injected as well to beans.
I thought of refreshing my context but that creates problems.
I thought maybe to use setters for injection and re-use those setters once properties are re-configured. Is there a working practice for such a requirement?
Any ideas?
UPDATE
As some suggested I can use a factory/registry that holds both implementations (ImplA and ImplB) and returns the right one by querying the relevant property.
If I do that I still have the second challenge - the environment. for example if my registry looks like this:
#Service
public class MyRegistry {
private String configurationValue;
private final MyInterface implA;
private final MyInterface implB;
#Inject
public MyRegistry(Environmant env, MyInterface implA, MyInterface ImplB) {
this.implA = implA;
this.implB = implB;
this.configurationValue = env.getProperty("myinterface.type");
}
public MyInterface getMyInterface() {
switch(configurationValue) {
case "implA":
return implA;
case "implB":
return implB;
}
}
}
Once property has changed I should re-inject my environment. any suggestions for that?
I know I can query that env inside the method instead of constructor but this is a performance reduction and also I would like to think of an ider for re-injecting environment (again, maybe using a setter injection?).
I would keep this task as simple as possible. Instead of conditionally load one implementation of the MyInterface interface at startup and then fire an event that triggers dynamic loading of another implementation of the same interface, I would tackle this problem in a different way, that is much simpler to implement and maintain.
First of all, I'd just load all possible implementations:
#Component
public class MyInterfaceImplementationsHolder {
#Autowired
private Map<String, MyInterface> implementations;
public MyInterface get(String impl) {
return this.implementations.get(impl);
}
}
This bean is just a holder for all implementations of the MyInterface interface. Nothing magic here, just common Spring autowiring behavior.
Now, wherever you need to inject a specific implementation of MyInterface, you could do it with the help of an interface:
public interface MyInterfaceReloader {
void changeImplementation(MyInterface impl);
}
Then, for every class that needs to be notified of a change of the implementation, just make it implement the MyInterfaceReloader interface. For instance:
#Component
public class SomeBean implements MyInterfaceReloader {
// Do not autowire
private MyInterface myInterface;
#Override
public void changeImplementation(MyInterface impl) {
this.myInterface = impl;
}
}
Finally, you need a bean that actually changes the implementation in every bean that has MyInterface as an attribute:
#Component
public class MyInterfaceImplementationUpdater {
#Autowired
private Map<String, MyInterfaceReloader> reloaders;
#Autowired
private MyInterfaceImplementationsHolder holder;
public void updateImplementations(String implBeanName) {
this.reloaders.forEach((k, v) ->
v.changeImplementation(this.holder.get(implBeanName)));
}
}
This simply autowires all beans that implement the MyInterfaceReloader interface and updates each one of them with the new implementation, which is retrieved from the holder and passed as an argument. Again, common Spring autowiring rules.
Whenever you want the implementation to be changed, you should just invoke the updateImplementations method with the name of the bean of the new implementation, which is the lower camel case simple name of the class, i.e. myImplA or myImplB for classes MyImplA and MyImplB.
You should also invoke this method at startup, so that an initial implementation is set on every bean that implements the MyInterfaceReloader interface.
I solved a similar issue by using org.apache.commons.configuration.PropertiesConfiguration and org.springframework.beans.factory.config.ServiceLocatorFactoryBean:
Let VehicleRepairService be an interface:
public interface VehicleRepairService {
void repair();
}
and CarRepairService and TruckRepairService two classes that implements it:
public class CarRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a car");
}
}
public class TruckRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a truck");
}
}
I create an interface for a service factory:
public interface VehicleRepairServiceFactory {
VehicleRepairService getRepairService(String serviceType);
}
Let use Config as configuration class:
#Configuration()
#ComponentScan(basePackages = "config.test")
public class Config {
#Bean
public PropertiesConfiguration configuration(){
try {
PropertiesConfiguration configuration = new PropertiesConfiguration("example.properties");
configuration
.setReloadingStrategy(new FileChangedReloadingStrategy());
return configuration;
} catch (ConfigurationException e) {
throw new IllegalStateException(e);
}
}
#Bean
public ServiceLocatorFactoryBean serviceLocatorFactoryBean() {
ServiceLocatorFactoryBean serviceLocatorFactoryBean = new ServiceLocatorFactoryBean();
serviceLocatorFactoryBean
.setServiceLocatorInterface(VehicleRepairServiceFactory.class);
return serviceLocatorFactoryBean;
}
#Bean
public CarRepairService carRepairService() {
return new CarRepairService();
}
#Bean
public TruckRepairService truckRepairService() {
return new TruckRepairService();
}
#Bean
public SomeService someService(){
return new SomeService();
}
}
By using FileChangedReloadingStrategy your configuration be reload when you change the property file.
service=truckRepairService
#service=carRepairService
Having the configuration and the factory in your service, let you can get the appropriate service from the factory using the current value of the property.
#Service
public class SomeService {
#Autowired
private VehicleRepairServiceFactory factory;
#Autowired
private PropertiesConfiguration configuration;
public void doSomething() {
String service = configuration.getString("service");
VehicleRepairService vehicleRepairService = factory.getRepairService(service);
vehicleRepairService.repair();
}
}
Hope it helps.
If I understand you correctly then the goal is not to replace injected object instances but to use different implementations during interface method call depends on some condition at run time.
If it is so then you can try to look at the Sring TargetSource mechanism in combination with ProxyFactoryBean. The point is that proxy objects will be injected to beans that uses your interface, and all the interface method calls will be sent to TargetSource target.
Let's call this "Polymorphic Proxy".
Have a look at example below:
ConditionalTargetSource.java
#Component
public class ConditionalTargetSource implements TargetSource {
#Autowired
private MyRegistry registry;
#Override
public Class<?> getTargetClass() {
return MyInterface.class;
}
#Override
public boolean isStatic() {
return false;
}
#Override
public Object getTarget() throws Exception {
return registry.getMyInterface();
}
#Override
public void releaseTarget(Object target) throws Exception {
//Do some staff here if you want to release something related to interface instances that was created with MyRegistry.
}
}
applicationContext.xml
<bean id="myInterfaceFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="MyInterface"/>
<property name="targetSource" ref="conditionalTargetSource"/>
</bean>
<bean name="conditionalTargetSource" class="ConditionalTargetSource"/>
SomeService.java
#Service
public class SomeService {
#Autowired
private MyInterface myInterfaceBean;
public void foo(){
//Here we have `myInterfaceBean` proxy that will do `conditionalTargetSource.getTarget().bar()`
myInterfaceBean.bar();
}
}
Also if you want to have both MyInterface implementations to be Spring beans, and the Spring context could not contains both instances at the same time then you can try to use ServiceLocatorFactoryBean with prototype target beans scope and Conditional annotation on target implementation classes. This approach can be used instead of MyRegistry.
P.S.
Probably Application Context refresh operation also can do what you want but it can cause other problems such as performance overheads.
This may be a duplicate question or at least very similar, anyway I answered this sort of question here: Spring bean partial autowire prototype constructor
Pretty much when you want a different beans for a dependency at run-time you need to use a prototype scope. Then you can use a configuration to return different implementations of the prototype bean. You will need to handle the logic on which implementation to return yourself, (they could even be returning 2 different singleton beans it doesn't matter) But say you want new beans, and the logic for returning the implementation is in a bean called SomeBeanWithLogic.isSomeBooleanExpression(), then you can make a configuration:
#Configuration
public class SpringConfiguration
{
#Bean
#Autowired
#Scope("prototype")
public MyInterface createBean(SomeBeanWithLogic someBeanWithLogic )
{
if (someBeanWithLogic .isSomeBooleanExpression())
{
return new ImplA(); // I could be a singleton bean
}
else
{
return new ImplB(); // I could also be a singleton bean
}
}
}
There should never be a need to reload the context. If for instance, you want the implementation of a bean to change at run-time, use the above. If you really need to reload your application, because this bean was used in constructors of a singleton bean or something weird, then you need to re-think your design, and if these beans are really singleton beans. You shouldn't be reloading the context to re-create singleton beans to achieve different run-time behavior, that is not needed.
Edit The first part of this answer answered the question about dynamically injecting beans. As asked, but I think the question is more of one: 'how can I change the implementation of a singleton bean at run-time'. This could be done with a proxy design pattern.
interface MyInterface
{
public String doStuff();
}
#Component
public class Bean implements MyInterface
{
boolean todo = false; // change me as needed
// autowire implementations or create instances within this class as needed
#Qualifier("implA")
#Autowired
MyInterface implA;
#Qualifier("implB")
#Autowired
MyInterface implB;
public String doStuff()
{
if (todo)
{
return implA.doStuff();
}
else
{
return implB.doStuff();
}
}
}
You can use #Resource annotation for injection as originally answered here
e.g.
#Component("implA")
public class ImplA implements MyInterface {
...
}
#Component("implB")
public class ImplB implements MyInterface {
...
}
#Component
public class DependentClass {
#Resource(name = "\${myinterface.type}")
private MyInterface impl;
}
and then set the implementation type in properties file as -
myinterface.type=implA
Be aware that - if interesting to know about - FileChangedReloadingStrategy makes your project highly dependent on the deployment conditions: the WAR/EAR should be exploded by container and your should have direct access to the file system, conditions that are not always met in all situations and environments.
You can use Spring #Conditional on a property value. Give both Beans the same name and it should work as only one Instance will be created.
Have a look here on how to use #Conditional on Services and Components:
http://blog.codeleak.pl/2015/11/how-to-register-components-using.html
public abstract class SystemService {
}
public class FooSystemService extends FileSystemService {
}
public class GoSystemService extends FileSystemService {
}
#Configuration
public class SystemServiceConf {
#Bean
#Conditional(SystemServiceCondition.class)
public SystemService systemService(#Value("${value.key}") value) {
switch (value) {
case A:
return new FooSystemService();
case B:
return new GoSystemService();
default:
throw new RuntimeException("unknown value ");
}
}
}
public class SystemServiceCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return true;
}
}

Spring autowried in Abstract class construtor

I have a scenario where autowired is null when called in the constructor of an abstract class like this :
public abstract class AbstractClass{
#Autowired
#Qualifier("proId")
protected Prop prop;
public AbstractClass(){
prop.getName();
The above throws NullException on deployment.
But the following works when the autowired property called after instantiating
public abstract class AbstractClass{
#Autowired
#Qualifier("proId")
protected Prop prop;
public void Init(){
prop.getName();
}
}
public class DefaultClass extends AbstractClass(){
...
#autowired
DefaultClass dc ;
...
dc.Init();
How can I get the first case to work ?
You can't. Injection can only happen after an object has been created (or during construction with constructor injection). In other words, when prop.getName() is called inside the abstract class constructor, the field is still null since Spring hasn't processed it.
Consider refactoring your code so that your abstract class has a constructor that accepts a Prop argument and use constructor injection
public AbstractClass(Prop prop) {
this.prop = prop;
prop.getName();
}
...
#Autowired
public DefaultClass(Prop prop) {
super(prop);
}
Do you know object creation life-cycle in Java?
Spring doesn't do any magic about that.
There are multiple phases when using Spring for creating beans
an object is instantiated using the constructor
dependencies are injected into bean (obviously except for constructor dependencies which are passed through the object in first phase)
objects #PostConstruct (or InitializingBean) methods are called.
Remember that before constructor there is no instance of your bean, so Spring can not wire anything in it!

interface getBean in test class

I have an interface
#Component("a")
#Scope("prototype")
Public interface A{
.....
}
and the b class that implement interface a
public class B implement A{
...
}
and Junit test class
public class PartyTest {
private static BeanFactory factory = null;
#BeforeClass
public static void loadSpring() {
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext(new String[]{"/spring/mainContext.xml"});
factory = (BeanFactory) applicationContext;
}
#Test
public void personSaveTest() {
A a = (A) factory.getBean("a");
}
}
it throws
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'a' is defined.
My question is, Why i cannot load interface? And if I use #Component("b") on the top of class b it can load class B but it can not load interface A.
Spring managed components are "real instances" of something, so they must always be instances of a concrete implementation (which must be concrete class). You cannot make instances of interfaces or abstract classes.
Note, that this has nothing to do with the type (what might have confused you): Of course, such instances are of any type in the type hierarchy up from the concrete class. In your example, an instance of B is of type B and A.
Spring need a concrete "thing" in order to create a bean. So #Component is misplaced (should be on B). Same goes for #Scope which target a future bean (so something concrete).

Categories