0

I have a problem with an autowire of a component.

My implementation consists in a Controller, an interface used by the Controller, and a Component that implements thagt interface. I want to autowire another component in the implementation.

This is the controller:

@Controller
public class MyController {

    @RequestMapping(path = "/myPath/{subpath}", method = RequestMethod.GET)
    public void myMethod(@PathVariable("subpath") String subpath, HttpServletResponse response){        
        try{
            MyHandler handler = new MyHandlerImpl(response.getOutputStream());
            handler.handle();       
        } catch (Exception e) {

        }       
    }   
}

This is the interface:

public interface MyHandler {

    public void handle();

}

And this is the Implementation:

// tried all: @Component, @Service, @Repository, @Configurable
public class MyHandlerImpl implements MyHandler {

    @Autowired
    MyComponentToAutowired myComponentToAutowired; // <= this is NULL

    public MyHandlerImpl (ServletOutputStream output) {
        this.output = output;
    }

    private OutputStream output;

    public void handle() {
        myComponentToAutowired.theMethod(); // <- NullPointerException at this point
        // ...
    }

    /*
        If I don't create a default constructor, Spring crash at the start because it not finds the default constructor with no-args.
    */

}

What can I do to autowire the component properly?

Thanks.

Alessandro C
  • 3,310
  • 9
  • 46
  • 82
  • Create a singleton `MyHandlerImpl` bean and pass the `ServletOutputStream` to its `handle` method. Or create your own instance of `MyHandlerImpl` on each request and pass a `MyComponentToAutowired` bean to its `handle` method. – Sotirios Delimanolis May 23 '16 at 16:21

1 Answers1

0

You need to annotate a MyComponentToAutowired implementation with @Component. Where is your MyComponentToAutowired implementation?

That will create an instance of MyComponentToAutowired in the Spring context that will be wired to your MyHandlerImpl instance.

The problem is that you are instantiating a MyHandlerImpl object and not using the one created by the IoC Container (Spring), that's the one that have the MyComponentToAutowired injected.

In order to use the wired MyHandlerImpl you should do

@Component
public class MyHandlerImpl implements MyHandler {

and

@Controller
public class MyController {

@Autowired
MyHandlerImpl myHandler;

@RequestMapping(path = "/myPath/{subpath}", method = RequestMethod.GET)
public void myMethod(@PathVariable("subpath") String subpath, HttpServletResponse response){        
    try{
        myHandler.setStream(response.getOutputStream());
        handler.handle();       
    } catch (Exception e) {

    }       
  }   
}

But then all the requests will be sharing the same MyHandlerImpl instance and this is no what you want.

You could pass the MyComponentToAutowired to the handle method and inject it to the controller.

@Controller
public class MyController {

@Autowired
MyComponentToAutowired myComponent;

@RequestMapping(path = "/myPath/{subpath}", method = RequestMethod.GET)
public void myMethod(@PathVariable("subpath") String subpath, HttpServletResponse response){        
    try{
        MyHandler handler = new MyHandlerImpl(response.getOutputStream());
        handler.handle(myComponent);       
    } catch (Exception e) {

    }       
  }   
}

I assume that your MyComponentToAutowired is stateless.

gabrielgiussi
  • 9,245
  • 7
  • 41
  • 71