Spring: Why do we autowire the interface and not the implemented class? - java

Example
interface IA
{
public void someFunction();
}
#Resource(name="b")
class B implements IA
{
public void someFunction()
{
//busy code block
}
public void someBfunc()
{
//doing b things
}
}
#Resource(name="c")
class C implements IA
{
public void someFunction()
{
//busy code block
}
public void someCfunc()
{
//doing C things
}
}
class MyRunner
{
#Autowire
#Qualifier("b")
IA worker;
worker.someFunction();
}
Can someone explain this to me.
How does spring know which polymorphic type to use.
Do I need #Qualifier or #Resource?
Why do we autowire the interface and not the implemented class?

How does spring know which polymorphic type to use.
As long as there is only a single implementation of the interface and that implementation is annotated with #Component with Spring's component scan enabled, Spring framework can find out the (interface, implementation) pair. If component scan is not enabled, then you have to define the bean explicitly in your application-config.xml (or equivalent spring configuration file).
Do I need #Qualifier or #Resource?
Once you have more than one implementation, then you need to qualify each of them and during auto-wiring, you would need to use the #Qualifier annotation to inject the right implementation, along with #Autowired annotation. If you are using #Resource (J2EE semantics), then you should specify the bean name using the name attribute of this annotation.
Why do we autowire the interface and not the implemented class?
Firstly, it is always a good practice to code to interfaces in general. Secondly, in case of spring, you can inject any implementation at runtime. A typical use case is to inject mock implementation during testing stage.
interface IA
{
public void someFunction();
}
class B implements IA
{
public void someFunction()
{
//busy code block
}
public void someBfunc()
{
//doing b things
}
}
class C implements IA
{
public void someFunction()
{
//busy code block
}
public void someCfunc()
{
//doing C things
}
}
class MyRunner
{
#Autowire
#Qualifier("b")
IA worker;
....
worker.someFunction();
}
Your bean configuration should look like this:
<bean id="b" class="B" />
<bean id="c" class="C" />
<bean id="runner" class="MyRunner" />
Alternatively, if you enabled component scan on the package where these are present, then you should qualify each class with #Component as follows:
interface IA
{
public void someFunction();
}
#Component(value="b")
class B implements IA
{
public void someFunction()
{
//busy code block
}
public void someBfunc()
{
//doing b things
}
}
#Component(value="c")
class C implements IA
{
public void someFunction()
{
//busy code block
}
public void someCfunc()
{
//doing C things
}
}
#Component
class MyRunner
{
#Autowire
#Qualifier("b")
IA worker;
....
worker.someFunction();
}
Then worker in MyRunner will be injected with an instance of type B.

Also it may cause some warnigs in logs like a Cglib2AopProxy Unable to proxy method. And many other reasons for this are described here Why always have single implementaion interfaces in service and dao layers?

It worked for me only when I declared following bean in my .XML configuration file because #Autowired is a post process
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"></bean>

Related

Alternative to #Qualifier in spring boot

I have this scenario
team A is implementing an interface Vehicle as ClassAVehicle
team B is implementing a dashboard service in which it uses vehicle implementation
Now team A have new implementation of Vehicle as ClassBVehicle. And team B wants to use it. One way I know is that use of #Qualifier annotation. But for this I require to change team B's code.
So do I have tight coupling here? Can I have some XML based configuration so that team B's code resolves new ClassBVehicle instance automatically?
interface Vehicle{
int getNoTyre();
}
class ClassAVehicle{
int getNoTyre(){
return 1;
}
}
class ClassBVehicle{
int getNoTyre(){
return 2;
}
}
class Dashboard{
// Here everything is fine until classBVehicle is not there
// Now I want to use new classBVehicle.
// One way I see is that using #Qualifier but will it not be tight coupling?
#Autowired
Vehicle oldAInstance;
}
If you use xml to define bean, your way is good to decouple. Another way is that you can use ApplicationContext to get bean dynamically in annotation program. There are two way to getBean with beanName or beanClass. The below is sample:
#Service
public class BService {
private Vehicle vo;
#Autowired
ApplicationContext context;
public void getVehicle(String beanName){
this.vo = (Vehicle) context.getBean(beanName);
}
public void getVehicle(Class beanClz){
this.vo = (Vehicle) context.getBean(beanClz);
}
public void print(){
System.out.println("---class is "+vo.getClass());
}
}
public interface Vehicle {
}
#Component
public class OneVehicle implements Vehicle{
}
#Component
public class TwoVehicle implements Vehicle{
}
#SpringBootApplication
public class SpringDependenciesExampleApplication implements ApplicationRunner {
#Autowired
BService bService;
public static void main(String[] args) {
SpringApplication.run(SpringDependenciesExampleApplication.class, args);
}
#Override
public void run(ApplicationArguments applicationArguments) throws Exception {
bService.getVehicle("oneVehicle");
bService.print();
}
}
// output is ---class is class OneVehicle

Spring dependency injection of generic types usage

