Category Archives: Spring Framework

Post on Spring J2EE technology (spring, spring-mvc, spring-flow, …)

A Custom @AutoConfigure to provide a bean (Spring BeanPostProcessor likewise) for Unit testing dependent classes

This article is to show u how to implement your own bean factory on a unit tests (BeanPostProcess like wise) using @AutoConfigure features of _Spring (Boot)_.

Context

I had this need when I tried to implement a Unit test for a Custom repository class (using Spring Boot) that implements some logic, and is dependent on _EntityManager_.


@Repository
public class CustomRepository {
    @EntityManager
    entityManager;

    public AnyOutput any(AnyInput input) {
      // logic implementation
    }
}

I could, of course, _Mock_ the _EntityManager_ … but I needed something that validates the queries that were built dynamically from input parameters.

Why I did not use @DataJpaTest

Simply because this latter is made for Integration tests, launching a micro container and trying to deploy and validate all repository classes I have in my project! My need was a Unit test for my `CustomRepository`, not else.

Implementation details

  1. The in memory engine bean factory:
  2. For that, I’ve chosen to use HSQLDB in memory database as a persistent engine providing the following bean factory

    
    @Configuration
    public class HSQLDBEntityManagerConfiguration {
    
      @ConditionalOnMissingBean
      @Bean
      public EntityManager entityManager(@Autowired @Qualifier("test-entities") Collection<Class<?>> entities) {
        org.hibernate.cfg.Configuration configuration = new org.hibernate.cfg.Configuration();
        entities.forEach(aClass -> configuration.addAnnotatedClass(aClass));
        configuration.setProperty("hibernate.connection.driver_class", org.hsqldb.jdbcDriver.class.getName())
          .setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:testdb")
          .setProperty("hibernate.connection.username", "sa")
          .setProperty("hibernate.connection.password", "")
          .setProperty("hibernate.dialect", org.hibernate.dialect.HSQLDialect.class.getName())
          .setProperty("hibernate.hbm2ddl.auto", "update")
          .setProperty("hibernate.show_sql", "true")
          .configure();
    
        SessionFactory sessionFactory = configuration.buildSessionFactory(
          new StandardServiceRegistryBuilder()
            .applySettings(configuration.getProperties())
            .build()
        );
        Session session = sessionFactory.openSession();
        Runtime.getRuntime().addShutdownHook(new Thread(sessionFactory::close));
        EntityManagerFactory entityManagerFactory = session.getEntityManagerFactory();
        EntityManager entityManager = entityManagerFactory.createEntityManager();
    
        return (EntityManager) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{EntityManager.class}, (proxy, method, args) -> {
    
          if (! method.getName().equalsIgnoreCase("close")) {
            entityManager.getTransaction().begin();
          }
          Object invoke = method.invoke(entityManager, args);
          if (! method.getName().equalsIgnoreCase("close")) {
            entityManager.getTransaction().commit();
          }
    
          return invoke;
        });
      }
    }
    
    

    The `@Qualifier(“test-entities”) Collection<Class> entities` here are needed for an annotated based Hibernate session factory configuration. This is expected to be provided in the Spring registry at runtime as we will see later.

    This is of course an example detail, … your bean factory could me much simpler!

  3. The Spring-Boot likewise auto-configuration
  4. 
        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.TYPE)
        @ImportAutoConfiguration(HSQLDBEntityManagerConfiguration.class)
        public @interface AutoConfigureEntityManagerHSQLDB {
        }
    
    
  5. Usage example of the above in a Unit test
  6. 
    @RunWith(SpringRunner.class)
    @AutoConfigureEntityManagerHSQLDB // this what makes the in-memory entity manager available for DI
    @Import(DuplicateRepositoryTest.Config.class)
    public class CustomRepositoryTest {
    
        @Autowired
        CustomRepository duplicateRepository;
    
        @Autowired
        EntityManager entityManager;
    
        @Before
        public void init() {
            // test context and data setup 
            SubEntity subEntity = new SubEntity();
            subEntity.setName("sub_entity");
    
            TestEntity entity = new TestEntity();
            entity.setName("test_entity");
            entity.setSubEntity(subEntity);
    
            entityManager.persist(entity);
        }
    
        @Test
        public void onDuplicateShouldReturnTrue() {        
            // test logic implementation and assertions
        }
    
        @Configuration
        @Import(CustomRepository.class)
        static class Config {
    
            // these are the entities configured for the annotation based session factory initialisation
            // TestEntity and SubEntity are marked with JPA annotations (@Entity, ... etc)
            @Bean
            @Qualifier("test-entities")
            Collection<Class<?>> getEntities() {
                return Arrays.asList(TestEntity.class, SubEntity.class);
            }
        }
    }
    
    
