Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Annotated Spring-MVC controller not recognized when controller extends interface

I'm using spring 2.5, and am using annotations to configure my controllers. My controller works fine if I do not implement any additional interfaces, but the spring container doesn't recognize the controller/request mapping when I add interface implementations.

I can't figure out why adding an interface implementation messes up the configuration of the controller and the request mappings. Any ideas?

So, this works:

package com.shaneleopard.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.providers.encoding.Md5PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.shaneleopard.model.User;
import com.shaneleopard.service.UserService;
import com.shaneleopard.validator.RegistrationValidator;
import com.shaneleopard.web.command.RegisterCommand;

@Controller
public class RegistrationController {

    @Autowired
    private UserService userService;

    @Autowired
    private Md5PasswordEncoder passwordEncoder;

    @Autowired
    private RegistrationValidator registrationValidator;

    @RequestMapping( method = RequestMethod.GET, value = "/register.html" )
    public void registerForm(@ModelAttribute RegisterCommand registerCommand) {
        // no op
    }

    @RequestMapping( method = RequestMethod.POST, value = "/register.html" )
    public String registerNewUser( @ModelAttribute RegisterCommand command,
            Errors errors ) {
        String returnView = "redirect:index.html";

        if ( errors.hasErrors() ) {
            returnView = "register";
        } else {
            User newUser = new User();
            newUser.setUsername( command.getUsername() );
            newUser.setPassword( passwordEncoder.encodePassword( command
                    .getPassword(), null ) );
            newUser.setEmailAddress( command.getEmailAddress() );
            newUser.setFirstName( command.getFirstName() );
            newUser.setLastName( command.getLastName() );

            userService.registerNewUser( newUser );
        }
        return returnView;

    }

    public Validator getValidator() {
        return registrationValidator;
    }
}

but this doesn't:

package com.shaneleopard.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.providers.encoding.Md5PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.shaneleopard.model.User;
import com.shaneleopard.service.UserService;
import com.shaneleopard.validator.RegistrationValidator;
import com.shaneleopard.web.command.RegisterCommand;

@Controller
public class RegistrationController extends ValidatingController {

    @Autowired
    private UserService userService;

    @Autowired
    private Md5PasswordEncoder passwordEncoder;

    @Autowired
    private RegistrationValidator registrationValidator;

    @RequestMapping( method = RequestMethod.GET, value = "/register.html" )
    public void registerForm(@ModelAttribute RegisterCommand registerCommand) {
        // no op
    }

    @RequestMapping( method = RequestMethod.POST, value = "/register.html" )
    public String registerNewUser( @ModelAttribute RegisterCommand command,
            Errors errors ) {
        String returnView = "redirect:index.html";

        if ( errors.hasErrors() ) {
            returnView = "register";
        } else {
            User newUser = new User();
            newUser.setUsername( command.getUsername() );
            newUser.setPassword( passwordEncoder.encodePassword( command
                    .getPassword(), null ) );
            newUser.setEmailAddress( command.getEmailAddress() );
            newUser.setFirstName( command.getFirstName() );
            newUser.setLastName( command.getLastName() );

            userService.registerNewUser( newUser );
        }
        return returnView;

    }

    public Validator getValidator() {
        return registrationValidator;
    }
}
like image 552
layne Avatar asked Sep 29 '08 23:09

layne


People also ask

CAN controller extends another controller?

You can extend one spring controller by another spring controller.

What happens when a class is annotated with the @controller annotation?

The @Controller annotation indicates that a particular class serves the role of a controller. There is no need to extend any controller base class or reference the Servlet API.

Can a controller implement an interface?

Now, when Spring MVC controllers implement an interface, they do this not only in the standard Java way but also inherit all web request related functionality defined in the interface. As always, we may find the corresponding code snippets on our GitHub repository.

Which method is provided on the controller interface which handles requests?

When a Controller has been found to handle the request, the handleRequest method of the located Controller will be invoked; the located Controller is then responsible for handling the actual request and — if applicable — returning an appropriate ModelAndView .


2 Answers

layne, you described the problem as happening when your controller class implements an interface, but in the code sample you provided, the problem occurs when your controller class extends another class of yours, ValidatingController.

Perhaps the parent class also defines some Spring annotations, and the Spring container noticed them first and classified the controller class as that type of managed object and did not bother to check for the @Controller annotation you also defined in the subclass. Just a guess, but if that pans out, I'd suggest reporting it to the Spring team, as it sounds like a bug.

like image 114
Dov Wasserman Avatar answered Nov 09 '22 14:11

Dov Wasserman


By default JDK proxy are created using interface and if controller implements an interface the RequestMapping annotation gets ignored as the targetClass is not being used

Add this in your servlet context config:

<aop:aspectj-autoproxy proxy-target-class="true"/>
like image 28
user979051 Avatar answered Nov 09 '22 12:11

user979051