I have a question about SOLID design principles in the context of Spring dependency injection with generic type usage. I have the next generic interface:
public interface EmailChecker<T> {
boolean check(T message);
}
Then I have two implementations: one for production and one for the staging environment
#Profile("!production")
#Component
public class EmailRequestCheckerStaging implements EmailChecker<EmailRequest> {
#Override
public boolean check(EmailRequest message) {
//TODO: some code here;
return result;
}
}
#Profile("production")
#Component
public class EmailRequestCheckerProduction implements EmailChecker<EmailRequest> {
#Override
public boolean check(EmailRequest message) {
//TODO: some code here;
return result;
}
}
And finally over here is a dependency injection of 'emailChecker' field:
#Service
public class Receiver {
#Autowired
private EmailChecker<EmailRequest> emailChecker;
public void receiveMessage(EmailRequest dto) {
if(emailChecker.check(dto)) {
//TODO: some logic here
}
}
}
Question: does such dependency injection follows all SOLID principles?
Note: I have multiple implementations of 'EmailChecker' interface with different types (for simplicity I described 'EmailRequest' DTO implementations)
While opinion based, the injected dependency should be explicit via constructor injection.
#Service
public class Receiver {
private EmailChecker<EmailRequest> emailChecker;
#Autowired //could actually be omitted since class has only one constructor
public Receiver(EmailChecker<EmailRequest> emailChecker) {
this.emailChecker = emailChecker;
}
public void receiveMessage(EmailRequest dto) {
if(emailChecker.check(dto)) {
//TODO: some logic here
}
}
}
So that consumers of the Receiver class are aware of what it needs in order for it to function correctly
Classes with explicit dependencies are more honest about what they need. They state very clearly what they require in order to perform their particular function.

Change method based on environment

How can I switch between two method calls of the same name based on the environment?
I know that this can be done at the class level with #Profile, but is there a way to do this at the method level? So ideally, I would want something like the below snippet.
Example
public class Foo {
#Profile('local')
public void bar() {...}
#Profile('prod')
public void bar() {...}
Since Spring 4.x is possible newly to control the profile directly with annotating by #Profile on the method level.
... as a method-level annotation on any #Bean method
Personally, I do not use profiles on the method level, read more at Is Spring's #Profile on methods a good practice?
In your case, I rather suggest you the following approach:
Create two classes and make the implement the common interface.
public interface Foo {
public void bar();
}
Annotate each with #Profile based on the environment.
#Component
#Profile("local")
public class LocalFoo implements Foo {
#Override
public void bar() { ... }
}
#Component
#Profile("prod")
public class ProdFoo implements Foo {
#Override
public void bar() { ... }
}
Since now, they are ready to be injected according to the active profile.

EJB3 instantiation

I got some propably trivial question.
If I got defined EJB3+ interface, lets say it's remote like that:
#Remote
public class FooServiceRemote {
void foo();
}
and one implementation
#Stateless
public class FooService implements FooServiceRemote {
void foo() { ... }
}
How does the application server by default resolves what implementation to use (and call via proxy) if he knows only #EJB annotation for dependency injection like on interface:
public class SomeClass {
#EJB
private FooServiceRemote fooService;
}
Is it done by reflection (shortening name of interface)? Or he scans possible implementations of such interface, choosing one. Or.. ? And what if I want to create more implementations of one interface, is it possible and how to specify what implementation should be instantiated (maybe it is possible via some argument of annotation).
Thanks:-)
In the rare case that you need to have two beans implementing the same interface (not a good practice), you can name them and choose which one you want by name.
#Stateless(name="FooService1")
public class FooService1 implements FooService { }
#Stateless(name="FooService2")
public class FooService2 implements FooService { }
public class SomeClass {
#EJB(beanName="FooService1")
private FooService fooService;
}
Other possible approaches are looking it up using JNDI or the mappedName property.
See the javadoc for EJB annotation here: http://download.oracle.com/javaee/6/api/javax/ejb/EJB.html
Just a fix,
#Remote
interface FooServiceRemote {
void foo();
}
#Stateless
public class FooService implements FooServiceRemote {
void foo() { ... }
}
With this, application server knows which classes implements the specified interface.
If you have two classes, you must specifify which class do you need.

How to set mock object in proxy-based Spring bean?

I'm having problems trying to set the mock object in my wired bean in my testcase.
Here's my simplified problem:-
class SomeClassTest {
#Autowired
private SomeClass someClass;
#Test
public void testRun() {
Service service = mock(ServiceImpl.class);
when(service.doIt()).thenReturn("");
// this line fails with ClassCastException
((SomeClassImpl) someClass).setService(service);
assertEquals("bad", someClass.run());
}
}
interface SomeClass {
String run();
}
class SomeClassImpl implements SomeClass {
private Service service;
public void setService(Service service) {
this.service = service;
}
public String run() {
String value = service.doIt();
return StringUtils.isBlank(value) ? "bad" : "good";
}
}
interface Service {
String doIt();
}
class ServiceImpl implements Service {
public String doIt() {
return "bla";
}
}
In this example, I'm trying to test SomeClass by mocking out Service.doIt() so that I can test different conditions. The problem I'm facing is I'm not sure how exactly I should set the mock Service object in SomeClass. The only way I can think of is to downcast SomeClass into the concrete class to call setService(...), however, I'm getting a ClassCastException saying $Proxy incompatible with SomeClassImpl. I believe all my bean wirings are proxy-based because I'm using AOP to configure the transaction. I really do not want to expose setService(...) in SomeClass interface because it makes no sense to do so in my production code.
Is there a way for me to accomplish this?
Thanks.
You can use the #Resource annotation to get the implementation:
#Resource
private SomeClassImpl someClass;
...
someClass.setService(service);
...
Use additional interface for Service setter than.
or
Do not autowire Service but use 'new' operator in your test.

Categories

Resources