Inject constructor dependency using Lombok Builder - java

I have a class file as below
import com.google.inject.Inject;
import lombok.Builder;
#Builder
public class A {
private final B objB;
private final C objC;
#Inject
public A(B b, C c) {
this.objB = b;
this.objC = c;
}
}
Now if I have to use this object in another class, will the .builder() method takes care of the dependencies being injected.
public class Main {
public void doSomething() {
A a = A.builder().build();
a.getObjB(); // Will it be null ?
a.getObjC(); // Will it be null ?

Injection always only works when you let guice deal with instance creation.
So when you use
#Inject
private A a;
guice will find that it needs a B and a C to create A and inject it.
But when you instantiate A yourself, it does not matter if via new or via builder() guice does not know about the instance creation, thus in your example, B and C will be null.

Related

Mocking a constructor which sets member variables using other member variables whose configurable values are read from properties file

I have a spring mvc application. There is a class A as shown below:
public class A extends X {
private final RetryRegistry retryReg;
#value("${retry.attempts:5}")
private int retryAttempts;
#value("${retry.delay:5000}")
private int retryDelay;
public A( B b, C c, D d){
super(b,c,d);
this.retryReg = RetryRegistry.of(RetryConfig.custom()
.maxAttempts(this.retryAttempts)
.waitDuration(Duration.ofMillis(this.retryDelay))
.build());
}
.......
}
The test class for class A is as shown below:
#PrepareForTest(A.class)
#runWith(PowerMockRunner.class)
#SupressWarnings("unchecked")
public class ATest {
#InjectMocks
private A a;
........
}
Now when test class injects mock and calls A's constructor, the value for retryAttempts is 0 inside the constructor, hence an exception is thrown.
It seems that the configurable properties (from the properties file whose path has been mentioned in servlet-context are no being read) when inject mock tries to construct A.
I tried many things like adding #TestPropertySource to my test file, but it doesn't work.
#TestPropertySource(locations="classpath:SettingsTest.properties")
#PrepareForTest(A.class)
#runWith(PowerMockRunner.class)
#SupressWarnings("unchecked")
public class ATest {
#InjectMocks
private A a;
........
}
Am I doing something wrong, or is #TestPropertySource is only supported for Springboot apps.
Any suggestions on how I can set the configurable properties before #InjectMocks tries to access class A'constructor.
How about you create the registry as a bean in a #Configuration?
// this will automatically be initialized with yours properties
#ConfigurationProperties(prefix="retry)
class RetryProperties {
private int attempts;
private int delay;
}
#Configuration
class RetryConfiguration {
#Bean RetryRegistry registry(RetryProperties props) {
return RetryRegistry.of(RetryConfig.custom()
.maxAttempts(retryProperties)
.waitDuration(Duration.ofMillis(this.retryDelay))
.build());
}
}
#Component // I assume, otherwise the #Value properties wouldn't work
public class A extends X {
private final RetryRegistry retryReg;
public A( B b, C c, D d, RetryRegistry reg){
super(b,c,d);
this.retryReg = reg;
}
.......
}
Now you can mock and inject the registry.
Overall, your structure looks a bit all over the place, with some constructor autowiring, some initialization in the constructor, some fields read from properties. You should probably stick to one of them. Also super(b,c,d) looks pretty suspicious, I've rarely seen a class hierarchy be a good idea for components (with three parameters no less).

Spring inject interface implementation

I'd like to use lombok to inject a class implemented from a interface like below:
#RequiredArgsConstructor(onConstructor = #_(#Inject))
public class className {
#NonNull
private final ClassA1 a1 implements ClassA;
...
}
But obviously this is not working, so what's the correct way to do this?
=================
edit:
Or should I do this way?
public class className {
private ClassA a1;
public className(A1 a1) {
this.a1 = a1; }
}
===================
Here's the code after taking advice from Mykhailo Moskura:
#Component
#RequiredArgsConstructor(onConstructor = #_(#Inject))
public class C {
#NonNull
private A b;
public someFunction() {
b.method();
}
}
Here A is the interface, while b is Class implementing A with camelcase name. And using lombok I injected b, and now call some method of b in some function. However I realized b.method still points to the interface A, but not B.
#NonNull is not required
Lombok will generate a constructor with fields that are marked as final or #NonNull
You can autowire just declaring the interface type
and giving the implementation class name in camel case starting from lower case.
Also you need to declare your implementation as bran and the class in which you are injecting it too.
#Inject is java ee CDI dependency.
#Autowired is spring specific.
Spring supports both but it says to use #Autowired
Here is an example:
public interface A{
}
#Component
public class B implements A{
}
#Component
public class C {
private A a;
#Autowired
public C(A a){
this.a = a;
}
}
Lombok sample:
#RequiredArgsConstructor
#Component
public class C {
//Here it will inject the implementation of A interface with name of implementation (As we have name of impl B we declare field as b , if HelloBeanImpl then helloBeanImpl
private A b;
}
But if you have many implementations of one interface you can use #Qualifier with name of bean or the above sample with lombok where A b where b is the name of implementation

Spring injected beans null in nested class

I have a class with 2 static nested classes that do the same operation on 2 different generic types.
I exposed the 2 classes as beans and added #Autowired for the constructors as I usually do.
Here is the basic setup
abstract class <T> Parent implements MyInterface<T> {
private final Service service;
Parent(Service service){ this.service = service; }
#Override public final void doInterfaceThing(T thing){
T correctedT = map(thing);
service.doTheThing(correctedT);
}
protected abstract T map(T t);
#Service
public static class ImplA extends Parent<A> {
#Autowired ImplA (Service service){ super(service); }
A map(A a){ //map a }
}
#Service
public static class ImplB extends Parent<B> {
#Autowired ImplB (Service service){ super(service); }
B map(B b){ //map b }
}
}
And in another class I have
#Service
public class Doer {
private final List<MyInterface<A>> aImpls;
#Autowired public Doer(List<MyInterface<A>> aImpls){ this.aImpls = aImpls; }
public void doImportantThingWithA(A a){
aImpls.get(0).doInterfaceThing(a);
}
}
When I run the app, everything appears to be injected correctly and when I put a breakpoint in the ImplA and ImplB constructors, I have a not-null value for "service". I also have an ImplA bean in the aImpls list in Doer.
When I call doImportantThingWithA(a) however, "service" is null inside ImplA and I obviously die.
I'm not sure how this is possible because:
I see a nonnull value in my constructors for service which is a final field.
If spring is injecting ImplA and ImplB into another class, it should already have either injected a Service into ImplA or ImplB, or thrown an exception on bean initialization. I have nothing set to lazily load and all bean dependencies are required.
The reason for the nested classes is because the only thing that changes between the 2 implementations is the map() function. Trying to avoid extra classes for 1 line of varying code.
More info:
When I add a breakpoint in Parent.doInterfaceThing(), if I add a watch on "service" I get null as the value. If I add a getService() method, and then call getService() instead of referring directly to this.service, I get the correct bean for service. I don't know the implications of this but something seems weird with the proxying.
It looks like what is causing the issue is Parent.doInterfaceThing();
If I remove final from the method signature, "service" field is correctly populated and the code works as expected.
I don't understand at all why changing a method signature affects the injected value of final fields in my class... but it works now.
What I meant with my "use mappers" comment was something like this:
class MyInterfaceImpl implements MyInterface {
#Autowired
private final Service service;
#Override public final <T> void doInterfaceThing(T thing, UnaryOperator<T> mapper){
T correctedT = mapper.apply(thing);
service.doTheThing(correctedT);
}
// new interface to allow autowiring despite type erasure
public interface MapperA extends UnaryOperator<A> {
public A map(A toMap);
default A apply(A a){ map(a); }
}
#Component
static class AMapper implements MapperA {
public A map(A a) { // ... }
}
public interface MapperB extends UnaryOperator<B> {
public B map(B toMap);
default B apply(B b){ map(b); }
}
#Component
static class BMapper implements MapperB {
public B map(B a) { // ... }
}
}
This does have a few more lines than the original, but not much; however, you do have a better Separation of Concern. I do wonder how autowiring works in your code with the generics, it does look as if that might cause problems.
Your client would look like this:
#Service
public class Doer {
private final List<MapperA> aMappers;
private final MyInterface myInterface;
#Autowired public Doer(MyInterface if, List<MapperA> mappers){
this.myInterface = if;
this.aImpls = mappers; }
public void doImportantThingWithA(A a){
aMappers.stream().map(m -> m.map(a)).forEach(myInterface::doInterfaceThing);
}
}

Can instantiate object of class in which a bean is autowired

There are two classes class A and class B. class B is spring bean and autowired in class A. Class A is not spring bean.
public class A {
int a,c;
public A(int a, int c ){
this.a = a;
this.c = c;
}
#Autowired
B b
// some logic
}
class C {
// Can object will be created
A obj = new A(10,12);
}
if code will compile what will happen I mean object of B will be created.
Object of class B will be created at application start-up, but will not be injected into instance of A, since it's not a spring managed bean.

Spring autowire / Java

If I have two classes like:
Class A {
public String importantValue = "stringvalue";
#Autowire
public B b;
}
#Component
#Scope("prototype");
Class B {
// This should be set automatically
// from IOC Container upon injection.
public String importantValueFromA;
}
Is this even possible? As soon as B class has been injected to A it should automatically set the value in B.
Do you want class A to do some setup on injected class B? That's simple:
#Service
class A {
private String importantValue = "stringvalue";
#Autowire
private B b;
#PostConstruct
public void initB() {
b.importantValueFromA = this.importantValue;
}
}
Obviously you cannot access b.importantValueFromA in A.A constructor because injection didn't yet happen. But #PostConstruct callback is guaranteed to be called after injection.
Another approach is to use setter injection, but it feels kind of hacky:
private B b;
#Autowire
public void setB(B b) {
this.b = b;
b.importantValueFromA = this.importantValue;
}
Two suggestions:
keep your fields private and use setters/methods to access them.
injecting prototype scoped bean to singleton bean might have some unexpected results. Enough to say only one instance of B will be created.
No. B is created before A (since A depends on B) so it will not update the value itself. You have to use a contructor injection:
Class A {
public String importantValue = "stringvalue";
#Autowire
public A(B b) {
b.importantValueFromA = this.importantValue;
}
}
How about doing something like this:
Declare your class B as a scoped proxy, which underlying will expose a proxy to A instead of the real B and will respect the prototype scope.
#Component
#Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
class B {
Then you can inject in an attribute of A in B this way:
#Value("#{a.importantValue}")
private String importantValueFromA;
Here is a full working example in a gist:
https://gist.github.com/3395329

Categories