Spring Data + Hazelcast + Querydsl demo

This post introduces demo code of Spring Data Hazelcast with simple Apache Maven configuration.


So, let’s start with the pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<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.denismigol.example</groupId>
    <artifactId>spring-data-hazelcast-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <querydsl.version>4.1.3</querydsl.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.hazelcast</groupId>
            <artifactId>spring-data-hazelcast</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-core</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-collections</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.1.3</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources</outputDirectory>
                            <processor>com.querydsl.apt.QuerydslAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>com.querydsl</groupId>
                        <artifactId>querydsl-apt</artifactId>
                        <version>${querydsl.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>

In this POM we have:

  • Spring Data Hazelcast and Querydsl dependencies;
  • configured Querydsl APT Maven plugin with Querydsl APT dependency.

Then, initialize Hazelcast-related Spring beans in JavaConfig (AppConfig.java):

package com.denismigol.example;

import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.hazelcast.HazelcastKeyValueAdapter;
import org.springframework.data.hazelcast.repository.config.EnableHazelcastRepositories;
import org.springframework.data.keyvalue.core.KeyValueOperations;
import org.springframework.data.keyvalue.core.KeyValueTemplate;

/**
 * @author Denis Migol
 */
@Configuration
@EnableHazelcastRepositories("com.denismigol.example")
public class AppConfig {
    @Bean
    HazelcastInstance hazelcastInstance() {
        return Hazelcast.newHazelcastInstance();
    }

    @Bean
    public KeyValueOperations keyValueTemplate() {
        return new KeyValueTemplate(new HazelcastKeyValueAdapter(hazelcastInstance()));
    }

    @Bean
    public HazelcastKeyValueAdapter hazelcastKeyValueAdapter(HazelcastInstance hazelcastInstance) {
        return new HazelcastKeyValueAdapter(hazelcastInstance);
    }
}

After that, create an entity (City.java):

package com.denismigol.example;

import com.querydsl.core.annotations.QueryEntity;
import org.springframework.data.annotation.Id;

import java.io.Serializable;

/**
 * @author Denis Migol
 */
@QueryEntity
public class City implements Serializable {
    @Id
    private String name;
    private String country;

    public String getName() {
        return name;
    }

    public City setName(String name) {
        this.name = name;
        return this;
    }

    public String getCountry() {
        return country;
    }

    public City setCountry(String country) {
        this.country = country;
        return this;
    }

    @Override
    public String toString() {
        return new StringBuilder()
                .append("\"")
                .append(name)
                .append(", ")
                .append(country)
                .append("\"")
                .toString();
    }
}

Note – entity must:

  • implement java.io.Serializable;
  • has primary key member (which holds org.springframework.data.annotation.Id annotation). Otherwise, java.lang.NullPointerException will be thrown at org.springframework.data.repository.core.support.PersistentEntityInformation.getIdType.

Also, entity must hold com.querydsl.core.annotations.QueryEntity annotation to be processed by Querydsl APT Maven plugin.

And, of course, define repository for the entity (CityRepository.java):

package com.denismigol.example;

import org.springframework.data.hazelcast.repository.HazelcastRepository;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;

/**
 * @author Denis Migol
 */
public interface CityRepository extends HazelcastRepository<City, String>, QueryDslPredicateExecutor<City> {
}

Finally, run demo code (Main.java):

package com.denismigol.example;

import com.hazelcast.core.HazelcastInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;

/**
 * @author Denis Migol
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        CityRepository cityRepository = context.getBean(CityRepository.class);

        cityRepository.save(Arrays.asList(
                new City().setCountry("US").setName("New York"),
                new City().setCountry("UK").setName("London"),
                new City().setCountry("FR").setName("Paris"),
                new City().setCountry("US").setName("San Francisco")
        ));

        System.out.println(cityRepository.findAll());
        System.out.println(cityRepository.findAll(QCity.city.country.eq("US"), QCity.city.name.asc()));

        context.getBean(HazelcastInstance.class).shutdown();
    }
}

By calling cityRepository.findAll(QCity.city.country.eq("US"), QCity.city.name.asc()) client code expects all cities from proper country (US) sorted ascendingly by name (alphabetically).

Output:

["San Francisco, US", "New York, US", "Paris, FR", "London, UK"]
["New York, US", "San Francisco, US"]

References