Java Dependency Injection - Annotation based setup possible in scenario? - java

I'm fiddling around with Dependency Injection in Java using simple JUnit tests and javax.inject-Annotations.
I have the following scenario: There's a "top-level"-class (SomeObject) with two dependencies (SomeObjDepA and SomeObjDepB). SomeObjDepB has a dependency to SomeObjDepA too. And this should be the same instance of SomeObjDepA as in the SomeObject-instance. But SomeObjDepA must not be a Singleton, since different SomeObj-instances shall have different instances of SomeObjDepA (and SomeObjDepB). This is where I am stuck.
To be more clear, here's some basic code without any configuration:
public class SomeObject {
#Inject
private SomeObjDepA someObjDepA;
#Inject
private SomeObjDepB someObjDepB;
public SomeObjDepA getSomeObjDepA() {
return someObjDepA;
}
public SomeObjDepB getSomeObjDepB() {
return someObjDepB;
}
}
public class SomeObjDepA {
}
public class SomeObjDepB {
#Inject
private SomeObjDepA someObjDepA;
public SomeObjDepA getSomeObjDepA() {
return someObjDepA;
}
}
public class DependencyInjectionTest {
#Inject
private Provider<SomeObject> someObjProvider;
#Test
public void instancesTest() {
final SomeObject someObjInst1 = this.someObjProvider.get();
final SomeObject someObjInst2 = this.someObjProvider.get();
Assertions.assertNotEquals(someObjInst1, someObjInst2);
Assertions.assertNotEquals(someObjInst1.getSomeObjDepA(), someObjInst2.getSomeObjDepA());
Assertions.assertNotEquals(someObjInst1.getSomeObjDepB(), someObjInst2.getSomeObjDepB());
Assertions.assertEquals(someObjInst1.getSomeObjDepA(), someObjInst1.getSomeObjDepB().getSomeObjDepA());
Assertions.assertEquals(someObjInst2.getSomeObjDepA(), someObjInst2.getSomeObjDepB().getSomeObjDepA());
}
}
Question: How to setup dependency injection to build up a scenario like this? I am looking for a annotation or Java based configuration (if possible)
I am currently using CDI 2.0 (Weld 3.1.5), and JUnit 5 for testing. I prefer a solution using CDI, but any other solution using Spring, Guice, etc. would be nice to.
Many thanks in advance

