5

I'm using Spring 3.1.0.RELEASE with Spring Security 3.1. I want to inject my Spring user (i.e. the user who is currently logged in) into a controller. I want to do this as opposed to using

SecurityContextHolder.getContext().getAuthentication().getPrincipal();

because it allows me to test the controller more easily with JUnit. However, I'm having a problem with my current setup. My question is, what is the correct way to inject my user (per request) into my controller? In my application context file, I have ...

<bean id="userDetails" class="com.myco.eventmaven.security.SecurityHolder" factory-method="getUserDetails" scope="request">
    <aop:scoped-proxy />
</bean>

where I define my factory class as ...

public class SecurityHolder {

@Autowired
private static UserService userService;

public static MyUserDetails getUserDetails() {
    final Authentication a = SecurityContextHolder.getContext().getAuthentication();
    if (a == null) {
        return null;
    } else {
        final MyUserDetails reg = (MyUserDetails) a.getPrincipal();
        final int userId = reg.getId();
        final MyUserDetails foundUser = userService.findUserById(userId);
        return foundUser;
    } // if
}   // getUserDetails

}

but the factory class repeatedly dies because "userService" fails to get autowired (the value is always null). I'm looking for a better way to do all this that can easily also integrate into my JUnit test. Any ideas?

Edit: Here's the JUnit test I'm looking to work with ...

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "file:src/test/resources/testApplicationContext.xml" })
public class UserEventFeedsControllerTest extends AbstractTransactionalJUnit4SpringContextTests {

private MockHttpServletRequest request;
private MockHttpServletResponse response;
...
@Autowired
private RequestMappingHandlerAdapter handlerAdapter;

@Autowired
private RequestMappingHandlerMapping handlerMapping;

@Before
public void setUp() {
    ...
    request = new MockHttpServletRequest();
    response = new MockHttpServletResponse();
}
...
@Test
public void testSubmitUserEventFeedsForm() throws Exception {
    request.setRequestURI("/eventfeeds.jsp");
    request.setMethod("POST");
    final List<EventFeed> allEventFeeds = getAllEventFeeds();
    request.setParameter("userEventFeeds", allEventFeeds.get(0).getId().toString());

    final Object handler = handlerMapping.getHandler(request).getHandler();
    final ModelAndView mav = handlerAdapter.handle(request, response, handler);

    assertViewName(mav, "user/eventfeeds");
}
Dave
  • 15,639
  • 133
  • 442
  • 830

1 Answers1

10

You cannot autowire static fields. There are some workarounds, but I don't want to show them to you...

There are plenty of ways to access current user in an easier and more elegant matter:

See also

Community
  • 1
  • 1
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • Regarding your first suggestion, how do I inject the Principal object in my JUnit test using the Spring4JUnitRunner class? I have added a code example illustrating how I'm running my Junit test. – Dave Mar 20 '12 at 21:14
  • I couldn't find an elegant way of getting from my original UserDetails object to a Principal object so I had to create a test class that extended my original UserDetails object and implemented Principal. I injected that test class into the request per your link and I was good to go. – Dave Mar 21 '12 at 19:26
  • You can't use static because you shouldn't. Ever. Really. – Ben Jul 21 '17 at 17:48