Open source Java projects: Spring Data

Use common Spring queries to access multiple NoSQL data stores

1 2 3 4 5 Page 3
Page 3 of 5
  • Two domain classes, User and Address
  • Two corresponding repositories, UserRepository and AddressRepository
  • A service, UserService, and its implementation, UserServiceImpl
  • A JUnit test case to exercise and test the service

Note that in order to run the unit test (which might better be called an integration test since it is talking directly to the database) you'll need to install and run MongoDB on your local machine, listening on the standard 27017 port.

Project POM

Listing 8 shows the Maven POM file for the project.

Listing 8. POM.xml for the Spring Data demo




<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.geekcap.javaworld</groupId>
  <artifactId>spring-data-example</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>spring-data-example</name>
  <url>http://maven.apache.org</url>

    <properties>
        <spring.version>3.2.1.RELEASE</spring.version>
        <spring.data.mongodb.version>1.2.0.RELEASE</spring.data.mongodb.version>
        <java.version>1.6</java.version>
        <querydsl.version>2.9.0</querydsl.version>
    </properties>

  <dependencies>

      <!-- Spring -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>${spring.version}</version>
          <exclusions>
              <exclusion>
                  <groupId>commons-logging</groupId>
                  <artifactId>commons-logging</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-beans</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>${spring.version}</version>
      </dependency>

      <!-- Spring & Spring Data MongoDB -->
      <dependency>
          <groupId>org.springframework.data</groupId>
          <artifactId>spring-data-mongodb</artifactId>
          <version>${spring.data.mongodb.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-expression</artifactId>
          <version>${spring.version}</version>
      </dependency>

      <!-- Querydsl -->
      <dependency>
          <groupId>com.mysema.querydsl</groupId>
          <artifactId>querydsl-mongodb</artifactId>
          <version>${querydsl.version}</version>
      </dependency>

      <!-- Test -->
      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>${spring.version}</version>
          <scope>test</scope>
      </dependency>

  </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.0.8</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources</outputDirectory>
                            <processor>org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

The POM in Listing 8 imports the core Spring classes, Spring Data, Spring Data's support for MongoDB, and QueryDSL, among other things. Be sure to notice the com.mysema.maven plug-in. This plug-in generates the QueryDSS classes previously described.

Execute the following command to build the project:

mvn clean install

Application context file

Next, look at the applicationContext.xml file in Listing 9.

Listing 9. applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:mongo="http://www.springframework.org/schema/data/mongo"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:oxm="http://www.springframework.org/schema/oxm"
       xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
                           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd">


    <!-- Component scan to find all Spring components -->
    <context:component-scan base-package="com.geekcap.javaworld.springdata" />

    <!-- Load Spring Data Mongo Support -->
    <mongo:db-factory id="mongoDbFactory" dbname="SpringDataExample" host="localhost" port="27017"/>

    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg ref="mongoDbFactory" />
        <property name="writeConcern" value="SAFE" />
    </bean>

    <!-- Ask Spring Data to scan our domain objects -->
    <mongo:mapping-converter id="mongoConverter" base-package="com.geekcap.javaworld.springdata.model" />

    <!-- Ask Spring Data to scan our repositories -->
    <mongo:repositories base-package="com.geekcap.javaworld.springdata.repository" />

</beans>

The applicationContext.xml file runs a basic component scan to find the requested Spring components. It will search for annotated services, components, repositories, and so on. It then builds a MongoTemplate, wiring in a MongoDB Factory. Next, it uses the mongo:mapping-converter to scan the domain objects, which are annotated with the MongoDB @Document annotation. Finally, it uses the mongo:repositories to scan the repositories, enabling Spring Data to create implementations of the repository interfaces.

With these directives defined, the application context (a bean factory) contains implementations of the Spring Data repository interfaces for our domain objects.

Extending UserRepository

The domain objects that we defined back in Listings 3 and 4, and the AddressRepository from Listing 6 will remain the same for this demo. In Listing 10 I've updated UserRepository (from Listing 7) with support for QueryDSL.

Listing 10. UserRepository.java extended for QueryDSL

package com.geekcap.javaworld.springdata.repository;

import com.geekcap.javaworld.springdata.model.User;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;

import java.util.List;

/**
 * Spring Data Repository for managing users
 */
public interface UserRepository  extends PagingAndSortingRepository<User,String>, QueryDslPredicateExecutor<User>
{
    public User findByEmailAddress( String emailAddress );
    public List<User> findByLastName( String lastName );

    @Query( "{ age: { \"$gte\" : ?0 } }")
    public List<User> findByAgeOver( int age );

    @Query( "{ age: { \"$gte\" : ?0, \"$lte\" : ?1 } }")
    public List<User> findByAgeBetween( int lower, int upper );
}   

Listing 10 adds support for the QueryDslPredicateExecutor and shows a couple of MongoDB aggregate query examples using the @Query annotation.

A query service

Listings 11 and 12 show the source code for the demo's UserService and UserServiceImpl, respectively.

Listing 11. UserService.java

package com.geekcap.javaworld.springdata.service;

import com.geekcap.javaworld.springdata.model.User;

import java.util.List;

/**
 * Defines operations that can be performed on a User
 */
public interface UserService
{
    public enum SortOrder {
        ASCENDING, DESCENDING
    }

    public void addUser( User user );
    public User getUser( String id );
    public User findUserByEmailAddress( String emailAddress );
    public List<User> findUsersByLastName( String lastName );
    public List<User> findUsers();
    public List<User> findUsers( int pageNumber, int pageSize );
    public List<User> findUsersSortByAge( SortOrder sortOrder );
    public List<User> findUsersByAgeOver( int age );
    public List<User> findUsersWithAgeBetween( int lower, int upper );
    public List<User> findByLastNameOverAge( String lastName, int age );
    public void removeUser( String id );
}
1 2 3 4 5 Page 3
Page 3 of 5