Depending on what you're looking for, you want to make use of scopes and/or qualifiers.
You can think of a scope as a lifespan. If you don't specify a scope (you don't anywhere above), then the default scope is "create a new one whenever one is called for", which is known as dependent scope. (This is because the thing being injected's lifespan is dependent on the thing that is housing it.)
As #Glains points out above, #ApplicationScoped is one way of indicating that a bean should be in "application scope", which is basically singleton scope with extra goodies. So you can put that on any class that meets the requirements to indicate that its lifespan should be that of the application as a whole.
Next, you talk about distinguishing between two otherwise indistinguishable occurrences of a given object, both of which might be singletons (SomeObjDepA). Qualifiers let you do this.
Let's say that you have a producer method that makes a "yellow" SomeObjDepA and another one that makes a "red" SomeObjDepA. To do this in CDI, you'll need qualifier annotations that express the "red" and "yellow" bits. Then apply them at the site of production. For example:
#ApplicationScoped // producer methods need to be "housed" in a bean
public class Host {
#Produces
#Red // you define this annotation following the spec's rules for qualifier annotations
#ApplicationScoped // ...or whatever scope is called for
public SomeDepA produceRedDepA() {
return new SomeDepA();
}
#Produces
#Yellow // you define this annotation following the spec's rules for qualifier annotations
#ApplicationScoped // ...or whatever scope is called for
public SomeDepA produceYellowDepA() {
return new SomeDepA();
}
}
Here we have two producer methods that will be called by the container appropriately and will "satisfy" relevant injection points elsewhere. For example, in SomeObject, you might have:
#Inject
#Red
private SomeDepA red;
#Inject
#Yellow
private SomeDepA yellow;

Related

Internal working of field injection in spring and why is it not recommended to use

As the title suggests , I want to know how does field injection internally works in spring , I read many articles on this and got to know few things like below but didn't understood the exact reason behind it :
-> It should not be used because when you do unit testing then you are dependent upon the spring
container to instantiate the class in case of field injection.
-> You cannot use "final" keyword in case of field injection , means you cannot make the field immutable.
-> It internally uses reflection
I want to know how exactly does #Autowired works internally , how does it uses reflection , I am trying to understand the exact reason behind all the above mentioned points, what happens behind the scenes when we write the below code :
#Component
public class B {
#Autowired
private A a1;
}
I have read similar questions on stack overflow about this topic , but I couldn't find the exact explanation that I am looking.
Spring has a concept of Bean Post Processors.
When spring builds a bean it applies registered bean post processors that help to "initialize" the bean.
So, there is org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor that handles autowiring.
Basically it works with an newly created object. Spring introspects the fields of the beans (by using reflection). The fields that have #Autowired is a subject for processing with this bean post processor. It finds the candidate for injection in the application context and actually injects the value.
Now given this information, its understandable why final fields cannot be autowired. Leave alone spring, In pure Java, final fields must be instantiated directly right during the declaration (final int i = 123) or in the constructor of the class. But the autowiring happens after constructor, so its impossible to autowire the final fields.
As for the unit testing, the private properties must be somehow configured from the test. But since they're encapsulated (yes, spring kind of breaks encapsulation in this case for its usage), its impossible to write a good test for the class that contains fields injection. That's is a reason to switch to constructor injection.
public class FieldInjection {
#Autowired
private A a;
}
VS.
public class ConstructorInjection {
private final A a;
// this can be generated by lombok, you don't have to put #Autowired on constructor in the case of single constructor, spring will use it to create a bean
public ConstructorInjection(A a) {
this.a = a;
}
}
Now the test for FieldInjection class is impossible:
public class FieldInjectionTest {
#Test
void test() {
FieldInjection underTest = new FieldInjection();
how do you know that you should instantiate A a. ????
}
}
However in the case of constructor injection its a trivial task:
public class ConstructorInjectionTest {
#Test
void test() {
A a = mock(A.class);
ConstructorInjection underTest = new ConstructorInjection(a);
// the dependencies must be supplied in the constructor
// otherwise its impossible to create an object under test
}
}

Can I negate (!) a collection of spring profiles?

Is it possible to configure a bean in such a way that it wont be used by a group of profiles? Currently I can do this (I believe):
#Profile("!dev, !qa, !local")
Is there a neater notation to achieve this? Let's assume I have lots of profiles. Also, if I have a Mock and concrete implementation of some service (or whatever), Can I just annotate one of them, and assume the other will be used in all other cases? In other words, is this, for example, necessary:
#Profile("dev, prof1, prof2")
public class MockImp implements MyInterface {...}
#Profile("!dev, !prof1, !prof2") //assume for argument sake that there are many other profiles
public class RealImp implements MyInterface {...}
Could I just annotate one of them, and stick a #Primary annotation on the other instead?
In essence I want this:
#Profile("!(dev, prof1, prof2)")
Thanks in advance!
Since Spring 5.1 (incorporated in Spring Boot 2.1) it is possible to use a profile expression inside profile string annotation (see the description in Profile.of(..) for details).
So to exclude your bean from certain profiles you can use an expression like this:
#Profile("!dev & !prof1 & !prof2")
Other logical operators can be used as well, for example:
#Profile("test | local")
Short answer is: You can't in versions of Spring prior to Spring 5.1 (i.e. versions of Spring Boot prior to 2.1).
But there is a neat workarounds that exists thanks to the #Conditional annotation.
Create Condition matchers:
public static abstract class ProfileCondition extends SpringBootCondition {
#Override
public ConditionOutcome getMatchOutcome(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
if (matchProfiles(conditionContext.getEnvironment())) {
return ConditionOutcome.match("A local profile has been found.");
}
return ConditionOutcome.noMatch("No local profiles found.");
}
protected static abstract boolean matchProfiles(final Environment environment);
}
public class DevProfileCondition extends ProfileCondition {
protected boolean matchProfiles(final Environment environment) {
return Arrays.stream(environment.getActiveProfiles()).anyMatch(prof -> {
return prof.equals("dev") || prof.equals("prof1") || prof.equals("prof2");
});
}
}
public static class ProdProfileCondition extends ProfileCondition {
protected boolean matchProfiles(final Environment environment) {
return Arrays.stream(environment.getActiveProfiles()).anyMatch(prof -> {
return (!prof.equals("dev") && !prof.equals("prof1") && !prof.equals("prof2"));
});
}
}
Use it
#Conditional(value = {DevProfileCondition.class})
public class MockImpl implements MyInterface {...}
#Conditional(value = {ProdProfileCondition.class})
public class RealImp implements MyInterface {...}
However, this aproach requires Springboot.
From what I understand, what you want to do is be capable of replacing some of your beans with some stub/mock beans for specific profiles. There are 2 ways to address this:
Exclude the not needed beans for the corresponding profiles and include by default everything else
Include only the required beans for each profile
The first option is feasible but difficult. This is because the default behaviour of Spring when providing multiple profiles in #Profile annotation is an OR condition (not an AND as you would need in your case). This behaviour of Spring is the more intuitive, because ideally each profile should correspond to each configuration of your application (production, unit testing, integration testing etc.), so only one profile should be active at each time. This is the reason OR makes more sense than AND between profiles. As a result of this, you can work around this limitation, probably by nesting profiles, but you would make your configuration very complex and less maintainable.
Thus, I suggest you go with the second approach. Have a single profile for each configuration of your application. All the beans that are the same for every configuration can reside in a class that will have no #Profile specified. As a result, these beans will be instantiated by all the profiles. For the remaining beans that should be distinct for each different configuration, you should create a separate #Configuration class (for each Spring profile), having all of them with the #Profile set to the corresponding profile. This way, it will be really easy to tract what is injected in every case.
This should be like below:
#Profile("dev")
public class MockImp implements MyInterface {...}
#Profile("prof1")
public class MockImp implements MyInterface {...}
#Profile("prof2")
public class MockImp implements MyInterface {...}
#Profile("the-last-profile") //you should define an additional profile, not rely on excluding as described before
public class RealImp implements MyInterface {...}
Last, #Primary annotation is used to override an existing beans. When there are 2 beans with the same type, if there is no #Primary annotation, you will get an instantiation error from Spring. If you define a #Primary annotation for one of the beans, there will be no error and this bean will be injected everywhere this type is required (the other one will be ignored). As you see, this is only useful if you have a single Profile. Otherwise, this will also become complicated as the first choice.
TL;DR: Yes you can. For each type, define one bean for each profile and add a #Profile annotation with only this profile.

Guice / DI and mixing injection and parameters passed in at runtime

I have a situation where when I initialize some of my classes, some of the fields I need to be injected (e.g. references to factories etc) whereas some others are dynamic and created at runtime (e.g. usernames etc). How do I construct such objects using the GUICE framework?
Simply annotating the fields I need injected as #Inject doesn't work as they seem to not be set up when creating an object using the constructor. For instance:
class C {
#Inject
private FactoryClass toBeInjected;
private ConfigurationField passedIn;
public C(ConfigurationField passedIn) {
this.passedIn = passedIn;
}
}
If my understanding is correct (and I could be wrong), the fact that I'm creating a new instance of C via new and not through Guice means that no injection will take place. I do need to pass these parameters in the constructor, but also want some fields injected -- so how do I solve this problem?
A feature specifically matching "mixing injection and parameters passed" would be Assisted Injection.
class C {
// Guice will automatically create an implementation of this interface.
// This can be defined anywhere, but I like putting it in the class itself.
interface Factory {
C create(ConfigurationField passedIn);
}
#Inject
private FactoryClass toBeInjected;
private ConfigurationField passedIn;
private SomeOtherDepIfYoudLike otherDep;
#Inject public C(#Assisted ConfigurationField passedIn,
SomeOtherDepIfYoudLike otherDep) {
this.passedIn = passedIn;
this.otherDep = otherDep;
}
}
Now in your module:
#Override public void configure() {
install(new FactoryModuleBuilder().build(C.Factory.class));
}
Now when someone wants to create a C, they can avoid calling the constructor directly; instead, they inject a C.Factory into which they pass a ConfigurationField instance of their choice and receive a fully-constructed, fully-injected C instance. (Like with most well-designed DI objects, they can call the constructor directly.)
Note that this design is especially useful in a few ways:
You can use constructor injection, treat all your fields as final, and treat the object as immutable.
If you stick with constructor injection entirely, your object will never be in a partially-initialized state, and your API stays simple (call the constructor and your object is ready).
For testing, you can write any implementation of C.Factory and have it return any instance you want. This can include test doubles of C or its factory: Fakes, mocks, or spies that you create manually or by using Mockito, EasyMock, JMock, or any other mocking framework.
What you are looking for is "On Demand" Injections:
public static void main(String[] args)
{
Injector injector = Guice.createInjector(...);
CreditCardProcessor creditCardProcessor = new PayPalCreditCardProcessor();
injector.injectMembers(creditCardProcessor);
}
or for static things
#Override public void configure() {
requestStaticInjection(ProcessorFactory.class);
...
}
All explained very well https://github.com/google/guice/wiki/Injections#on-demand-injection.
Note:
Both of these things are code smells and should only really be used
for migrating old code over to Guice. New code should not use these
approaches.

