I'm new in Spring Boot and I'm I'm facing the following :
public interface A {}
public class AImpl implements A {}
public class MyClassImpl implements MyClass {
private A a;
#Autowired
public MyClassImpl(A a) {
this.a = a;
}
}
And MyClass is being autowired in another class.
At launch, my program is going through MyClassImpl's constructor with parameter a being an AImpl.
But now, I would like a class, let's say A2Impl to implement interface A too, and be the implementation used in MyClassImpl's constructor instead.
A and AImpl come from a library. I wrote this A2Impl class but there is no change, not even an error indicating that SB doesn't know which implementation to use... It just still use AImpl...
What am I missing...?
Related
I need to analyze the call hierarchy of methods in a Java Spring Boot application.
IntelliJ IDEA gets confused when I have:
a interface I declaring I.foo()
an abstract class A with implementation of I.foo()
several concrete classes B, C etc extending A and B overrides A.foo()
I'd like to get the call hierarchy of B.foo() however I get also all callers of C.foo().
If that matters, the classes are autowired similar to the following:
#Component
public class Caller1 {
#Autowired B b;
public void bar(){ b.foo()}
}
#Component
public class Caller2 {
#Autowired C c;
public void bar(){ c.foo()}
}
public interface I {
void foo();
}
public abstract class A implements I {
void foo(){..}
}
#Component
public B extends A {
#Override
void foo() {..}
}
#Component
public C extends A {
..
}
In IntelliJ IDEA, the call hierarchy of B.foo() includes both Caller1.bar() and Caller2.bar(). But I only want callers of B.foo() such as Caller1.bar().
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
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);
}
}
I am trying to create a Component that will be Autowired unless the user creates a different implementation.
I used the following code to try and isolate the problem:
The interface:
public interface A {...}
The implementation:
#Component
#ConditionalOnMissingBean(A.class)
public class AImpl implements A {...}
The usage code:
public class AUsage {
#Autowired
private A a;
}
In this example, I don't get AImpl autowired into AUsage.
If I implement A in another class without the ConditionalOnMissingBean it works.
I tried copying existing uses of #ConditionalOnMissingBean from the internet and noticed that they all reference a #Bean method.
Indeed, when I added this code to AUsage:
public class AUsage {
#Autowired
private A a;
#Bean
#ConditionalOnMissingBean
public A createA() {
return new AImpl();
}
}
and removed the annotations from AImpl:
public class AImpl implements A {...}
everything works as expected.
I'd be pleased to get an explanation to this, if anyone knows.
In my spring-based project I have a core module ('core') with a class
#Component
public class Superclass {
// stuff
}
instances of which are injected by type throughout the code like this:
public class AService {
#Autowired
private Superclass superclass;
// service stuff
}
I also have two other modules that depend on the core module and one of which (let's call it 'module1') extends Superclass:
#component
public class Subclass extends Superclass {
// overridden stuff
}
The other module ('module2') uses Superclass as is.
Now I want that when I compile and run 'child1' an instance of Subclass is used everywhere an instance of Superclass is expected. So I write a configuration class:
#Configuration
public class Module2Configuration {
#Bean
public Superclass superclass(){
return new Subclass();
}
}
When I run this I see both Superclass and Subclass instantiated which is definitely not what I want. How do specify in 'module1' which type Spring should instantiate?
You can use #Qualifier("some name") annotation.
There is more information about that: http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/
Spring eagerly instantiates singleton beans as stated in the documentation:
By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process.
which might explain why both #Components are created.
To specifiy which implementation is provided as a dependency you might want to check on Qualifiers that enable to choose between different implementations. In combination with lazy loading this should do the trick.
Depending on your personal taste you could also use delegation instead of inheritance using a separated interface:
public interface MyService {
public String foobar(int baz);
}
public static class CommonBehavior {
// whatever is used by Superclass and Subclass
}
#Component #Lazy
public class FormerSuperClass implements MyService {
private final CommonBehavior ...;
...
}
#Component #Lazy
public class FormerSubClass implements MyService {
private final CommonBehavior ...;
...
}
Good luck!
There are 2 methods: Use #Qualifier("SubclassName") Or Mark your subclass as #Component and declare the subclass when #Autowired
In your case:
Use #Qualifier("SubclassName")
#Component
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
#Qualifier("Subclass")
private Superclass superclass;
// service stuff
}
2.Mark your subclass as #Component and declare the subclass when #Autowired
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
private Subclass subclass;
// service stuff
}