Showing posts with label dependency injection. Show all posts
Showing posts with label dependency injection. Show all posts

Tuesday, April 21, 2015

spring annotations i never had the chance to use part 1: @primary

Today I remembered an old friend of mine (@primary) with whom we met from tutorials to tutorials. You know that in Spring @Autowired annotation works by type, that is if Spring finds an eligible bean that matches in terms of type it will inject it in. Let's see it on an example.

Assume I have two Singer classes; OperaSinger and MetalSinger.


@Component
public class MetalSinger implements Singer{

    @Override
    public String sing(String lyrics) {
        return "I am singing with DIO voice: "+lyrics;
    }
}
public class OperaSinger implements Singer {
    @Override
    public String sing(String lyrics) {
        return "I am singing in Bocelli voice: "+lyrics;
    }
}
They both implement the Singer interface.
public interface Singer {
    String sing(String lyrics);
}
And lets define a SingerService and inject the Singer bean inside.
@Component
public class SingerService {
    private static final Logger logger = LoggerFactory.getLogger(SingerService.class);

    @Autowired
    private Singer singer;

    public String sing(){
        return singer.sing("song lyrics");
    }
}
What do you think; which Singer will be injected inside? Here's the result:
 I am singing with DIO voice: song lyrics.

This is because OperaSinger is not defined as Component or Service so Spring does not have a clue about it. If we add @Component annotion to it:


@Component
public class OperaSinger implements Singer {
    @Override
    public String sing(String lyrics) {
        return "I am singing in Bocelli voice: "+lyrics;
    }
}
Than I'll get this exception:

 org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [main.service.Singer] is defined: expected single matching bean but found 2: metalSinger,operaSinger

The reason is quite plain to see. If I have more than one bean with same type, and if I use @Autowired annotion which binds type I'll have this exception. Spring does not have a clue which Singer it should use.

Let's favor a music genre and tell Spring to use OperaSinger as Primary.


@Primary
@Component
public class OperaSinger implements Singer{

    @Override
    public String sing(String lyrics) {
        return "I am singing in Bocelli voice: "+lyrics;
    }
}
If we do the SingerService call we will get:
"I am singing in Bocelli voice: song lyrics"
That is because we choose OperaSinger as Primary which means "if you get confused with types you better use this one". Another approach would be the use of qualifier names which directly maps names to beans.

Monday, May 13, 2013

inject a value in a static field using spring

I don't know any software developer who's a great fan of legacy code but as any developer I know that there's no escape from it too. There's a utility class that is used everywhere in our project. I'd like to inject two arguments in it and then use them in another method. But every method of this class is static and Spring does not like injecting stuff in static classes. One way to do it is to add a bean definition for this static class (as if this is not a utility class but a singleton class) and inject the variables. But a better way is to use static method call using MethodInvokingFactoryBean of Spring.

Our bean definition in the application context will be like this: 
  

        
        
            
                apology
                accepted
            
        
    

We don't touch the class part. It should be "MethodInvokingFactoryBean". We will give two properties. The "staticMethod" property will tell Spring the class and its method where we will inject the arguments. The second property (arguments) will tell Spring which arguments to be injected. I'm injecting a list of arguments here. The list consists of "apology" and "accepted". I have my bean definition but where's my class? Here it is:
public class ExampleUtil {
 private static String argument1, argument2;
 public static void setArguments(String arg1, String arg2){
  argument1 = arg1;
  argument2 = arg2;
 }

 public static void printArguments(){
  System.out.println("args: "+argument1+", "+argument2);
 }

}
If you debug you'll try that two Strings (apology and accepted) is injected to ExampleUtil's setArguments() method. As they are static fields they can be reached from other methods such as printArguments().

Monday, July 11, 2011

surprise with spring while doing dependency injection to a child object

My child class (ChildDaoImpl) extends a parent class (ParentDaoImpl) and they are both managed by Spring. When I try to call a parent functionality from the child class with super.parentsMethod() I get NullPointerException.
I debug and see that the parent's injections are not complete at all. The DataSource field that should be injected in ParentDaoImpl is null. But the injection definitions seem ok in application context so where's the problem? I call the parent's bean separately and it works!

Spring does not trace the whole object hierarchy from the child class to the first ancestor which means that it does not do the necessary dependency injections to the parent chain. Thus my DataSource field in the ParentDaoImpl is not injected.
If you extend some class in your java code and you want the child class to work properly with parents' functionality you have to tell Spring explicitly that your child class has a parent.

So your application context should go from





to