Advertisements

SpringSecurity – RememberMe Authentication & Basic Authentication

Preface

In Spring Security, you can enable RememberMe Authentication for persistent login. This is achieved via the exchange of a RememberMe cookie between server and client. The configuration presented here shows how this can be accomplished using the Spring Security “form-login” (or equivalent). Shortly, in order to ask for the RememberMe cookie/mechanism from the server, the client must post the parameter “_spring_security_remember_me” along with the login credentials; the RememberMe authentication mechanism is thus tightly related to that parameter and thus to a login form.

In a recent project (a webservices project), I had to establish a persistent login along with a Basic authentication across multiple platforms using the Remember Me cookie approach using Spring Security. The difficulty is to configure Spring Security to send back to client the Remember Me cookie on successful authentication with Basic Authentication credentials (no login form and thus no request parameter “_spring_security_remember_me”).

Here the configuration that allows you to achieved this.

The Basic Authentication entry point configuration

You have to (re-)declare the Basic Authentication entry point and filter:

<http auto-config="false" entry-point-ref="basicAuthenticationEntryPoint">
   <intercept-url pattern="/**" access="ROLE_USER" />
   <remember-me key="mykey" services-ref="rememberMeServices" />
   <custom-filter position="BASIC_AUTH_FILTER" ref="basicAuthenticationFilter" />
</http>

<beans:bean id="basicAuthenticationFilter"
   class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
	<beans:property name="rememberMeServices" ref="rememberMeServices" />
	<beans:property name="authenticationManager" ref="authenticationManager" />
	<beans:property name="authenticationEntryPoint" ref="basicAuthenticationEntryPoint" />
</beans:bean>

<beans:bean id="basicAuthenticationEntryPoint"
   class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
	<beans:property name="realmName" value="Webservices" />
</beans:bean>

This XML configuration comes in replacement to the following classical configuration:

<http auto-config="true">
   <intercept-url pattern="/**" access="ROLE_USER" />
   <remember-me key="mykey" services-ref="rememberMeServices" />
   <basic-auth />
</http>

In the first configuration above, we disabled the form login (remember that it is a webservices project where authentication is done via Basic Authentication). In order to enable the Remember Me authentication along with that Basic authentication on successful login, we had to:

  1. Disable any default login form and http-basic configuration through the “http” attribute
    auto-config="false"
  2. Define an entry point (there must be at least one) through the “http” attribute
    entry-point-ref="basicAuthenticationEntryPoint"

    This is the entry point Spring loads when using “http-basic”

  3. Define the Basic Authentication filter
    <custom-filter position="BASIC_AUTH_FILTER" ref="basicAuthenticationFilter" />

    This again is the default filter Spring loads when using “http-basic” with the difference here that we are referencing the Remember me service bean to support remember on successful authentication

The rest of the configuration file (download file here) is no more that classical Spring Security Remember Me authentication configuration.

This was tested with Spring Security 3.0.x and 4.x.

Spring MVC 3.1 and Apache Tiles 2 maven archetype

