views:

5044

answers:

2

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;
    }
}
A: 

I think you'll find that the problem is to do with inheritance and using annotations, they do not mix well.

Have you tried to implement the above using inheritance and SimpleFormController with all other details configured in your application context? This will at least narrow down the problem to an annotations and inheritance issue.

Abarax
+1  A: 

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.

Dov Wasserman