spring-bootdependency-injectionget-mapping

Springboot @GetMapping method injection with object as parameter


I am new to Spring Boot. As I understand how constructor injection works then I can't tell why HelloController works - index method is not a constructor so where/why cat object instance is created? Would be glad to get some documentation or articles about it.

HelloController.java

@RestController
public class HelloController {
    @GetMapping("/{name}")
    public String index(@PathVariable("name") String name, Cat cat){
        cat.setName(name);
        return "<b>Hello " + cat.getName() + "</b>";
    }
}

Cat.java

@Component
public class Cat {
    @Getter @Setter
    private String name;

    public Cat(){
        System.out.println("Created new Cat!");
    }
}

Solution

  • This is an interesting question - only because of the way you have put it. By injection, do you mean creation of a singleton class (You have Cat marked as @Component)? Well to answer this, I added something extra to your print statement:

        public Cat(){
            System.out.println("Created new Cat! with hasCode: " + hashCode());
        }
    

    You see, the hashCode should not change for the same object. The results are not very surprising:

    Created new Cat! with hasCode: 362563829
    Created new Cat! with hasCode: 782885695
    

    The first line was printed when the application was started. That is expected as the bean is created with a scope of singleton and the process completes before the application is completely loaded. The second output comes when I make a request to the endpoint in which case, Spring creates an instance of Cat and passes it as an argument to the @GetMapping. You get as many objects of Cat as your requests. Along the same lines, if i remove @Component from Cat, the first line does not show up. Moving along, I made another change to the RestController class:

    @RestController
    public class HelloController {
    
        @Autowired
        private Cat myCat;
    
        @GetMapping("/{name}")
        public String index(@PathVariable("name") String name, Cat cat){
            cat.setName(name);
            System.out.println("Hello " + myCat.hashCode());
            return "Hello " + cat.getName() + "The age is: " + cat.getAge();
        }
    }
    

    Here is the result of running this application: enter image description here

    What it shows is that the cat passed on to the controller method is not same as the one that was managed by Spring container.

    Concussions

    1. Rest controller method will be passed a new instance of a class everytime it is called.
    2. The controller method is not pass the instance of a spring managed object

    N.B.: I have not really come across any official documentation statinng above findings. Would be very happy to see one though