title: Trouble wiring Hibernate, JDBC and SpringSecurity together
body: <p>I am working on a simple Spring web app. I'm using Spring Security for user authentication, and Hibernate for persistence. I want Spring Security to use the database (as opposed to basic in-memory authentication).</p>
  
  <p>However, I am getting an exception when running the app.</p>
  
  <pre><code>    SEVERE: Servlet /knights threw load() exception
  java.lang.ClassCastException: 
  org.springframework.web.accept.ContentNegotiationManagerFactoryBean$$EnhancerByCGLIB$$fae0dbb8 cannot be cast to org.springframework.web.accept.ContentNegotiationManager
  </code></pre>
  
  <p>I have no idea what could be causing this. Could this be an issue with Hibernate-generated proxies? The trouble is, since I'm new to Spring and I'm following various online tutorials, my configuration is a mix of XML and Java configuration files. My Spring Security and DataSource are configured in Java, and Hibernate is configured using XML.</p>
  
  <p>Here's the full stack trace:</p>
  
  <pre><code>SEVERE: Context initialization failed
  org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'handlerExceptionResolver' defined in class org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerExceptionResolver org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.handlerExceptionResolver()] threw exception; nested exception is java.lang.ClassCastException: org.springframework.web.accept.ContentNegotiationManagerFactoryBean$$EnhancerByCGLIB$$6412755f cannot be cast to org.springframework.web.accept.ContentNegotiationManager
      at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:581)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1025)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:921)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
      at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
      at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
      at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
      at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
      at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
      at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:651)
      at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:599)
      at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:665)
      at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:518)
      at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:459)
      at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
      at javax.servlet.GenericServlet.init(GenericServlet.java:160)
      at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1280)
      at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1193)
      at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1088)
      at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5176)
      at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5460)
      at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
      at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
      at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
      at java.util.concurrent.FutureTask.run(FutureTask.java:262)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
      at java.lang.Thread.run(Thread.java:745)
  Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerExceptionResolver org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.handlerExceptionResolver()] threw exception; nested exception is java.lang.ClassCastException: org.springframework.web.accept.ContentNegotiationManagerFactoryBean$$EnhancerByCGLIB$$6412755f cannot be cast to org.springframework.web.accept.ContentNegotiationManager
      at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:181)
      at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:570)
      ... 30 more
  Caused by: java.lang.ClassCastException: org.springframework.web.accept.ContentNegotiationManagerFactoryBean$$EnhancerByCGLIB$$6412755f cannot be cast to org.springframework.web.accept.ContentNegotiationManager
      at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$fe413563.mvcContentNegotiationManager(&lt;generated&gt;)
      at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.addDefaultHandlerExceptionResolvers(WebMvcConfigurationSupport.java:632)
      at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.handlerExceptionResolver(WebMvcConfigurationSupport.java:596)
      at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$fe413563.CGLIB$handlerExceptionResolver$14(&lt;generated&gt;)
      at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$fe413563$$FastClassByCGLIB$$71eb2090.invoke(&lt;generated&gt;)
      at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
      at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:286)
      at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$fe413563.handlerExceptionResolver(&lt;generated&gt;)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:606)
      at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:160)
      ... 31 more
  </code></pre>
  
  <h2><code>servlet-context.xml</code>:</h2>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
      xmlns:beans="http://www.springframework.org/schema/beans"
      xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
      xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"&gt;
  
      &lt;!-- Expose the resources folder --&gt;
      &lt;mvc:resources mapping="/resources/**" location="/resources/"/&gt;
  
      &lt;!-- Map simple view name such as "test" into /WEB-INF/test.jsp --&gt;
      &lt;bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
          &lt;property name="prefix" value="/WEB-INF/" /&gt;
          &lt;property name="suffix" value=".jsp" /&gt;
      &lt;/bean&gt;
  &lt;/beans&gt;
  </code></pre>
  
  <h2><code>AppConfig.java</code>:</h2>
  
  <pre><code>@EnableWebMvc
  @Configuration
  @ComponentScan("com.siegedog.browsergame")
  public class AppConfig extends WebMvcConfigurerAdapter {
  
  }
  </code></pre>
  
  <h2><code>PersistenceConfig.java</code>:</h2>
  
  <p>package com.siegedog.browsergame.config;</p>
  
  <pre><code>@Configuration
  @EnableTransactionManagement
  @ComponentScan({ "com.siegedog.browsergame" })
  public class PersistenceConfig {
  
      @Bean(name = "dataSource")
      public DriverManagerDataSource dataSource() {
          DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
          driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
          driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/knights");
          driverManagerDataSource.setUsername("root");
          driverManagerDataSource.setPassword("");
          return driverManagerDataSource;
      }
  
      @Bean
      public LocalSessionFactoryBean sessionFactory() {
          LocalSessionFactoryBean fb = new LocalSessionFactoryBean();
          fb.setPackagesToScan("com.siegedog.browsergame");
          fb.setDataSource(dataSource());
          fb.setHibernateProperties(hibernateProperties());
          return fb;
      }
  
      @Bean
      @Autowired
      public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
          HibernateTransactionManager txManager = new HibernateTransactionManager();
          txManager.setSessionFactory(sessionFactory);
  
          return txManager;
      }
  
      @Bean
      public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
          return new PersistenceExceptionTranslationPostProcessor();
      }
  
      Properties hibernateProperties() {
          return new Properties() {
              {
                  setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                  setProperty("hibernate.globally_quoted_identifiers", "true");
              }
          };
      }
  }
  </code></pre>
  
  <h2><code>SecurityConfig.java</code>:</h2>
  
  <pre><code>@Configuration
  @EnableWebSecurity
  @EnableGlobalMethodSecurity(prePostEnabled=true)
  public class SecurityConfig extends WebSecurityConfigurerAdapter {
  
      @Autowired
      DataSource dataSource;
  
      @Autowired
      public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
          auth.jdbcAuthentication().dataSource(dataSource)
              .usersByUsernameQuery("select name, password_hash from users where name = ?")
              .authoritiesByUsernameQuery("select name, role from users where name = ?");
      }
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http.authorizeRequests()
          .antMatchers("/dashboard").hasRole("USER")
          .anyRequest().anonymous()
          .and()
              // Generate a form login if none is explicitly provided
              .formLogin()//.failureUrl("/login?error")
              //.usernameParameter("name").passwordParameter("password_hash")
          .and()
              .logout().logoutSuccessUrl("/login?logout")
          .and()
              .exceptionHandling().accessDeniedPage("/403")
          .and()
              .csrf();
  
      }
  }
  </code></pre>
  
  <p>And, finally my DAO (pretty straightforward). </p>
  
  <h2><code>PizzaDAO.java</code>:</h2>
  
  <pre><code>import java.util.List;
  
  import org.hibernate.Session;
  import org.hibernate.SessionFactory;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Repository;
  import org.springframework.transaction.annotation.Transactional;
  
  @Repository
  @SuppressWarnings({"unchecked"})
  public class PizzaDAO {
      @Autowired private SessionFactory sessionFactory;
  
      /**
       * @Transactional annotation below will trigger Spring Hibernate
       * transaction manager to automatically create a hibernate session. 
       * See src/main/webapp/WEB-INF/servlet-context.xml
       */
      @Transactional
      public List&lt;Pizza&gt; findAll() {
          Session session = sessionFactory.getCurrentSession();
          List&lt;Pizza&gt; pizzas = session.createQuery("from Pizza").list();
          return pizzas;
      }
  
      @Transactional
      public void save(Pizza pizza) {
          Session session = sessionFactory.getCurrentSession();
          session.save(pizza);
      }
  }
  </code></pre>
  
  <h1>Edit:</h1>
  
  <p>I ended up removing all the XML configuration and replacing it with full-Java configs.
  My final config consists of <code>AppConfig.java</code>, <code>SpringMvcInitializer.java</code>, <code>SpringSecurityInitializer.java</code> and <code>WebSecurityConfig.java</code>. Here's my final, working config, in case anyone is interested:</p>
  
  <h2>AppConfig.java</h2>
  
  <pre><code>@EnableWebMvc
  @EnableTransactionManagement
  @Configuration
  @ComponentScan( {"com.siegedog.knights"} )
  public class AppConfig extends WebMvcConfigurerAdapter {
  
      @Bean(name = "dataSource")
      public DriverManagerDataSource dataSource() {
          DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
          driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
          driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/knights");
          driverManagerDataSource.setUsername("root");
          driverManagerDataSource.setPassword("");
          return driverManagerDataSource;
      }
  
      @Override
      public void addResourceHandlers(ResourceHandlerRegistry registry) {
          registry.addResourceHandler("/assets/**").addResourceLocations(
                  "classpath:/assets/");
          registry.addResourceHandler("/css/**").addResourceLocations("/css/");
          registry.addResourceHandler("/img/**").addResourceLocations("/img/");
          registry.addResourceHandler("/js/**").addResourceLocations("/js/");
      }
  
      @Bean
      public InternalResourceViewResolver viewResolver() {
          InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
          viewResolver.setViewClass(JstlView.class);
          viewResolver.setPrefix("/WEB-INF/jsp/");
          viewResolver.setSuffix(".jsp");
          return viewResolver;
      }
  
      @Bean
      public LocalSessionFactoryBean sessionFactory() {
          LocalSessionFactoryBean fb = new LocalSessionFactoryBean();
          fb.setPackagesToScan("com.siegedog.knights");
          fb.setDataSource(dataSource());
          fb.setHibernateProperties(hibernateProperties());
          return fb;
      }
  
      @Bean
      @Autowired
      public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
          HibernateTransactionManager txManager = new HibernateTransactionManager();
          txManager.setSessionFactory(sessionFactory);
          return txManager;
      }
  
      Properties hibernateProperties() {
          return new Properties() {
              {
                  setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                  setProperty("hibernate.globally_quoted_identifiers", "true");
              }
          };
      }
  }
  </code></pre>
  
  <h2>SpringMvcInitializer.java</h2>
  
  <pre><code>public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
  
      @Override
      protected Class&lt;?&gt;[] getRootConfigClasses() {
          return new Class[] { AppConfig.class };
      }
  
      @Override
      protected Class&lt;?&gt;[] getServletConfigClasses() {
          return null;
      }
  
      @Override
      protected String[] getServletMappings() {
          return new String[] { "/" };
      }
  
  }
  </code></pre>
  
  <h2>SpringSecurityInitializer.java (see comment)</h2>
  
  <pre><code>/** Required to inject the proper security filter. */
  public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
  
  }
  </code></pre>
  
  <h2>WebSecurityConfig.java</h2>
  
  <p>This code simply sets the proper rout authentication rules. It also uses the dataSource defined in <code>AppConfig.java</code> to authenticate users who are registered.</p>
  
  <pre><code>@Configuration
  @EnableWebMvcSecurity
  public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
      @Autowired
      DataSource dataSource;
  
      /**
       * Important: csrf prevention is on by default.
       */
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http
              .authorizeRequests()
                  .antMatchers("/dashboard").hasRole("USER")
                  .antMatchers("/forest").hasRole("USER")
                  .antMatchers("/arena").hasRole("USER")
                  .antMatchers("/store").hasRole("USER")
                  .anyRequest().permitAll();
  
          http
              .formLogin().loginPage("/login").failureUrl("/login?error").defaultSuccessUrl("/dashboard")
              .permitAll()
          .and()
              .logout()
              .permitAll()
          .and()
              .exceptionHandling().accessDeniedPage("/403");
      }
  
      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth.jdbcAuthentication().dataSource(dataSource)
              .usersByUsernameQuery("select name, password_hash, enabled from users where name=?")
              // Hash passwords with sha-256
              .passwordEncoder(new ShaPasswordEncoder(256))
              .authoritiesByUsernameQuery("select name, role from users where name=?");
      }
  }
  </code></pre>