Dzmitry Lazerka
Dzmitry Lazerka

Reputation: 1925

Autowire/inject scoped bean into controller method

Spring 3.2. Everything works when I do:

@Controller
public class MyController {
    @Inject
    Provider<MyBean> provider;

    @RequestMapping("/chart")
    public void getChart(HttpServletResponse resp) {
        provider.get();
    }
}

but it doesn't work when I set MyBean as an argument to getChart:

@Controller
public class MyController {

    @RequestMapping("/chart")
    public void getChart(HttpServletResponse resp, MyBean myBean) {
        // No such method MyBean.<init>()
    }
}

So Spring tries to create a new instance of myBean instead of using already bound one.

Configuration:

@Configuration
public class Config {
    @Inject
    @Bean @Scope("request")
    public MyBean provideMyBean(MyOtherBean myOtherBean) {
         return myOtherBean.getMyBean();
    }
}

It also doesn't work if I make my controller request scoped, and add @Inject/@Autowired to the getChart(). Then it cannot find HttpServletResponse instance (NoSuchBeanDefinitionException), although there surely must be one in request-scope.

Maybe it just isn't implemented in Spring?

Upvotes: 5

Views: 3540

Answers (1)

Dzmitry Lazerka
Dzmitry Lazerka

Reputation: 1925

Resolved by creating a custom HandlerMethodArgumentResolver:

/**
 * Resolves beans defined in {@link Config},
 * because Spring doesn't want to do it implicitly.
 *
 * Makes possible to write something like
 * @RequestMapping(value="/chart", method=RequestMethod.GET)
 * getChart(HttpServletRequest req, MyBean myBean)
 *
 * and Spring will inject both arguments.
 */
public class MethodArgumentResolver implements HandlerMethodArgumentResolver, BeanFactoryAware {
    private final Set<Class> knownTypes = Config.getDeclaredTypes();

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        Class<?> type = parameter.getParameterType();
        return knownTypes.contains(type);
    }

    @Override
    public Object resolveArgument(
            MethodParameter parameter,
            ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest,
            WebDataBinderFactory binderFactory) throws Exception {
        Class<?> type = parameter.getParameterType();
        return beanFactory.getBean(type);
    }
}

and in Config:

static Set<Class> getDeclaredTypes() {
    Set<Class> result = Sets.newHashSet();
    Method[] methods = Config.class.getDeclaredMethods();
    for (Method method : methods) {
        if (method.getAnnotation(Bean.class) != null) {
            result.add(method.getReturnType());
        }
    }
    return result;
}

Upvotes: 1

Related Questions