Find in this post a Maven archetype for a Spring MVC 3.1 and Apache tiles 2.
The generated application is maven-based web application (.war) where the dependencies are all configured and set:

  • servlet-api 2.5
  • Apache tiles 2.2
  • Spring MVC 3.1
  • jstl 1.2
  • Java 1.6 version (this is not a constraint, I think you could downgrade the version to 1.5 without difficulties)

The application is ready to deploy on a web application server (tested on Apache tomcat 6.x and higher).

Installing and using the archetype

  1. Download the archetype from this link
  2. Install the downloaded archetype to your local repository using the following command (sorry it is not yet available from the Maven central)
    mvn install:install-file -Dfile=springmvc3.1-archetype-1.0.1.jar -DgroupId=com.michir.projects -DartifactId=springmvc3.1-archetype -Dversion=1.0.1 -Dpackaging=jar -DgeneratePom=true [-DlocalRepositoryPath=[path to your local repository]]
    
  3. Once installed on your local repository, generate a new web project using the following maven command
    mvn archetype:generate -DarchetypeGroupId=com.michir.projects -DarchetypeArtifactId=springmvc3.1-archetype -DarchetypeVersion=1.0.1 -DgroupId=com.mycompany -DartifactId=myproject -Dversion=1.0.0-SNAPSHOT
    

A new (Maven) web project is generated under the “myproject” folder (your artifactId from the maven command line). The projects comes with:

  • A spring configuration file under src/main/webapp/WEB-INF/spring-servlet.xml with an Apache tiles 2 configuration, pointing to tiles.xml tiles configuration file (see Spring MVC documentation for more View Resolvers).
  • The web application is configured (see web.xml) to map the Spring Dispatcher Servlet to *.html
  • The spring framework will scan the package com.mycompany (your groupId from the maven command line) for spring annotated controllers, see the “context:component-scan” tag in spring-servlet.xml file
  • The application comes with Page1Controller.java in the package “com.mycompany” spring controller (as an example) that maps page1.html, it is redirected to the page1.jsp view under src/main/webapp/WEB-INF/jsp/

Adding a new controller, a new view to the project

If your are not used with Spring MVC framework and Apache tiles, adding a new component may seem tedious. Here are the steps to achieve that (base on the above installation and configuration):

  1. Create a new Spring @Controller, say MayController.java in the package “com.mycompany” that maps, say “page2.html”
    package com.mycompany;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    @Controller
    public class MyController {
    	@RequestMapping("/page2.*")
    	public String redirect() {
    		return "page2";
    	}
    }
    
  2. Create a “page2.jsp” file in “WEB-INF/jsp” folder, along with “page1.jsp”:
    <!-- to use spring jsp tags -->
    <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
    <html>
      <head>
        <title>Page 2</title>
      </head>
      <body>
        <h2>Page 2</h2>
      </body>
    </html>
    
  3. Add the “page2.jsp” definition to the “tiles.xml” file:

    ...
    <definition name="page2" extends="base.definition">
       <put-attribute name="title" value="Page 2" />
       <put-attribute name="body" value="/WEB-INF/jsp/page2.jsp" />
    </definition>
    ...
    

It is done, you can now compile/build your application, deploy on a web server and test it (oh … perhaps one last thing, add a link to your newly added page in menu.jsp along with the “page1” link like this:

   <a href="page1.html">Page 1</a><br />
   <a href="page2.html">Page 2</a><br />

Enjoy!

a Spring MVC template package (Spring 2.5, Maven 2)

Description

Spring MVC is a powerful MVC framework (Model-View-Controller) for web applications development.

Find here a template package (using Maven 2) thats configures a very simple and basic hello world web application based on Spring MVC  (2.5). This can be a starting point for a more complete web application using this framework.

Template Application architecture here.

Downloads: A light package that includes no libraries can be downloaded here.

Important notes

– This template was tested under Apache Tomcat 6.

– The “javax.servlet:servlet-api” is included as a provided dependency, since it is already embedded in the Tomcat 6 distribution.

Keywords: Spring MVC 2.5, Maven 2, Tomcat, Java J2EE