Spring JPA: How to get dependencies right with injection?

My data model consists of three objects, let's call them A, B and C. A has a one-to-many relationship to B, and B to C. They are only modeled as interfaces.
To get concrete versions of them, I have interfaces AProvider, BProvider and CProvider which provide create, retrieve, and delete operations.
I am now doing an implementation using Spring-JPA and Hibernate by the means of spring-boot-starter-data-jpa. For this, I have three #Entitys InternalA, InternalB and InternalC which do not implement the A, B and C interfaces, but are used as transfer objects only. To access them, I use the autogenerated repositories from Spring (see CrudRepository).
For creating the "real" objects, I have implementations of the XProvider interfaces which inject their necessary dependencies. This structure is the following (I prefer javax.inject style injection):
#Component
public class AProviderImpl implements AProvider {
#Inject
private InternalARepository _aRepository;
// implementation
}
#Component
public class BProviderImpl implements BProvider {
#Inject
private InternalBRepository _bRepository;
#Inject
private AProvider _aProvider;
// implementation
}
#Component
public class CProviderImpl implements CProvider {
#Inject
private InternalCRepository _cRepository;
#Inject
private BProvider _bProvider;
// implementation
}
I figure out that this should work, and the AutowireCapableBeanFactory correctly figures out what to instantiate first. But this only works up to the BProviderImpl, e.g., when removing the CProviderImpl. As soon as CProviderImpl exists, initialization fails with No qualifying bean of type [com.somewhere.BProvider] found.
It makes no difference if I use #Autowired instead of #Inject.
I stepped through the initialization process with a debugger and the CProvider is indeed initialized first, i.e., the bean factory does not correctly figure out that it needs the BProvider which in turn needs the AProvider first.
My current workaround is using #DependsOn like this:
#Component("myAProvider")
public class AProviderImpl implements AProvider { ... }
#Component("myBProvider")
#DependsOn("myAProvider")
public class BProviderImpl implements BProvider { ... }
#Component("myCProvider")
#DependsOn("myBProvider")
public class CProviderImpl implements CProvider { ... }
This works, but I read elsewhere that this is a code smell and should be avoided because it introduces implicit dependencies. Currently, this is all local to one module, so it is no problem there, but later my model will grow and I will have model elements and providers spread over multiple modules, so I cannot use #DependsOn until kingdom come.
Is there a better way to tackle this?
You can use the #Order annotation, this will enable to prioritize Bean loading and doesn't pollute your loading hierarchy as with #DependsOn. With this you can certainly modularize your design later without a problem. Lowest order value has highest priority.
#Component("myAProvider")
#Order(1)
public class AProviderImpl implements AProvider { ... }
#Component("myBProvider")
#Order(2)
public class BProviderImpl implements BProvider { ... }
#Component("myCProvider")
#Order(3)
public class CProviderImpl implements CProvider { ... }
I found another workaround: Lazy initialization. Since initialization of my XProviders are not long-running, I just added the #Lazy annotation. That way, Spring creates uninitialized instances and adds them to the registry, and when at a later point an injected dependency is accessed, it is initialized.
I don't know if this is the best solution, but I think it is better than using #DependsOn and it should be working over module boundaries.

Spring Autowire Annotation with Several Interface Implementations

Suppose you have one interface
public interface A {
public void doSomething();
}
and two implementation classes
#Component(value="aImpl1")
public class AImpl1 implements A {
}
#Component(value="aImpl2")
public class AImpl2 implements A{
}
And finally a class that will use an "A" implementation:
#Component
public class MyClass {
#Autowire
A a;
}
Now if I want to inject AImpl1 I add the #Qualifier("aImpl1") while if I want to inject AImpl2 I add #Qualifier("aImpl2")
The question is: Is it possible to instruct spring somehow to look up all implementations of "A" in this case AImpl1 and AImpl2 and use some application specific conventions to choose the most appropriate implementation? for example in this case my convention could be use the implementation with the greatest suffix (i.e. AImpl2)?
EDIT: the class MyClass should not be aware at all about the implementation lookup logic, it should just find its property "a" set with an object of AImpl2.
You can inject all implentations as List:
#Autowired
List<A> as;
or as Map with bean name as key:
#Autowired
Map<String, A> as;
and then choose proper implementation manually (perhaps, in a setter method):
#Autowired
public void setAs(Map<String, A> as) {
this.a = ...;
}
Assuming you already have hundreds of interfaces and implementations (as you said in a comment), and you do not want to refactor all the code... then is a tricky problem... and this is a tricky solution:
You could create a custom BeanDefinitionRegistryPostProcessor and implement either the method postProcessBeanDefinitionRegistry or postProcessBeanFactory.
This way you have access to all bean definitions before they are instantiated and injected. Do your logic to find which is the preferred implementation for each one of your interfaces, and then, set that one as primary.
#Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(
BeanDefinitionRegistry registry) throws BeansException {
// this method can be used to set a primary bean, although
// beans defined in a #Configuration class will not be avalable here.
}
#Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
// here, all beans are available including those defined by #configuration, #component, xml, etc.
// do some magic to somehow find which is the preferred bean name for each interface
// you have access to all bean-definition names with: beanFactory.getBeanDefinitionNames()
String beanName = "aImpl2"; // let's say is this one
// get the definition for that bean and set it as primary
beanFactory.getBeanDefinition(beanName).setPrimary(true)
}
}
The hard part is to find the bean name, it depends of the specifics of your application. I guess that having a consistent naming convention will help.
Update:
It seems that both methods in the interface BeanDefinitionRegistryPostProcessor can be used for this purpose. Having in mind that in the postProcessBeanDefinitionRegistry phase, beans configured through #configuration classes are not yet available, as noted in the comments below.
On the other hand they are indeed available in postProcessBeanFactory.
If you have a Configuration class you could use a method in that to make the decision of which implementation of A to return. Then the autowired will inject the appropriate instance for that class.
#Configuration
public class ApplicationConfiguration {
#Bean
A getA() {
// instantiate the implementation of A that you would like to have injected
// or you could use reflection to find the correct class from the classpath.
// return the instance
}
}
This assumes you always want to use the same instance everywhere you are injecting A. If not, then you could have different #Bean annotated methods with names to get different versions.
You can try to use Spring Profiles.

Categories

Resources