├── .gitignore ├── .travis.yml ├── 01-intro ├── pom.xml └── src │ ├── main │ └── java │ │ └── example │ │ ├── Customer.java │ │ └── CustomerRepository.java │ └── test │ └── java │ └── example │ └── ApplicationIntegrationTests.java ├── 02-bom ├── README.adoc ├── build.gradle └── pom.xml ├── 03-java8 ├── pom.xml └── src │ ├── main │ ├── java │ │ └── example │ │ │ └── springdata │ │ │ └── jpa │ │ │ └── java8 │ │ │ ├── Customer.java │ │ │ └── CustomerRepository.java │ └── resources │ │ └── META-INF │ │ └── orm.xml │ └── test │ └── java │ └── example │ └── springdata │ └── jpa │ └── java8 │ └── Java8IntegrationTests.java ├── 04-custom-repository ├── pom.xml └── src │ ├── main │ ├── java │ │ └── example │ │ │ ├── CustomBaseRepository.java │ │ │ ├── Customer.java │ │ │ └── CustomerRepository.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── example │ └── ApplicationIntegrationTests.java ├── 05-web-projection ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── example │ │ │ ├── Application.java │ │ │ ├── Password.java │ │ │ ├── User.java │ │ │ ├── UserManagement.java │ │ │ ├── UserRepository.java │ │ │ ├── Username.java │ │ │ └── web │ │ │ └── UserController.java │ └── resources │ │ ├── messages.properties │ │ ├── static │ │ └── css │ │ │ └── style.css │ │ └── templates │ │ └── users.html │ └── test │ └── java │ └── example │ ├── AbstractIntegrationTests.java │ ├── UserManagementIntegrationTests.java │ └── UserRepositoryIntegrationTests.java ├── 06-querydsl-web ├── pom.xml └── src │ └── main │ ├── java │ └── example │ │ ├── Application.java │ │ ├── User.java │ │ ├── UserInitializer.java │ │ ├── UserRepository.java │ │ └── web │ │ └── UserController.java │ └── resources │ ├── application.properties │ ├── randomuser.me.csv │ └── templates │ └── index.html ├── 07-jpa-entity-graph ├── pom.xml └── src │ ├── main │ ├── java │ │ └── example │ │ │ ├── fetchgraph │ │ │ ├── Product.java │ │ │ ├── ProductRepository.java │ │ │ └── Tag.java │ │ │ └── storedprocedures │ │ │ ├── User.java │ │ │ └── UserRepository.java │ └── resources │ │ ├── application.properties │ │ └── schema.sql │ └── test │ └── java │ └── example │ ├── fetchgraph │ └── FetchGraphIntegrationTests.java │ └── storedprocedures │ └── UserRepositoryIntegrationTests.java ├── 08-mongodb-security ├── pom.xml └── src │ ├── main │ └── java │ │ └── example │ │ ├── Person.java │ │ └── PersonRepository.java │ └── test │ └── java │ └── example │ └── PersonRepositoryIntegrationTest.java ├── 09-mongodb-java8 ├── pom.xml └── src │ ├── main │ └── java │ │ └── example │ │ ├── Person.java │ │ └── PersonRepository.java │ └── test │ └── java │ └── example │ └── PersonRepositoryIntegrationTest.java ├── 10-rest-headers ├── README.adoc ├── pom.xml └── src │ ├── main │ └── java │ │ └── example │ │ ├── Address.java │ │ ├── Application.java │ │ ├── Customer.java │ │ └── CustomerRepository.java │ └── test │ ├── java │ └── example │ │ ├── ApplicationIntegrationTests.java │ │ └── WebIntegrationTests.java │ └── resources │ └── documentation.properties ├── 11-rest-hal-browser ├── pom.xml ├── src │ ├── main │ │ ├── java │ │ │ └── example │ │ │ │ ├── Address.java │ │ │ │ ├── Application.java │ │ │ │ ├── Store.java │ │ │ │ ├── StoreInitializer.java │ │ │ │ ├── StoreRepository.java │ │ │ │ ├── WebConfig.java │ │ │ │ └── web │ │ │ │ └── StoresController.java │ │ └── resources │ │ │ ├── application.properties │ │ │ ├── starbucks.csv │ │ │ ├── static │ │ │ └── img │ │ │ │ └── map.png │ │ │ └── templates │ │ │ └── index.html │ └── test │ │ └── java │ │ └── example │ │ ├── StarbucksClient.java │ │ └── StoreRepositoryIntegrationTests.java └── webui.png ├── 12-redis ├── .gitignore ├── pom.xml └── src │ ├── main │ └── java │ │ └── example │ │ └── Vehicle.java │ └── test │ └── java │ └── example │ ├── ObjectSerializationTests.java │ ├── RedisOperationsTests.java │ └── RedisTestConfiguration.java ├── 13-key-value ├── pom.xml └── src │ ├── main │ └── java │ │ └── example │ │ ├── Person.java │ │ └── PersonRepository.java │ └── test │ └── java │ └── example │ └── PersonRepositoryIntegrationTest.java ├── 14-redis-repositories ├── .gitignore ├── pom.xml └── src │ ├── main │ └── java │ │ └── example │ │ ├── City.java │ │ ├── Person.java │ │ └── PersonRepository.java │ └── test │ └── java │ └── example │ ├── EmbeddedRedisRule.java │ ├── RedisRepositoryTests.java │ └── RedisTestConfiguration.java ├── LICENSE ├── pom.xml └── readme.adoc /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .classpath 3 | .springBeans 4 | .settings/ 5 | target/ 6 | 7 | #IntelliJ Stuff 8 | .idea 9 | *.iml 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - oraclejdk8 5 | 6 | cache: 7 | directories: 8 | - $HOME/.m2 9 | - $HOME/.embedmongo 10 | 11 | sudo: false 12 | 13 | install: true 14 | 15 | script: "mvn clean dependency:list test -Dsort" 16 | -------------------------------------------------------------------------------- /01-intro/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | com.springone2gx.2015 7 | whats-new-in-spring-data 8 | 1.0.0.BUILD-SNAPSHOT 9 | ../pom.xml 10 | 11 | 12 | spring-data-intro 13 | What's new in Spring Data? - Intro 14 | 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-data-jpa 20 | 21 | 22 | 23 | org.hsqldb 24 | hsqldb 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /01-intro/src/main/java/example/Customer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.AccessLevel; 19 | import lombok.EqualsAndHashCode; 20 | import lombok.Getter; 21 | import lombok.NoArgsConstructor; 22 | import lombok.RequiredArgsConstructor; 23 | import lombok.ToString; 24 | 25 | import javax.persistence.Entity; 26 | import javax.persistence.GeneratedValue; 27 | import javax.persistence.Id; 28 | 29 | /** 30 | * @author Oliver Gierke 31 | * @author Thomas Darimont 32 | */ 33 | @Entity 34 | @Getter 35 | @EqualsAndHashCode 36 | @ToString 37 | @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) 38 | @RequiredArgsConstructor 39 | public class Customer { 40 | 41 | private @Id @GeneratedValue Long id; 42 | private final String firstname, lastname; 43 | private final String email; 44 | } 45 | -------------------------------------------------------------------------------- /01-intro/src/main/java/example/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import java.util.List; 19 | import java.util.Optional; 20 | 21 | import org.springframework.data.domain.Page; 22 | import org.springframework.data.domain.Pageable; 23 | import org.springframework.data.repository.CrudRepository; 24 | 25 | /** 26 | * Repository to manage {@link Customer} instances. 27 | * 28 | * @author Oliver Gierke 29 | * @author Thomas Darimont 30 | */ 31 | interface CustomerRepository extends CrudRepository { 32 | 33 | Optional findByEmail(String email); 34 | 35 | List findByFirstnameContaining(String firstname); 36 | 37 | Page findByLastnameStartsWith(String lastname, Pageable pageable); 38 | } 39 | -------------------------------------------------------------------------------- /01-intro/src/test/java/example/ApplicationIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.hamcrest.Matchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import example.Customer; 22 | import example.CustomerRepository; 23 | 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | import org.springframework.beans.factory.annotation.Autowired; 27 | import org.springframework.boot.autoconfigure.SpringBootApplication; 28 | import org.springframework.boot.test.SpringApplicationConfiguration; 29 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 30 | import org.springframework.transaction.annotation.Transactional; 31 | 32 | /** 33 | * Integration test to show the usage of Java 8 date time APIs with Spring Data JPA auditing. 34 | * 35 | * @author Oliver Gierke 36 | * @author Thomas Darimont 37 | */ 38 | @RunWith(SpringJUnit4ClassRunner.class) 39 | @SpringApplicationConfiguration 40 | @Transactional 41 | public class ApplicationIntegrationTests { 42 | 43 | @SpringBootApplication 44 | static class Config {} 45 | 46 | @Autowired CustomerRepository repository; 47 | 48 | @Test 49 | public void providesFindOneWithOptional() { 50 | 51 | Customer carter = repository.save(new Customer("Carter", "Beauford", "carter@dmband.com")); 52 | 53 | assertThat(repository.findOne(carter.getId()), is(notNullValue())); 54 | assertThat(repository.findOne(carter.getId() + 4711), is(nullValue())); 55 | } 56 | 57 | // TODO: Tests for finders 58 | } 59 | -------------------------------------------------------------------------------- /02-bom/README.adoc: -------------------------------------------------------------------------------- 1 | = Spring Data - Release Train BOM example 2 | 3 | This project shows the usage of the Spring Data release train in a non-Spring-Boot project with both Maven and Gradle. 4 | 5 | == Properties 6 | 7 | In both Maven and Gradle a couple of properties are used to define the versions of Spring Framework and Spring Data to use. For Spring Framework a plain version is used. For Spring Data we refer to a particular revision of a release train. The naming of Spring Data releases uses the following conventions: 8 | 9 | ** `${release-train}-M1` -> Milestones 10 | ** … 11 | ** `${release-train}-RC1` -> Release candidate 12 | ** … 13 | ** `${release-train}-RELEASE` -> GA version 14 | ** `${release-train}-SR1` -> Services release (bugfixes) for that release train 15 | 16 | == Maven 17 | 18 | The `` section declares dependencies to the BOMs for both Spring and Spring Data, using the `import` scope and `pom` type. 19 | 20 | The standard `` section can now list Spring Framework and Spring Data dependencies without declaring a version and still be sure all libraries are in matching versions. 21 | 22 | Note, that we don't declare a Spring Framework dependency here. The import of the Spring Framework BOM nonetheless makes sure we control the version of all transitive Spring Framework dependencies pulled in by the Spring Data modules. 23 | 24 | == Gradle 25 | 26 | Gradle does not support Maven BOMs out of the box so the first thing to do is to declare a buildscript dependency on the https://github.com/spring-gradle-plugins/dependency-management-plugin[dependency management plugin] and apply it to the project. 27 | 28 | With the plugin applied, the `dependencyManagement` section can be used to import the Spring Framework and Spring Data BOMs. 29 | 30 | The standard `dependencies` section can now list Spring and Spring Data dependencies without declaring a version and still be sure all libraries are in matching versions. 31 | 32 | Note, that we don't declare a Spring Framework dependency here. The dependency management plugin and Spring Framework BOM nonetheless makes sure we control the version of all transitive Spring Framework dependencies pulled in by the Spring Data modules. 33 | -------------------------------------------------------------------------------- /02-bom/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'io.spring.gradle:dependency-management-plugin:0.5.0.RELEASE' 7 | } 8 | } 9 | 10 | apply plugin: 'io.spring.dependency-management' 11 | apply plugin: 'java' 12 | 13 | ext { 14 | springVersion = '4.1.6.RELEASE' 15 | springDataVersion = 'Fowler-RELEASE' 16 | } 17 | 18 | repositories { 19 | jcenter() 20 | } 21 | 22 | dependencyManagement { 23 | imports { 24 | mavenBom "org.springframework:spring-framework-bom:${springVersion}" 25 | mavenBom "org.springframework.data:spring-data-releasetrain:${springDataVersion}" 26 | } 27 | } 28 | 29 | dependencies { 30 | compile 'org.springframework.data:spring-data-rest-webmvc' 31 | compile 'org.springframework.data:spring-data-mongodb' 32 | } 33 | -------------------------------------------------------------------------------- /02-bom/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.springone.2015 6 | spring-data-bom 7 | 1.0.0.BUILD-SNAPSHOT 8 | 9 | What's new in Spring Data? - BOM 10 | 11 | 12 | 4.2.1.RELEASE 13 | 14 | 15 | Fowler-SR2 16 | 17 | 18 | 19 | 20 | 21 | 22 | org.springframework 23 | spring-framework-bom 24 | ${spring.version} 25 | import 26 | pom 27 | 28 | 29 | 30 | org.springframework.data 31 | spring-data-releasetrain 32 | ${spring-data.version} 33 | import 34 | pom 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.springframework.data 45 | spring-data-rest-webmvc 46 | 47 | 48 | 49 | org.springframework.data 50 | spring-data-mongodb 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /03-java8/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | com.springone2gx.2015 7 | whats-new-in-spring-data 8 | 1.0.0.BUILD-SNAPSHOT 9 | ../pom.xml 10 | 11 | 12 | spring-data-java8 13 | What's new in Spring Data? - Java 8 14 | 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-data-jpa 20 | 21 | 22 | 23 | org.hsqldb 24 | hsqldb 25 | runtime 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /03-java8/src/main/java/example/springdata/jpa/java8/Customer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.springdata.jpa.java8; 17 | 18 | import lombok.AccessLevel; 19 | import lombok.Getter; 20 | import lombok.NoArgsConstructor; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.ToString; 23 | 24 | import java.time.LocalDateTime; 25 | 26 | import javax.persistence.Entity; 27 | import javax.persistence.GeneratedValue; 28 | import javax.persistence.Id; 29 | 30 | import org.springframework.data.annotation.CreatedDate; 31 | import org.springframework.data.annotation.LastModifiedDate; 32 | 33 | /** 34 | * @author Oliver Gierke 35 | * @author Thomas Darimont 36 | */ 37 | @Entity 38 | @Getter 39 | @ToString 40 | @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) 41 | @RequiredArgsConstructor 42 | public class Customer { 43 | 44 | // TODO: 01 - Support for non-time-zoned JSR-310 types 45 | 46 | private @Id @GeneratedValue Long id; 47 | private @CreatedDate LocalDateTime createdDate; 48 | private @LastModifiedDate LocalDateTime modifiedDate; 49 | 50 | private final String firstname, lastname; 51 | } 52 | -------------------------------------------------------------------------------- /03-java8/src/main/java/example/springdata/jpa/java8/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.springdata.jpa.java8; 17 | 18 | import java.util.List; 19 | import java.util.Optional; 20 | import java.util.concurrent.CompletableFuture; 21 | import java.util.stream.Stream; 22 | 23 | import org.springframework.data.jpa.repository.Query; 24 | import org.springframework.data.repository.CrudRepository; 25 | import org.springframework.data.repository.Repository; 26 | import org.springframework.scheduling.annotation.Async; 27 | 28 | /** 29 | * Repository to manage {@link Customer} instances. 30 | * 31 | * @author Oliver Gierke 32 | * @author Thomas Darimont 33 | */ 34 | public interface CustomerRepository extends Repository { 35 | 36 | /** 37 | * Special customization of {@link CrudRepository#findOne(java.io.Serializable)} to return a JDK 8 {@link Optional}. 38 | * 39 | * @param id 40 | * @return 41 | */ 42 | Optional findOne(Long id); 43 | 44 | /** 45 | * Saves the given {@link Customer}. 46 | * 47 | * @param customer 48 | * @return 49 | */ 50 | S save(S customer); 51 | 52 | /** 53 | * Sample method to derive a query from using JDK 8's {@link Optional} as return type. 54 | * 55 | * @param lastname 56 | * @return 57 | */ 58 | // TODO: 03 - Support for Optional (existed before) 59 | Optional findByLastname(String lastname); 60 | 61 | /** 62 | * Sample default method to show JDK 8 feature support. 63 | * 64 | * @param customer 65 | * @return 66 | */ 67 | default Optional findByLastname(Customer customer) { 68 | return findByLastname(customer == null ? null : customer.getLastname()); 69 | } 70 | 71 | /** 72 | * Sample method to demonstrate support for {@link Stream} as a return type with a custom query. The query is executed 73 | * in a streaming fashion which means that the method returns as soon as the first results are ready. 74 | * 75 | * @return 76 | */ 77 | @Query("select c from Customer c") 78 | Stream streamAllCustomers(); 79 | 80 | /** 81 | * Sample method to demonstrate support for {@link Stream} as a return type with a derived query. The query is 82 | * executed in a streaming fashion which means that the method returns as soon as the first results are ready. 83 | * 84 | * @return 85 | */ 86 | Stream findAllByLastnameIsNotNull(); 87 | 88 | @Async 89 | // TODO: 04 - Support for CompletableFuture 90 | CompletableFuture> readAllBy(); 91 | } 92 | -------------------------------------------------------------------------------- /03-java8/src/main/resources/META-INF/orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /03-java8/src/test/java/example/springdata/jpa/java8/Java8IntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.springdata.jpa.java8; 17 | 18 | import static org.hamcrest.Matchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import lombok.extern.slf4j.Slf4j; 22 | 23 | import java.util.Optional; 24 | import java.util.concurrent.CompletableFuture; 25 | import java.util.concurrent.TimeUnit; 26 | import java.util.stream.Collectors; 27 | import java.util.stream.Stream; 28 | 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.springframework.beans.factory.annotation.Autowired; 32 | import org.springframework.boot.autoconfigure.SpringBootApplication; 33 | import org.springframework.boot.orm.jpa.EntityScan; 34 | import org.springframework.boot.test.SpringApplicationConfiguration; 35 | import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters; 36 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 37 | import org.springframework.scheduling.annotation.EnableAsync; 38 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 39 | import org.springframework.transaction.annotation.Propagation; 40 | import org.springframework.transaction.annotation.Transactional; 41 | 42 | /** 43 | * Integration test to show the usage of Java 8 date time APIs with Spring Data JPA auditing. 44 | * 45 | * @author Oliver Gierke 46 | * @author Thomas Darimont 47 | */ 48 | @RunWith(SpringJUnit4ClassRunner.class) 49 | @SpringApplicationConfiguration 50 | @Transactional 51 | @Slf4j 52 | public class Java8IntegrationTests { 53 | 54 | // TODO: 02 - Support for non-time-zoned JSR-310 types 55 | 56 | @EnableAsync 57 | @EntityScan(basePackageClasses = { Java8IntegrationTests.class, Jsr310JpaConverters.class }) 58 | @EnableJpaAuditing 59 | @SpringBootApplication 60 | static class Config {} 61 | 62 | @Autowired CustomerRepository repository; 63 | 64 | @Test 65 | public void providesFindOneWithOptional() { 66 | 67 | Customer carter = repository.save(new Customer("Carter", "Beauford")); 68 | 69 | assertThat(repository.findOne(carter.getId()).isPresent(), is(true)); 70 | assertThat(repository.findOne(carter.getId() + 1), is(Optional. empty())); 71 | } 72 | 73 | @Test 74 | public void auditingSetsJdk8DateTimeTypes() { 75 | 76 | Customer customer = repository.save(new Customer("Dave", "Matthews")); 77 | 78 | assertThat(customer.getCreatedDate(), is(notNullValue())); 79 | assertThat(customer.getModifiedDate(), is(notNullValue())); 80 | } 81 | 82 | @Test 83 | public void invokesDefaultMethod() { 84 | 85 | Customer customer = repository.save(new Customer("Dave", "Matthews")); 86 | Optional result = repository.findByLastname(customer); 87 | 88 | assertThat(result.isPresent(), is(true)); 89 | assertThat(result.get(), is(customer)); 90 | } 91 | 92 | /** 93 | * Streaming data from the store by using a repository method that returns a {@link Stream}. Note, that since the 94 | * resulting {@link Stream} contains state it needs to be closed explicitly after use! 95 | */ 96 | @Test 97 | public void useJava8StreamsWithCustomQuery() { 98 | 99 | Customer customer1 = repository.save(new Customer("Customer1", "Foo")); 100 | Customer customer2 = repository.save(new Customer("Customer2", "Bar")); 101 | 102 | try (Stream stream = repository.streamAllCustomers()) { 103 | assertThat(stream.collect(Collectors.toList()), hasItems(customer1, customer2)); 104 | } 105 | } 106 | 107 | /** 108 | * Streaming data from the store by using a repository method that returns a {@link Stream} with a derived query. 109 | * Note, that since the resulting {@link Stream} contains state it needs to be closed explicitly after use! 110 | */ 111 | @Test 112 | public void useJava8StreamsWithDerivedQuery() { 113 | 114 | Customer customer1 = repository.save(new Customer("Customer1", "Foo")); 115 | Customer customer2 = repository.save(new Customer("Customer2", "Bar")); 116 | 117 | try (Stream stream = repository.findAllByLastnameIsNotNull()) { 118 | assertThat(stream.collect(Collectors.toList()), hasItems(customer1, customer2)); 119 | } 120 | } 121 | 122 | /** 123 | * Here we demonstrate the usage of {@link CompletableFuture} as a result wrapper for asynchronous repository query 124 | * methods. Note, that we need to disable the surrounding transaction to be able to asynchronously read the written 125 | * data from from another thread within the same test method. 126 | */ 127 | @Test 128 | @Transactional(propagation = Propagation.NOT_SUPPORTED) 129 | public void supportsCompletableFuturesAsReturnTypeWrapper() throws Exception { 130 | 131 | repository.save(new Customer("Customer1", "Foo")); 132 | repository.save(new Customer("Customer2", "Bar")); 133 | 134 | // TODO: 05 - Support for CompletableFuture 135 | 136 | CompletableFuture future = repository.readAllBy().thenAccept(customers -> { 137 | 138 | assertThat(customers, hasSize(2)); 139 | customers.forEach(customer -> log.info(customer.toString())); 140 | log.info("Completed!"); 141 | }); 142 | 143 | while (!future.isDone()) { 144 | log.info("Waiting for the CompletableFuture to finish..."); 145 | TimeUnit.MILLISECONDS.sleep(500); 146 | } 147 | 148 | future.get(); 149 | 150 | log.info("Done!"); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /04-custom-repository/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | com.springone2gx.2015 7 | whats-new-in-spring-data 8 | 1.0.0.BUILD-SNAPSHOT 9 | ../pom.xml 10 | 11 | 12 | spring-data-custom-repository 13 | What's new in Spring Data? - Custom repository 14 | 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-data-jpa 20 | 21 | 22 | 23 | org.hsqldb 24 | hsqldb 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /04-custom-repository/src/main/java/example/CustomBaseRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.extern.slf4j.Slf4j; 19 | 20 | import java.io.Serializable; 21 | 22 | import javax.persistence.EntityManager; 23 | 24 | import org.springframework.data.jpa.repository.support.JpaEntityInformation; 25 | import org.springframework.data.jpa.repository.support.SimpleJpaRepository; 26 | 27 | /** 28 | * A custom extension of {@link SimpleJpaRepository}. See {@link ApplicationIntegrationTests.Config} for how to register 29 | * it. 30 | * 31 | * @author Oliver Gierke 32 | * @see ApplicationIntegrationTests.Config 33 | */ 34 | @Slf4j 35 | class CustomBaseRepository extends SimpleJpaRepository { 36 | 37 | /** 38 | * Creates a new {@link CustomBaseRepository} for the given {@link JpaEntityInformation} and {@link EntityManager}. 39 | * 40 | * @param entityInformation must not be {@literal null}. 41 | * @param entityManager must not be {@literal null}. 42 | */ 43 | public CustomBaseRepository(JpaEntityInformation entityInformation, EntityManager entityManager) { 44 | super(entityInformation, entityManager); 45 | } 46 | 47 | /* 48 | * (non-Javadoc) 49 | * @see org.springframework.data.jpa.repository.support.SimpleJpaRepository#findOne(java.io.Serializable) 50 | */ 51 | @Override 52 | public T findOne(ID id) { 53 | 54 | log.info("CustomBaseRepository.findOne(…) called!"); 55 | 56 | return super.findOne(id); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /04-custom-repository/src/main/java/example/Customer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.AccessLevel; 19 | import lombok.EqualsAndHashCode; 20 | import lombok.Getter; 21 | import lombok.NoArgsConstructor; 22 | import lombok.RequiredArgsConstructor; 23 | import lombok.ToString; 24 | 25 | import javax.persistence.Entity; 26 | import javax.persistence.GeneratedValue; 27 | import javax.persistence.Id; 28 | 29 | /** 30 | * @author Oliver Gierke 31 | */ 32 | @Entity 33 | @Getter 34 | @EqualsAndHashCode 35 | @ToString 36 | @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) 37 | @RequiredArgsConstructor 38 | public class Customer { 39 | 40 | private @Id @GeneratedValue Long id; 41 | private final String firstname, lastname; 42 | private final String email; 43 | } 44 | -------------------------------------------------------------------------------- /04-custom-repository/src/main/java/example/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import org.springframework.data.repository.CrudRepository; 19 | 20 | /** 21 | * Repository to manage {@link Customer} instances. 22 | * 23 | * @author Oliver Gierke 24 | */ 25 | interface CustomerRepository extends CrudRepository {} 26 | -------------------------------------------------------------------------------- /04-custom-repository/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.example=INFO 2 | -------------------------------------------------------------------------------- /04-custom-repository/src/test/java/example/ApplicationIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.hamcrest.Matchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import org.junit.Test; 22 | import org.junit.runner.RunWith; 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.boot.autoconfigure.SpringBootApplication; 25 | import org.springframework.boot.test.SpringApplicationConfiguration; 26 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 27 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 28 | import org.springframework.transaction.annotation.Transactional; 29 | 30 | /** 31 | * Integration test to show the usage of Java 8 date time APIs with Spring Data JPA auditing. 32 | * 33 | * @author Oliver Gierke 34 | */ 35 | @RunWith(SpringJUnit4ClassRunner.class) 36 | @SpringApplicationConfiguration 37 | @Transactional 38 | public class ApplicationIntegrationTests { 39 | 40 | @SpringBootApplication 41 | @EnableJpaRepositories(repositoryBaseClass = CustomBaseRepository.class) 42 | static class Config {} 43 | 44 | @Autowired CustomerRepository repository; 45 | 46 | @Test 47 | public void shouldInvokeMethodOnCustomRepository() { 48 | 49 | Customer carter = repository.save(new Customer("Carter", "Beauford", "carter@dmband.com")); 50 | 51 | assertThat(repository.findOne(carter.getId()), is(notNullValue())); 52 | assertThat(repository.findOne(carter.getId() + 4711), is(nullValue())); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /05-web-projection/README.md: -------------------------------------------------------------------------------- 1 | # Spring Data - web support example 2 | 3 | This example shows some of the Spring Data integration features with Spring MVC. 4 | 5 | 1. See how we plug into Spring MVC to create `Pageable` instances from request parameters in `UserController.users(…)`. 6 | 2. See how interfaces can be used to bind request payloads in `UserController.UserForm`. Spring Data creates a `Map`-backed proxy for you to easily create form-backing objects. -------------------------------------------------------------------------------- /05-web-projection/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | spring-data-web-projection 6 | 7 | What's new in Spring Data? - Web projection 8 | 9 | 10 | com.springone2gx.2015 11 | whats-new-in-spring-data 12 | 1.0.0.BUILD-SNAPSHOT 13 | ../pom.xml 14 | 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-web 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-thymeleaf 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-data-jpa 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-security 36 | 37 | 38 | 39 | org.hsqldb 40 | hsqldb 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /05-web-projection/src/main/java/example/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import java.util.stream.IntStream; 19 | 20 | import javax.annotation.PostConstruct; 21 | 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.SpringApplication; 24 | import org.springframework.boot.autoconfigure.SpringBootApplication; 25 | import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; 26 | import org.springframework.context.annotation.Bean; 27 | import org.springframework.data.domain.Pageable; 28 | import org.springframework.data.projection.ProjectionFactory; 29 | import org.springframework.data.projection.SpelAwareProxyProjectionFactory; 30 | import org.springframework.data.web.config.EnableSpringDataWebSupport; 31 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 32 | import org.springframework.security.crypto.password.PasswordEncoder; 33 | 34 | /** 35 | * Central Spring Boot application class to bootstrap the application. Excludes Spring Security auto-configuration as we 36 | * don't need it for the example but only want to use a {@link PasswordEncoder} (see {@link #passwordEncoder()}). 37 | *

38 | * Spring Data web support is transparently activated by Boot for you. In case you want to manually activate it, use 39 | * {@link EnableSpringDataWebSupport}. The core aspects of the enabled functionality shown in this example are: 40 | *

    41 | *
  1. Automatic population of a {@link Pageable} instances from request parameters (see 42 | * {@link example.web.UserController#users(Pageable)})
  2. 43 | *
  3. The ability to use proxy-backed interfaces to bind request payloads (see 44 | * {@link example.web.UserController.UserForm})
  4. 45 | *
46 | * 47 | * @author Oliver Gierke 48 | */ 49 | @SpringBootApplication(exclude = SecurityAutoConfiguration.class) 50 | public class Application { 51 | 52 | public static void main(String... args) { 53 | SpringApplication.run(Application.class, args); 54 | } 55 | 56 | @Autowired UserManagement userManagement; 57 | 58 | /** 59 | * Creates a few sample users. 60 | */ 61 | @PostConstruct 62 | public void init() { 63 | 64 | IntStream.range(0, 41).forEach(index -> { 65 | userManagement.register(new Username("user" + index), Password.raw("foobar")); 66 | }); 67 | } 68 | 69 | /** 70 | * A Spring Security {@link PasswordEncoder} to encrypt passwords for newly created users, used in 71 | * {@link UserManagement}. 72 | * 73 | * @return 74 | */ 75 | public @Bean PasswordEncoder passwordEncoder() { 76 | return new BCryptPasswordEncoder(); 77 | } 78 | 79 | public @Bean ProjectionFactory projectionFactory() { 80 | return new SpelAwareProxyProjectionFactory(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /05-web-projection/src/main/java/example/Password.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import javax.persistence.Embeddable; 19 | 20 | import lombok.AccessLevel; 21 | import lombok.AllArgsConstructor; 22 | import lombok.EqualsAndHashCode; 23 | import lombok.Getter; 24 | import lombok.experimental.Delegate; 25 | 26 | /** 27 | * A value object to represent {@link Password}s in encrypted and unencrypted state. Note how the methods to create a 28 | * {@link Password} in encrypted state are restricted to package scope so that only the user subsystem is actually able 29 | * to encrypted passwords. 30 | * 31 | * @author Oliver Gierke 32 | */ 33 | @EqualsAndHashCode 34 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 35 | @Getter(AccessLevel.PACKAGE) 36 | @Embeddable 37 | public class Password implements CharSequence { 38 | 39 | private @Delegate final String password; 40 | private @Getter transient boolean encrypted; 41 | 42 | Password() { 43 | this.password = null; 44 | this.encrypted = true; 45 | } 46 | 47 | /** 48 | * Creates a new raw {@link Password} for the given source {@link String}. 49 | * 50 | * @param password must not be {@literal null} or empty. 51 | * @return 52 | */ 53 | public static Password raw(String password) { 54 | return new Password(password, false); 55 | } 56 | 57 | /** 58 | * Creates a new encrypted {@link Password} for the given {@link String}. Note how this method is package protected so 59 | * that encrypted passwords can only created by components in this package and not accidentally by clients using the 60 | * type from other packages. 61 | * 62 | * @param password must not be {@literal null} or empty. 63 | * @return 64 | */ 65 | static Password encrypted(String password) { 66 | return new Password(password, true); 67 | } 68 | 69 | /* 70 | * (non-Javadoc) 71 | * @see java.lang.Object#toString() 72 | */ 73 | public String toString() { 74 | return encrypted ? password : "********"; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /05-web-projection/src/main/java/example/User.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import javax.persistence.Entity; 19 | import javax.persistence.GeneratedValue; 20 | import javax.persistence.Id; 21 | import javax.persistence.PrePersist; 22 | import javax.persistence.PreUpdate; 23 | 24 | import lombok.AccessLevel; 25 | import lombok.AllArgsConstructor; 26 | import lombok.EqualsAndHashCode; 27 | import lombok.Getter; 28 | import lombok.RequiredArgsConstructor; 29 | 30 | /** 31 | * A {@link User} domain object. The primary entity of this example. Basically a combination of a {@link Username} and 32 | * {@link Password}. 33 | * 34 | * @author Oliver Gierke 35 | */ 36 | @Entity 37 | @Getter 38 | @RequiredArgsConstructor 39 | @AllArgsConstructor(access = AccessLevel.PACKAGE) 40 | @EqualsAndHashCode(of = "id") 41 | public class User { 42 | 43 | private @GeneratedValue @Id Long id; 44 | private final Username username; 45 | private final Password password; 46 | 47 | User() { 48 | this.username = null; 49 | this.password = null; 50 | } 51 | 52 | /** 53 | * Makes sure only {@link User}s with encrypted {@link Password} can be persisted. 54 | */ 55 | @PrePersist 56 | @PreUpdate 57 | void assertEncrypted() { 58 | 59 | if (!password.isEncrypted()) { 60 | throw new IllegalStateException("Tried to persist/load a user with a non-encrypted password!"); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /05-web-projection/src/main/java/example/UserManagement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import java.util.Optional; 19 | 20 | import javax.transaction.Transactional; 21 | 22 | import lombok.RequiredArgsConstructor; 23 | 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.data.domain.Page; 26 | import org.springframework.data.domain.Pageable; 27 | import org.springframework.security.crypto.password.PasswordEncoder; 28 | import org.springframework.stereotype.Service; 29 | import org.springframework.util.Assert; 30 | 31 | /** 32 | * Domain service to register {@link User}s in the system. 33 | * 34 | * @author Oliver Gierke 35 | */ 36 | @Transactional 37 | @Service 38 | @RequiredArgsConstructor(onConstructor = @__(@Autowired)) 39 | public class UserManagement { 40 | 41 | private final UserRepository repository; 42 | private final PasswordEncoder encoder; 43 | 44 | /** 45 | * Registers a {@link User} with the given {@link Username} and {@link Password}. 46 | * 47 | * @param username must not be {@literal null}. 48 | * @param password must not be {@literal null}. 49 | * @return 50 | */ 51 | public User register(Username username, Password password) { 52 | 53 | Assert.notNull(username, "Username must not be null!"); 54 | Assert.notNull(password, "Password must not be null!"); 55 | 56 | repository.findByUsername(username).ifPresent(user -> { 57 | throw new IllegalArgumentException("User with that name already exists!"); 58 | }); 59 | 60 | Password encryptedPassword = Password.encrypted(encoder.encode(password)); 61 | 62 | return repository.save(new User(username, encryptedPassword)); 63 | } 64 | 65 | /** 66 | * Returns a {@link Page} of {@link User} for the given {@link Pageable}. 67 | * 68 | * @param pageable must not be {@literal null}. 69 | * @return 70 | */ 71 | public Page findAll(Pageable pageable) { 72 | 73 | Assert.notNull(pageable, "Pageable must not be null!"); 74 | 75 | return repository.findAll(pageable); 76 | } 77 | 78 | /** 79 | * Returns the {@link User} with the given {@link Username}. 80 | * 81 | * @param username must not be {@literal null}. 82 | * @return 83 | */ 84 | public Optional findByUsername(Username username) { 85 | 86 | Assert.notNull(username, "Username must not be null!"); 87 | 88 | return repository.findByUsername(username); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /05-web-projection/src/main/java/example/UserRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import java.util.Optional; 19 | 20 | import org.springframework.data.repository.PagingAndSortingRepository; 21 | 22 | /** 23 | * A Spring Data repository to persist {@link User}s. 24 | * 25 | * @author Oliver Gierke 26 | */ 27 | interface UserRepository extends PagingAndSortingRepository { 28 | 29 | /** 30 | * Returns the user with the given {@link Username}. 31 | * 32 | * @param username can be {@literal null}. 33 | * @return 34 | */ 35 | Optional findByUsername(Username username); 36 | } 37 | -------------------------------------------------------------------------------- /05-web-projection/src/main/java/example/Username.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import javax.persistence.Embeddable; 19 | 20 | import lombok.EqualsAndHashCode; 21 | 22 | import org.springframework.util.StringUtils; 23 | 24 | /** 25 | * value object to represent user names. 26 | * 27 | * @author Oliver Gierke 28 | */ 29 | @EqualsAndHashCode 30 | @Embeddable 31 | public class Username { 32 | 33 | private final String username; 34 | 35 | Username() { 36 | this.username = null; 37 | } 38 | 39 | /** 40 | * Creates a new {@link Username}. 41 | * 42 | * @param username must not be {@literal null} or empty. 43 | */ 44 | public Username(String username) { 45 | 46 | if (!StringUtils.hasText(username)) { 47 | throw new IllegalArgumentException("Invalid username!"); 48 | } 49 | 50 | this.username = username; 51 | } 52 | 53 | /* 54 | * (non-Javadoc) 55 | * @see java.lang.Object#toString() 56 | */ 57 | @Override 58 | public String toString() { 59 | return username; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /05-web-projection/src/main/java/example/web/UserController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.web; 17 | 18 | import static org.springframework.validation.ValidationUtils.*; 19 | 20 | import example.Password; 21 | import example.User; 22 | import example.UserManagement; 23 | import example.Username; 24 | import lombok.RequiredArgsConstructor; 25 | 26 | import java.util.List; 27 | import java.util.Map; 28 | 29 | import org.springframework.beans.factory.annotation.Autowired; 30 | import org.springframework.beans.factory.annotation.Value; 31 | import org.springframework.data.domain.Page; 32 | import org.springframework.data.domain.PageRequest; 33 | import org.springframework.data.domain.Pageable; 34 | import org.springframework.data.projection.ProjectionFactory; 35 | import org.springframework.data.web.PageableDefault; 36 | import org.springframework.data.web.PageableHandlerMethodArgumentResolver; 37 | import org.springframework.data.web.config.EnableSpringDataWebSupport; 38 | import org.springframework.http.MediaType; 39 | import org.springframework.stereotype.Controller; 40 | import org.springframework.ui.Model; 41 | import org.springframework.validation.BindingResult; 42 | import org.springframework.web.bind.annotation.ModelAttribute; 43 | import org.springframework.web.bind.annotation.RequestMapping; 44 | import org.springframework.web.bind.annotation.RequestMethod; 45 | import org.springframework.web.bind.annotation.ResponseBody; 46 | import org.springframework.web.servlet.view.RedirectView; 47 | 48 | /** 49 | * A sample controller implementation to showcase Spring Data web support: 50 | *
    51 | *
  1. Automatic population of a {@link Pageable} instance as controller method argument. This is achieved by the 52 | * automatic activation of {@link EnableSpringDataWebSupport} and in turn its registration of a 53 | * {@link PageableHandlerMethodArgumentResolver}.
  2. 54 | *
  3. Usage of proxy-backed interfaces to bind request parameters.
  4. 55 | *
56 | * 57 | * @author Oliver Gierke 58 | */ 59 | @Controller 60 | @RequiredArgsConstructor(onConstructor = @__(@Autowired) ) 61 | @RequestMapping("/users") 62 | class UserController { 63 | 64 | private final UserManagement userManagement; 65 | private final ProjectionFactory projections; 66 | 67 | /** 68 | * Equips the model with a {@link Page} of {@link User}s. Spring Data automatically populates the {@link Pageable} 69 | * from request data according to the setup of {@link PageableHandlerMethodArgumentResolver}. Note how the defaults 70 | * can be tweaked by using {@link PageableDefault}. 71 | * 72 | * @param pageable will never be {@literal null}. 73 | * @return 74 | */ 75 | @ModelAttribute("users") 76 | public Page users(@PageableDefault(size = 5) Pageable pageable) { 77 | return userManagement.findAll(pageable); 78 | } 79 | 80 | /** 81 | * Registers a new {@link User} for the data provided by the given {@link UserForm}. Note, how an interface is used to 82 | * bind request parameters. 83 | * 84 | * @param form the request data bound to the {@link UserForm} instance. 85 | * @param binding the result of the binding operation. 86 | * @param model the Spring MVC {@link Model}. 87 | * @return 88 | */ 89 | @RequestMapping(method = RequestMethod.POST) 90 | public Object register(UserForm userForm, BindingResult binding, Model model) { 91 | 92 | // TODO: 02 - Inbound projections 93 | 94 | userForm.validate(binding, userManagement); 95 | 96 | if (binding.hasErrors()) { 97 | return "users"; 98 | } 99 | 100 | userManagement.register(new Username(userForm.getUsername()), Password.raw(userForm.getPassword())); 101 | 102 | RedirectView redirectView = new RedirectView("redirect:/users"); 103 | redirectView.setPropagateQueryParams(true); 104 | 105 | return redirectView; 106 | } 107 | 108 | /** 109 | * Populates the {@link Model} with the {@link UserForm} automatically created by Spring Data web components. It will 110 | * create a {@link Map}-backed proxy for the interface. 111 | * 112 | * @param model will never be {@literal null}. 113 | * @param userForm will never be {@literal null}. 114 | * @return 115 | */ 116 | @RequestMapping(method = RequestMethod.GET) 117 | public String listUsers(Model model, UserForm userForm) { 118 | 119 | model.addAttribute("userForm", userForm); 120 | 121 | return "users"; 122 | } 123 | 124 | /** 125 | * Returns the first page of {@link User}s as JSON representation. Note how we leverage the {@link ProjectionFactory} 126 | * to wrap each result into the {@link UsernamesOnly} projection. 127 | * 128 | *
129 | 	 * curl -H "Content-type: application/json" -H "Accept: application/json" http://localhost:8080/users 
130 | 	 * 
131 | 	 * http --json http://localhost:8080/users
132 | 	 * 
133 | * 134 | * @return 135 | */ 136 | @ResponseBody 137 | @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) 138 | public List getUsers() { 139 | 140 | // TODO: 01 - Projections 141 | 142 | return userManagement.findAll(new PageRequest(0, 10))// 143 | .map(user -> projections.createProjection(UsernamesOnly.class, user))// 144 | .getContent(); 145 | } 146 | 147 | /** 148 | * An interface to represent the form to be used 149 | * 150 | * @author Oliver Gierke 151 | */ 152 | interface UserForm { 153 | 154 | String getUsername(); 155 | 156 | String getPassword(); 157 | 158 | String getRepeatedPassword(); 159 | 160 | /** 161 | * Validates the {@link UserForm}. 162 | * 163 | * @param errors 164 | * @param userManagement 165 | */ 166 | default void validate(BindingResult errors, UserManagement userManagement) { 167 | 168 | rejectIfEmptyOrWhitespace(errors, "username", "user.username.empty"); 169 | rejectIfEmptyOrWhitespace(errors, "password", "user.password.empty"); 170 | rejectIfEmptyOrWhitespace(errors, "repeatedPassword", "user.repeatedPassword.empty"); 171 | 172 | if (!getPassword().equals(getRepeatedPassword())) { 173 | errors.rejectValue("repeatedPassword", "user.password.no-match"); 174 | } 175 | 176 | try { 177 | 178 | userManagement.findByUsername(new Username(getUsername())) 179 | .ifPresent(user -> errors.rejectValue("username", "user.username.exists")); 180 | 181 | } catch (IllegalArgumentException o_O) { 182 | errors.rejectValue("username", "user.username.invalidFormat"); 183 | } 184 | } 185 | } 186 | 187 | /** 188 | * Projection interface 189 | * 190 | * @author Oliver Gierke 191 | */ 192 | interface UsernamesOnly { 193 | 194 | @Value("#{target.username.toString()}") 195 | String getUsername(); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /05-web-projection/src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | user.username.exists = Username already exists! 2 | user.password.no-match = The given passwords don't match! -------------------------------------------------------------------------------- /05-web-projection/src/main/resources/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: auto; 3 | width: 50%; 4 | } 5 | 6 | form.user-form { 7 | padding: 9px 14px; 8 | border: 1px solid #e1e1e8; 9 | border-radius: 4px; 10 | } 11 | 12 | .fieldError { 13 | border: 1px solid #a94442; 14 | } 15 | 16 | .errors { 17 | padding: 1em; 18 | margin: 1em 0; 19 | border: 1px solid #eee; 20 | border-left-width: 5px; 21 | border-left-color: #a94442; 22 | border-radius: 5px; 23 | } 24 | 25 | .errors li { 26 | list-style-type: none; 27 | margin: 0.5em 0.7em; 28 | } 29 | -------------------------------------------------------------------------------- /05-web-projection/src/main/resources/templates/users.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Users 5 | 6 | 7 | 8 | 9 | 10 |

Users

11 | 12 | 27 | 28 |
    29 |
  1. Username
  2. 30 |
31 | 32 |
33 | 34 |
    35 |
  • Input is incorrect
  • 36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 |
44 | 45 |
46 |
47 |
48 | 49 |
50 | 51 |
52 | 53 | -------------------------------------------------------------------------------- /05-web-projection/src/test/java/example/AbstractIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import example.Application; 19 | 20 | import org.junit.runner.RunWith; 21 | import org.springframework.boot.test.SpringApplicationConfiguration; 22 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 23 | 24 | /** 25 | * Integration tests to bootstrap the application. 26 | * 27 | * @author Oliver Gierke 28 | */ 29 | @RunWith(SpringJUnit4ClassRunner.class) 30 | @SpringApplicationConfiguration(classes = Application.class) 31 | public abstract class AbstractIntegrationTests {} 32 | -------------------------------------------------------------------------------- /05-web-projection/src/test/java/example/UserManagementIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.hamcrest.CoreMatchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import example.Password; 22 | import example.User; 23 | import example.UserManagement; 24 | import example.Username; 25 | 26 | import org.junit.Test; 27 | import org.springframework.beans.factory.annotation.Autowired; 28 | 29 | /** 30 | * Integration tests for {@link UserManagement}. 31 | * 32 | * @author Oliver Gierke 33 | */ 34 | public class UserManagementIntegrationTests extends AbstractIntegrationTests { 35 | 36 | @Autowired UserManagement userManagement; 37 | 38 | /** 39 | * @see #65 40 | */ 41 | @Test 42 | public void encryptsPasswordWhenCreatingAUser() { 43 | 44 | User user = userManagement.register(new Username("olivergierke"), Password.raw("foobar")); 45 | 46 | assertThat(user.getPassword().isEncrypted(), is(true)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /05-web-projection/src/test/java/example/UserRepositoryIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import example.Password; 19 | import example.User; 20 | import example.UserRepository; 21 | import example.Username; 22 | 23 | import org.junit.Test; 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.dao.InvalidDataAccessApiUsageException; 26 | 27 | /** 28 | * Integration tests for {@link UserRepository}. 29 | * 30 | * @author Oliver Gierke 31 | */ 32 | public class UserRepositoryIntegrationTests extends AbstractIntegrationTests { 33 | 34 | @Autowired UserRepository users; 35 | 36 | /** 37 | * @see #65 38 | */ 39 | @Test(expected = InvalidDataAccessApiUsageException.class) 40 | public void repositoryRejectsUnencryptedPassword() { 41 | users.save(new User(new Username("olivergierke"), Password.raw("foobar"))); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /06-querydsl-web/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | spring-data-querydsl-web 6 | 7 | What's new in Spring Data? - Querydsl web integration 8 | 9 | 10 | com.springone2gx.2015 11 | whats-new-in-spring-data 12 | 1.0.0.BUILD-SNAPSHOT 13 | ../pom.xml 14 | 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-web 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-mongodb 26 | 27 | 28 | 29 | com.querydsl 30 | querydsl-mongodb 31 | ${querydsl.version} 32 | 33 | 34 | 35 | org.springframework.batch 36 | spring-batch-core 37 | 38 | 39 | 40 | de.flapdoodle.embed 41 | de.flapdoodle.embed.mongo 42 | runtime 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-thymeleaf 50 | runtime 51 | 52 | 53 | 54 | org.webjars 55 | jquery 56 | 2.1.3 57 | runtime 58 | 59 | 60 | 61 | org.webjars 62 | bootstrap 63 | 3.3.4 64 | runtime 65 | 66 | 67 | 68 | org.webjars 69 | URI.js 70 | 1.14.1 71 | runtime 72 | 73 | 74 | 75 | org.webjars 76 | webjars-locator 77 | runtime 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | org.springframework.boot 87 | spring-boot-maven-plugin 88 | 89 | 90 | 91 | com.mysema.maven 92 | apt-maven-plugin 93 | ${apt.version} 94 | 95 | 96 | com.querydsl 97 | querydsl-apt 98 | ${querydsl.version} 99 | 100 | 101 | 102 | 103 | generate-sources 104 | 105 | process 106 | 107 | 108 | target/generated-sources/annotations 109 | org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor 110 | true 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /06-querydsl-web/src/main/java/example/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import javax.annotation.PostConstruct; 19 | 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.boot.SpringApplication; 22 | import org.springframework.boot.autoconfigure.SpringBootApplication; 23 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 24 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 25 | 26 | /** 27 | * @author Christoph Strobl 28 | * @author Oliver Gierke 29 | */ 30 | @SpringBootApplication 31 | public class Application extends WebMvcConfigurerAdapter { 32 | 33 | public static void main(String[] args) { 34 | SpringApplication.run(Application.class, args); 35 | } 36 | 37 | @Override 38 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 39 | 40 | // Configure resource handler explicitly to enable non-versioned 41 | // Webjars in Thymeleaf templates 42 | registry.addResourceHandler("/webjars/**").// 43 | addResourceLocations("classpath:/META-INF/resources/webjars/").// 44 | resourceChain(true); 45 | } 46 | 47 | @Autowired UserRepository repo; 48 | 49 | @PostConstruct 50 | void initialize() throws Exception { 51 | 52 | // Import demo users from local CSV 53 | new UserInitializer(repo).initLocally(); 54 | 55 | // Import demo users from remote service 56 | // new UserInitializer(repo).initRemote(100); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /06-querydsl-web/src/main/java/example/User.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.Data; 19 | import lombok.Value; 20 | 21 | import org.springframework.data.annotation.Id; 22 | import org.springframework.data.mongodb.core.mapping.Document; 23 | 24 | import com.fasterxml.jackson.annotation.JsonIgnore; 25 | import com.fasterxml.jackson.annotation.JsonUnwrapped; 26 | 27 | /** 28 | * @author Christoph Strobl 29 | * @author Oliver Gierke 30 | */ 31 | @Data 32 | @Document 33 | public class User { 34 | 35 | private @Id String username; 36 | private String firstname, lastname, email, nationality; 37 | private @JsonIgnore String password; 38 | 39 | private @JsonUnwrapped Address address; 40 | private Picture picture; 41 | 42 | @Value 43 | public static class Address { 44 | String city, street, zip; 45 | } 46 | 47 | @Value 48 | public static class Picture { 49 | String large, medium, small; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /06-querydsl-web/src/main/java/example/UserInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.springframework.util.StringUtils.*; 19 | 20 | import example.User.Address; 21 | import example.User.Picture; 22 | import lombok.RequiredArgsConstructor; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Arrays; 26 | import java.util.List; 27 | import java.util.Scanner; 28 | import java.util.stream.Collectors; 29 | 30 | import org.springframework.batch.item.ExecutionContext; 31 | import org.springframework.batch.item.file.FlatFileItemReader; 32 | import org.springframework.batch.item.file.mapping.DefaultLineMapper; 33 | import org.springframework.batch.item.file.separator.DefaultRecordSeparatorPolicy; 34 | import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; 35 | import org.springframework.core.io.ClassPathResource; 36 | import org.springframework.core.io.Resource; 37 | import org.springframework.core.io.UrlResource; 38 | import org.springframework.util.StringUtils; 39 | import org.springframework.web.util.UriTemplate; 40 | 41 | /** 42 | * Initialize {@link UserRepository} with sample data. 43 | * 44 | * @author Christoph Strobl 45 | * @author Oliver Gierke 46 | */ 47 | @RequiredArgsConstructor 48 | public class UserInitializer { 49 | 50 | private static final UriTemplate REMOTE_TEMPLATE = new UriTemplate( 51 | "https://randomuser.me/api/?results={numberOfUsers}&format=csv&nat=US"); 52 | 53 | private final UserRepository repository; 54 | 55 | public void initLocally() throws Exception { 56 | 57 | List users = readUsers(new ClassPathResource("randomuser.me.csv")); 58 | 59 | repository.deleteAll(); 60 | repository.save(users); 61 | } 62 | 63 | public void initRemote(int numberOfUsers) throws Exception { 64 | 65 | List users = readUsers(new UrlResource(REMOTE_TEMPLATE.expand(numberOfUsers))); 66 | 67 | repository.deleteAll(); 68 | repository.save(users); 69 | } 70 | 71 | private static List readUsers(Resource resource) throws Exception { 72 | 73 | Scanner scanner = new Scanner(resource.getInputStream()); 74 | String line = scanner.nextLine(); 75 | scanner.close(); 76 | 77 | FlatFileItemReader reader = new FlatFileItemReader(); 78 | reader.setResource(resource); 79 | 80 | DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(); 81 | tokenizer.setNames(line.split(",")); 82 | tokenizer.setStrict(false); 83 | 84 | DefaultLineMapper lineMapper = new DefaultLineMapper(); 85 | lineMapper.setFieldSetMapper(fields -> { 86 | 87 | User user = new User(); 88 | 89 | user.setEmail(fields.readString("email")); 90 | user.setFirstname(capitalize(fields.readString("first"))); 91 | user.setLastname(capitalize(fields.readString("last"))); 92 | user.setNationality(fields.readString("nationality")); 93 | 94 | String city = Arrays.stream(fields.readString("city").split(" "))// 95 | .map(StringUtils::capitalize)// 96 | .collect(Collectors.joining(" ")); 97 | String street = Arrays.stream(fields.readString("street").split(" "))// 98 | .map(StringUtils::capitalize)// 99 | .collect(Collectors.joining(" ")); 100 | 101 | try { 102 | user.setAddress(new Address(city, street, fields.readString("zip"))); 103 | } catch (IllegalArgumentException e) { 104 | user.setAddress(new Address(city, street, fields.readString("postcode"))); 105 | } 106 | 107 | user.setPicture( 108 | new Picture(fields.readString("large"), fields.readString("medium"), fields.readString("thumbnail"))); 109 | user.setUsername(fields.readString("username")); 110 | user.setPassword(fields.readString("password")); 111 | 112 | return user; 113 | }); 114 | 115 | lineMapper.setLineTokenizer(tokenizer); 116 | 117 | reader.setLineMapper(lineMapper); 118 | reader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy()); 119 | reader.setLinesToSkip(1); 120 | reader.open(new ExecutionContext()); 121 | 122 | List users = new ArrayList<>(); 123 | User user = null; 124 | 125 | do { 126 | 127 | user = reader.read(); 128 | 129 | if (user != null) { 130 | users.add(user); 131 | } 132 | 133 | } while (user != null); 134 | 135 | return users; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /06-querydsl-web/src/main/java/example/UserRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import org.springframework.data.querydsl.QueryDslPredicateExecutor; 19 | import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer; 20 | import org.springframework.data.querydsl.binding.QuerydslBindings; 21 | import org.springframework.data.repository.CrudRepository; 22 | 23 | import com.querydsl.core.types.dsl.StringPath; 24 | 25 | /** 26 | * Repository to manage {@link User}s. Also implements {@link QueryDslPredicateExecutor} to enable predicate filtering 27 | * on Spring MVC controllers as well as {@link QuerydslBinderCustomizer} to tweak the way predicates are created for 28 | * properties. 29 | * 30 | * @author Christoph Strobl 31 | * @author Oliver Gierke 32 | */ 33 | public interface UserRepository 34 | extends CrudRepository, QueryDslPredicateExecutor, QuerydslBinderCustomizer { 35 | 36 | /* 37 | * (non-Javadoc) 38 | * @see org.springframework.data.querydsl.binding.QuerydslBinderCustomizer#customize(org.springframework.data.querydsl.binding.QuerydslBindings, com.mysema.query.types.EntityPath) 39 | */ 40 | @Override 41 | default public void customize(QuerydslBindings bindings, QUser user) { 42 | 43 | // TODO: 02 - Binding customizations for Querydsl 44 | 45 | // Customize binding by referring to property 46 | bindings.bind(user.firstname).first((path, value) -> path.eq(value)); 47 | 48 | // Customize binding by type 49 | bindings.bind(String.class).first((StringPath path, String value) -> path.containsIgnoreCase(value)); 50 | 51 | // Exclude properties from binding 52 | bindings.excluding(user.password); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /06-querydsl-web/src/main/java/example/web/UserController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.web; 17 | 18 | import example.User; 19 | import example.UserRepository; 20 | import lombok.RequiredArgsConstructor; 21 | 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.data.domain.Pageable; 24 | import org.springframework.data.querydsl.binding.QuerydslPredicate; 25 | import org.springframework.stereotype.Controller; 26 | import org.springframework.ui.Model; 27 | import org.springframework.util.MultiValueMap; 28 | import org.springframework.web.bind.annotation.RequestMapping; 29 | import org.springframework.web.bind.annotation.RequestMethod; 30 | import org.springframework.web.bind.annotation.RequestParam; 31 | import org.springframework.web.servlet.support.ServletUriComponentsBuilder; 32 | 33 | import com.querydsl.core.types.Predicate; 34 | 35 | /** 36 | * Controller to handle web requests for {@link User}s. 37 | * 38 | * @author Christoph Strobl 39 | * @author Oliver Gierke 40 | */ 41 | @Controller 42 | @RequiredArgsConstructor(onConstructor = @__(@Autowired) ) 43 | class UserController { 44 | 45 | private final UserRepository repository; 46 | 47 | @RequestMapping(value = "/", method = RequestMethod.GET) 48 | String index(Model model, // 49 | @QuerydslPredicate(root = User.class) Predicate predicate, Pageable pageable, // 50 | @RequestParam MultiValueMap parameters) { 51 | 52 | // TODO: 01 - Support for Querydsl predicates 53 | 54 | ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromCurrentRequest(); 55 | builder.replaceQueryParam("page", new Object[0]); 56 | 57 | model.addAttribute("baseUri", builder.build().toUri()); 58 | model.addAttribute("users", repository.findAll(predicate, pageable)); 59 | 60 | return "index"; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /06-querydsl-web/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.data.mongodb.database=users-querydsl 2 | -------------------------------------------------------------------------------- /06-querydsl-web/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | User Center 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |

User Center

15 | 16 |
17 |
18 |

Search

19 |
20 |
21 | 22 |
23 | 24 |
25 | 26 | 27 |
28 |
29 | 30 | 31 |
32 |
33 | 34 | 35 |
36 |
37 | 38 | 39 |
40 |
41 | 42 | 43 |
44 |
45 | 46 |
47 | 48 |
49 |
50 |
51 | 52 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
#FirstnameLastnameNationalityCityStreetEmail
1. 85 | 86 | FirstnameLastnameNaionalityCityStreetEmail
96 | 97 |
98 | 99 | 100 | -------------------------------------------------------------------------------- /07-jpa-entity-graph/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | com.springone2gx.2015 7 | whats-new-in-spring-data 8 | 1.0.0.BUILD-SNAPSHOT 9 | ../pom.xml 10 | 11 | 12 | spring-data-jpa-entity-graph 13 | What's new in Spring Data? - JPA 2.1 entity graphs 14 | 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-data-jpa 20 | 21 | 22 | 23 | org.hsqldb 24 | hsqldb 25 | runtime 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /07-jpa-entity-graph/src/main/java/example/fetchgraph/Product.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.fetchgraph; 17 | 18 | import lombok.AccessLevel; 19 | import lombok.Data; 20 | import lombok.NoArgsConstructor; 21 | import lombok.RequiredArgsConstructor; 22 | 23 | import java.util.HashSet; 24 | import java.util.Set; 25 | 26 | import javax.persistence.CascadeType; 27 | import javax.persistence.Entity; 28 | import javax.persistence.FetchType; 29 | import javax.persistence.GeneratedValue; 30 | import javax.persistence.Id; 31 | import javax.persistence.ManyToMany; 32 | import javax.persistence.NamedAttributeNode; 33 | import javax.persistence.NamedEntityGraph; 34 | import javax.persistence.NamedEntityGraphs; 35 | 36 | /** 37 | * @author Thomas Darimont 38 | */ 39 | @Data 40 | @Entity 41 | @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) 42 | @RequiredArgsConstructor 43 | @NamedEntityGraphs(@NamedEntityGraph(name = "product-with-tags", attributeNodes = { @NamedAttributeNode("tags") })) 44 | public class Product { 45 | 46 | private @GeneratedValue @Id Long id; 47 | private final String name; 48 | 49 | @ManyToMany(fetch = FetchType.LAZY, targetEntity = Tag.class, cascade = CascadeType.ALL) // 50 | private final Set tags = new HashSet<>(); 51 | } 52 | -------------------------------------------------------------------------------- /07-jpa-entity-graph/src/main/java/example/fetchgraph/ProductRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.fetchgraph; 17 | 18 | import javax.persistence.FetchType; 19 | import javax.persistence.NamedEntityGraph; 20 | 21 | import org.springframework.data.jpa.repository.EntityGraph; 22 | import org.springframework.data.repository.CrudRepository; 23 | 24 | /** 25 | * @author Thomas Darimont 26 | */ 27 | interface ProductRepository extends CrudRepository { 28 | 29 | /** 30 | * Here we use the {@link EntityGraph} annotation to specify that we want to use the {@link NamedEntityGraph} 31 | * product-with-tags specified on the {@link Product} entity. 32 | * 33 | * @param id 34 | * @return 35 | */ 36 | @EntityGraph("product-with-tags") 37 | Product findOneById(Long id); 38 | 39 | /** 40 | * Here we use the {@link EntityGraph} annotation to specify that we want the {@link Product#tags} association which 41 | * is marked as {@link FetchType#LAZY} to be fetched eagerly. 42 | * 43 | * @param id 44 | * @return 45 | */ 46 | // TODO: 01 - Ad-hoc entity graphs 47 | @EntityGraph(attributePaths = "tags") 48 | Product getOneById(Long id); 49 | } 50 | -------------------------------------------------------------------------------- /07-jpa-entity-graph/src/main/java/example/fetchgraph/Tag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.fetchgraph; 17 | 18 | import lombok.AccessLevel; 19 | import lombok.Data; 20 | import lombok.NoArgsConstructor; 21 | import lombok.RequiredArgsConstructor; 22 | 23 | import javax.persistence.Entity; 24 | import javax.persistence.GeneratedValue; 25 | import javax.persistence.Id; 26 | 27 | /** 28 | * @author Thomas Darimont 29 | * @author Oliver Gierke 30 | */ 31 | @Data 32 | @Entity 33 | @RequiredArgsConstructor 34 | @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) 35 | public class Tag { 36 | 37 | private @GeneratedValue @Id Long id; 38 | private final String name; 39 | } 40 | -------------------------------------------------------------------------------- /07-jpa-entity-graph/src/main/java/example/storedprocedures/User.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.storedprocedures; 17 | 18 | import javax.persistence.Entity; 19 | import javax.persistence.GeneratedValue; 20 | import javax.persistence.Id; 21 | import javax.persistence.NamedStoredProcedureQuery; 22 | import javax.persistence.ParameterMode; 23 | import javax.persistence.StoredProcedureParameter; 24 | 25 | /** 26 | * Sample user class. 27 | * 28 | * @author Oliver Gierke 29 | * @author Thomas Darimont 30 | */ 31 | @Entity 32 | @NamedStoredProcedureQuery(name = "User.plus1", // 33 | procedureName = "plus1inout", 34 | parameters = { @StoredProcedureParameter(mode = ParameterMode.IN, name = "arg", type = Integer.class), 35 | @StoredProcedureParameter(mode = ParameterMode.OUT, name = "res", type = Integer.class) }) 36 | public class User { 37 | 38 | private @GeneratedValue @Id Long id; 39 | } 40 | -------------------------------------------------------------------------------- /07-jpa-entity-graph/src/main/java/example/storedprocedures/UserRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.storedprocedures; 17 | 18 | import javax.persistence.EntityManager; 19 | 20 | import org.springframework.data.jpa.repository.query.Procedure; 21 | import org.springframework.data.repository.CrudRepository; 22 | 23 | /** 24 | * Simple repository interface for {@link User} instances. The interface is used to declare so called query methods, 25 | * methods to retrieve single entities or collections of them. 26 | * 27 | * @author Oliver Gierke 28 | * @author Thomas Darimont 29 | */ 30 | interface UserRepository extends CrudRepository { 31 | 32 | /** 33 | * Explicitly mapped to named stored procedure {@code User.plus1IO} in the {@link EntityManager} 34 | * 35 | * @see User 36 | */ 37 | // TODO: 02 - Stored procedures 38 | @Procedure(name = "User.plus1") 39 | Integer plus1BackedByOtherNamedStoredProcedure(Integer arg); 40 | 41 | /** 42 | * Directly map the method to the stored procedure in the database (to avoid the annotation madness on your domain 43 | * classes). 44 | */ 45 | @Procedure 46 | Integer plus1inout(Integer arg); 47 | } 48 | -------------------------------------------------------------------------------- /07-jpa-entity-graph/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.separator=/; 2 | -------------------------------------------------------------------------------- /07-jpa-entity-graph/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | DROP procedure IF EXISTS plus1inout 2 | /; 3 | CREATE procedure plus1inout (IN arg int, OUT res int) 4 | BEGIN ATOMIC 5 | set res = arg + 1; 6 | END 7 | /; 8 | -------------------------------------------------------------------------------- /07-jpa-entity-graph/src/test/java/example/fetchgraph/FetchGraphIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.fetchgraph; 17 | 18 | import static org.hamcrest.Matchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import java.util.Collections; 22 | 23 | import javax.persistence.EntityManager; 24 | 25 | import org.junit.Test; 26 | import org.junit.runner.RunWith; 27 | import org.springframework.beans.factory.annotation.Autowired; 28 | import org.springframework.boot.autoconfigure.SpringBootApplication; 29 | import org.springframework.boot.test.SpringApplicationConfiguration; 30 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 31 | import org.springframework.transaction.annotation.Transactional; 32 | 33 | /** 34 | * Integration test showing the usage of JPA 2.1 fetch graph support through Spring Data JPA repositories. 35 | * 36 | * @author Thomas Darimont 37 | */ 38 | @RunWith(SpringJUnit4ClassRunner.class) 39 | @Transactional 40 | @SpringApplicationConfiguration 41 | public class FetchGraphIntegrationTests { 42 | 43 | @SpringBootApplication 44 | static class Config {} 45 | 46 | @Autowired EntityManager em; 47 | @Autowired ProductRepository repository; 48 | 49 | @Test 50 | public void shouldFetchAssociationMarkedAsLazyViaNamedEntityFetchGraph() { 51 | 52 | Product xps = new Product("Dell XPS 15"); 53 | Collections.addAll(xps.getTags(), new Tag("cool"), new Tag("macbook-killer"), new Tag("speed")); 54 | 55 | xps = repository.save(xps); 56 | 57 | em.flush(); 58 | em.detach(xps); 59 | 60 | Product loadedXps = repository.findOne(xps.getId()); 61 | em.detach(loadedXps); 62 | 63 | try { 64 | loadedXps.getTags().toString(); 65 | fail("Expected LazyInitializationException to occur when trying to access uninitialized association 'tags'."); 66 | } catch (Exception expected) { 67 | System.out.println(expected.getMessage()); 68 | } 69 | 70 | // Here we use the findOneById that uses a NamedEntityGraph 71 | Product loadedXpsWithFetchGraph = repository.findOneById(xps.getId()); 72 | 73 | assertThat(loadedXpsWithFetchGraph.getTags(), hasSize(3)); 74 | } 75 | 76 | @Test 77 | public void shouldFetchAssociationMarkedAsLazyViaCustomEntityFetchGraph() { 78 | 79 | Product xps = new Product("Dell XPS 15"); 80 | Collections.addAll(xps.getTags(), new Tag("cool"), new Tag("macbook-killer"), new Tag("speed")); 81 | 82 | xps = repository.save(xps); 83 | 84 | em.flush(); 85 | em.detach(xps); 86 | 87 | Product loadedXps = repository.findOne(xps.getId()); 88 | em.detach(loadedXps); 89 | 90 | try { 91 | loadedXps.getTags().toString(); 92 | fail("Expected LazyInitializationException to occur when trying to access uninitialized association 'tags'."); 93 | } catch (Exception expected) { 94 | System.out.println(expected.getMessage()); 95 | } 96 | 97 | // Here we use getOneById which uses an ad-hoc declarative fetch graph definition 98 | Product loadedXpsWithFetchGraph = repository.getOneById(xps.getId()); 99 | 100 | assertThat(loadedXpsWithFetchGraph.getTags(), hasSize(3)); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /07-jpa-entity-graph/src/test/java/example/storedprocedures/UserRepositoryIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.storedprocedures; 17 | 18 | import static org.hamcrest.CoreMatchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import example.storedprocedures.UserRepository; 22 | 23 | import javax.persistence.EntityManager; 24 | import javax.persistence.ParameterMode; 25 | import javax.persistence.StoredProcedureQuery; 26 | 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.springframework.beans.factory.annotation.Autowired; 30 | import org.springframework.boot.autoconfigure.SpringBootApplication; 31 | import org.springframework.boot.test.SpringApplicationConfiguration; 32 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 33 | import org.springframework.transaction.annotation.Transactional; 34 | 35 | /** 36 | * Intergration test showing the usage of JPA 2.1 stored procedures support through Spring Data repositories. 37 | * 38 | * @author Thomas Darimont 39 | * @author Oliver Gierke 40 | */ 41 | @RunWith(SpringJUnit4ClassRunner.class) 42 | @Transactional 43 | @SpringApplicationConfiguration 44 | public class UserRepositoryIntegrationTests { 45 | 46 | @SpringBootApplication 47 | static class Config {} 48 | 49 | @Autowired UserRepository repository; 50 | 51 | /** 52 | * @see DATAJPA-455 53 | */ 54 | @Test 55 | public void entityAnnotatedCustomNamedProcedurePlus1IO() { 56 | assertThat(repository.plus1BackedByOtherNamedStoredProcedure(1), is(2)); 57 | } 58 | 59 | /** 60 | * @see DATAJPA-455 61 | */ 62 | @Test 63 | public void invokeDerivedStoredProcedure() { 64 | assertThat(repository.plus1inout(1), is(2)); 65 | } 66 | 67 | // This is what it would look like implemented manually. 68 | 69 | @Autowired EntityManager em; 70 | 71 | @Test 72 | public void plainJpa21() { 73 | 74 | StoredProcedureQuery proc = em.createStoredProcedureQuery("plus1inout"); 75 | proc.registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN); 76 | proc.registerStoredProcedureParameter(2, Integer.class, ParameterMode.OUT); 77 | 78 | proc.setParameter(1, 1); 79 | proc.execute(); 80 | 81 | assertThat(proc.getOutputParameterValue(2), is((Object) 2)); 82 | } 83 | 84 | @Test 85 | public void plainJpa21_entityAnnotatedCustomNamedProcedurePlus1IO() { 86 | 87 | StoredProcedureQuery proc = em.createNamedStoredProcedureQuery("User.plus1"); 88 | 89 | proc.setParameter("arg", 1); 90 | proc.execute(); 91 | 92 | assertThat(proc.getOutputParameterValue("res"), is((Object) 2)); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /08-mongodb-security/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | spring-data-mongodb-security 6 | 7 | What's new in Spring Data? - MongoDB & Spring Security 8 | 9 | 10 | com.springone2gx.2015 11 | whats-new-in-spring-data 12 | 1.0.0.BUILD-SNAPSHOT 13 | ../pom.xml 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-data-mongodb 22 | 23 | 24 | 25 | de.flapdoodle.embed 26 | de.flapdoodle.embed.mongo 27 | runtime 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-security 35 | 36 | 37 | 38 | org.springframework.security 39 | spring-security-data 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /08-mongodb-security/src/main/java/example/Person.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.EqualsAndHashCode; 19 | import lombok.Getter; 20 | import lombok.RequiredArgsConstructor; 21 | 22 | import org.springframework.data.annotation.Id; 23 | 24 | /** 25 | * An entity to represent a {@link Person}. 26 | * 27 | * @author Thomas Darimont 28 | */ 29 | @Getter 30 | @EqualsAndHashCode 31 | @RequiredArgsConstructor 32 | public class Person { 33 | 34 | private @Id String id; 35 | private final String firstname; 36 | private final String lastname; 37 | } 38 | -------------------------------------------------------------------------------- /08-mongodb-security/src/main/java/example/PersonRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import java.util.List; 19 | 20 | import org.springframework.data.mongodb.repository.Query; 21 | import org.springframework.data.repository.CrudRepository; 22 | 23 | /** 24 | * Repository interface to manage {@link Person} instances. 25 | * 26 | * @author Thomas Darimont 27 | */ 28 | interface PersonRepository extends CrudRepository { 29 | 30 | // TODO: 01 - Spring security integration 31 | @Query("{ id : ?#{hasRole('ROLE_ADMIN') ? '{ $exists : true }' : principal.id }}") 32 | List findAllForCurrentUserById(); 33 | } 34 | -------------------------------------------------------------------------------- /08-mongodb-security/src/test/java/example/PersonRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.hamcrest.Matchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import java.util.List; 22 | 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | import org.springframework.beans.factory.annotation.Autowired; 27 | import org.springframework.boot.autoconfigure.SpringBootApplication; 28 | import org.springframework.boot.test.SpringApplicationConfiguration; 29 | import org.springframework.context.annotation.Bean; 30 | import org.springframework.data.repository.query.spi.EvaluationContextExtension; 31 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 32 | import org.springframework.security.core.authority.AuthorityUtils; 33 | import org.springframework.security.core.context.SecurityContextHolder; 34 | import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; 35 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 36 | 37 | /** 38 | * Integration test for {@link PersonRepository}. 39 | * 40 | * @author Thomas Darimont 41 | * @author Oliver Gierke 42 | */ 43 | @RunWith(SpringJUnit4ClassRunner.class) 44 | @SpringApplicationConfiguration 45 | public class PersonRepositoryIntegrationTest { 46 | 47 | @SpringBootApplication 48 | static class Application { 49 | 50 | @Bean 51 | public EvaluationContextExtension securityExtension() { 52 | return new SecurityEvaluationContextExtension(); 53 | } 54 | } 55 | 56 | @Autowired PersonRepository repository; 57 | 58 | Person dave, oliver, carter, admin; 59 | 60 | @Before 61 | public void setUp() { 62 | 63 | repository.deleteAll(); 64 | 65 | admin = repository.save(new Person("Admin", "Boss")); 66 | dave = repository.save(new Person("Dave", "Matthews")); 67 | oliver = repository.save(new Person("Oliver August", "Matthews")); 68 | carter = repository.save(new Person("Carter", "Beauford")); 69 | } 70 | 71 | @Test 72 | public void nonAdminCallingShouldReturnOnlyItSelfAsPerson() throws Exception { 73 | 74 | SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(dave, "x")); 75 | 76 | List persons = repository.findAllForCurrentUserById(); 77 | 78 | assertThat(persons, hasSize(1)); 79 | assertThat(persons, contains(dave)); 80 | } 81 | 82 | @Test 83 | public void adminCallingShouldReturnAllUsers() throws Exception { 84 | 85 | UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(admin, "x", AuthorityUtils.createAuthorityList("ROLE_ADMIN")); 86 | SecurityContextHolder.getContext().setAuthentication(auth); 87 | 88 | List persons = repository.findAllForCurrentUserById(); 89 | 90 | assertThat(persons, hasSize(4)); 91 | assertThat(persons, containsInAnyOrder(admin, dave, carter, oliver)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /09-mongodb-java8/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | spring-data-mongodb-java8 6 | What's new in Spring Data? - MongoDB & Java 8 7 | 8 | 9 | com.springone2gx.2015 10 | whats-new-in-spring-data 11 | 1.0.0.BUILD-SNAPSHOT 12 | ../pom.xml 13 | 14 | 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-data-mongodb 21 | 22 | 23 | 24 | de.flapdoodle.embed 25 | de.flapdoodle.embed.mongo 26 | runtime 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /09-mongodb-java8/src/main/java/example/Person.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.Data; 19 | import lombok.RequiredArgsConstructor; 20 | 21 | import org.springframework.data.annotation.Id; 22 | 23 | /** 24 | * An entity to represent a Person. 25 | * 26 | * @author Thomas Darimont 27 | */ 28 | @Data 29 | @RequiredArgsConstructor 30 | public class Person { 31 | 32 | private @Id String id; 33 | private final String firstname; 34 | private final String lastname; 35 | } 36 | -------------------------------------------------------------------------------- /09-mongodb-java8/src/main/java/example/PersonRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import java.util.List; 19 | import java.util.stream.Stream; 20 | 21 | import org.springframework.data.mongodb.repository.Query; 22 | import org.springframework.data.repository.CrudRepository; 23 | 24 | /** 25 | * Repository interface to manage {@link Person} instances. 26 | * 27 | * @author Thomas Darimont 28 | * @author Oliver Gierke 29 | */ 30 | interface PersonRepository extends CrudRepository { 31 | 32 | @Override 33 | List findAll(); 34 | 35 | @Query("{}") 36 | Stream findAllByCustomQueryWithStream(); 37 | } 38 | -------------------------------------------------------------------------------- /09-mongodb-java8/src/test/java/example/PersonRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import java.util.stream.Stream; 19 | 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | import org.junit.runner.RunWith; 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.boot.autoconfigure.SpringBootApplication; 25 | import org.springframework.boot.test.SpringApplicationConfiguration; 26 | import org.springframework.context.annotation.Bean; 27 | import org.springframework.data.mongodb.core.MongoOperations; 28 | import org.springframework.data.mongodb.core.mapping.event.LoggingEventListener; 29 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 30 | 31 | /** 32 | * Integration test for {@link PersonRepository}. 33 | * 34 | * @author Thomas Darimont 35 | * @authot Oliver Gierke 36 | */ 37 | @RunWith(SpringJUnit4ClassRunner.class) 38 | @SpringApplicationConfiguration 39 | public class PersonRepositoryIntegrationTest { 40 | 41 | @SpringBootApplication 42 | static class ApplicationConfiguration { 43 | 44 | public @Bean LoggingEventListener mongoEventListener() { 45 | return new LoggingEventListener(); 46 | } 47 | } 48 | 49 | @Autowired PersonRepository repository; 50 | @Autowired MongoOperations operations; 51 | 52 | Person dave, oliver, carter; 53 | 54 | @Before 55 | public void setUp() { 56 | 57 | repository.deleteAll(); 58 | 59 | dave = repository.save(new Person("Dave", "Matthews")); 60 | oliver = repository.save(new Person("Oliver August", "Matthews")); 61 | carter = repository.save(new Person("Carter", "Beauford")); 62 | } 63 | 64 | /** 65 | * Note that the all object conversions are performed before the results are printed to the console. 66 | */ 67 | @Test 68 | public void shouldPerformConversionBeforeResultProcessing() { 69 | repository.findAll().forEach(System.out::println); 70 | } 71 | 72 | /** 73 | * Note that the object conversions are performed during stream processing as one can see from the 74 | * {@link LoggingEventListener} output that is printed to the console. 75 | */ 76 | @Test 77 | public void shouldPerformConversionDuringJava8StreamProcessing() { 78 | 79 | // TODO: 01 - Support for Streams 80 | 81 | try (Stream result = repository.findAllByCustomQueryWithStream()) { 82 | result.forEach(System.out::println); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /10-rest-headers/README.adoc: -------------------------------------------------------------------------------- 1 | = Spring Data REST - Headers example 2 | 3 | This example shows how Spring Data REST auto-populates response headers for item resources and considers these values when conditional `GET` requests are used 4 | 5 | == Auto-populated headers 6 | 7 | If entities use optimistic locking (usually by demarcating a particular property as version property using a store-specific annotation), Spring Data REST will use the value stored in that property to populate the `ETag` header for `GET` and `HEAD` requests to the item resource. 8 | 9 | If http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#auditing[Spring Data's auditing capabilities] are activated (using `@EnableJpaAuditing` in this case), the `Last-Modified` header is populated with the value of the last-modified property. See the `Customer` domain class for how to mark those. 10 | 11 | == Conditional GET requests 12 | 13 | The response headers can be used to issue conditional GET requests to save bandwidth in case the resource hasn't changed on the server: 14 | 15 | .Conditional GET using If-Modified-Since 16 | ==== 17 | [source,bash] 18 | ---- 19 | $ curl http://localhost:8080/customers/1 -i -H "If-Modified-Since: Wed, 08 Apr 2015 17:24:20 GMT" 20 | ---- 21 | 22 | [source,http] 23 | ---- 24 | HTTP/1.1 304 Not Modified 25 | ---- 26 | ==== 27 | 28 | .Conditional GET using If-None-Match 29 | ==== 30 | [source,bash] 31 | ---- 32 | $ curl http://localhost:8080/customers/1 -i -H "If-None-Match: 0" 33 | ---- 34 | 35 | [source,http] 36 | ---- 37 | HTTP/1.1 304 Not Modified 38 | ---- 39 | ==== 40 | 41 | == Spring RESTDocs 42 | 43 | The sample uses https://github.com/wilkinsona/spring-restdocs[Spring RESTDocs] to document the HTTP interaction implemented using the test cases. See `WebIntegrationTests.setUp()` for general setup and the individual test methods with their usage of `….andDo(document(…))`. -------------------------------------------------------------------------------- /10-rest-headers/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | spring-data-rest-headers 6 | 7 | What's new in Spring Data? - REST headers 8 | 9 | 10 | com.springone2gx.2015 11 | whats-new-in-spring-data 12 | 1.0.0.BUILD-SNAPSHOT 13 | ../pom.xml 14 | 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-data-jpa 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-rest 26 | 27 | 28 | 29 | com.fasterxml.jackson.datatype 30 | jackson-datatype-jsr310 31 | 32 | 33 | 34 | org.hsqldb 35 | hsqldb 36 | runtime 37 | 38 | 39 | 40 | org.springframework.restdocs 41 | spring-restdocs 42 | 1.0.0.M1 43 | test 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /10-rest-headers/src/main/java/example/Address.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.AccessLevel; 19 | import lombok.Data; 20 | import lombok.NoArgsConstructor; 21 | import lombok.RequiredArgsConstructor; 22 | 23 | import javax.persistence.Entity; 24 | import javax.persistence.GeneratedValue; 25 | import javax.persistence.Id; 26 | 27 | /** 28 | * @author Oliver Gierke 29 | */ 30 | @Entity 31 | @Data 32 | @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) 33 | @RequiredArgsConstructor 34 | public class Address { 35 | 36 | private @GeneratedValue @Id Long id; 37 | private final String street, zipCode, city, state; 38 | 39 | /* 40 | * (non-Javadoc) 41 | * @see java.lang.Object#toString() 42 | */ 43 | public String toString() { 44 | return String.format("%s, %s %s, %s", street, zipCode, city, state); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /10-rest-headers/src/main/java/example/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import example.Customer.Gender; 19 | 20 | import javax.annotation.PostConstruct; 21 | 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.SpringApplication; 24 | import org.springframework.boot.autoconfigure.SpringBootApplication; 25 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 26 | 27 | /** 28 | * @author Oliver Gierke 29 | * @soundtrack The Intersphere - Out of phase (Live at Alte Feuerwache Mannheim) 30 | */ 31 | @EnableJpaAuditing 32 | @SpringBootApplication 33 | public class Application { 34 | 35 | public static void main(String... args) { 36 | SpringApplication.run(Application.class, args); 37 | } 38 | 39 | @Autowired CustomerRepository customers; 40 | 41 | @PostConstruct 42 | public void init() { 43 | customers.save(new Customer("Dave", "Matthews", Gender.MALE, // 44 | new Address("4711 Some Place", "54321", "Charlottesville", "VA"))); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /10-rest-headers/src/main/java/example/Customer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.AccessLevel; 19 | import lombok.Data; 20 | import lombok.NoArgsConstructor; 21 | import lombok.RequiredArgsConstructor; 22 | 23 | import java.time.LocalDateTime; 24 | 25 | import javax.persistence.CascadeType; 26 | import javax.persistence.Entity; 27 | import javax.persistence.EntityListeners; 28 | import javax.persistence.GeneratedValue; 29 | import javax.persistence.Id; 30 | import javax.persistence.OneToOne; 31 | import javax.persistence.Version; 32 | 33 | import org.springframework.data.annotation.LastModifiedDate; 34 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 35 | 36 | import com.fasterxml.jackson.annotation.JsonIgnore; 37 | 38 | /** 39 | * Aggregate root representing a customer. 40 | * 41 | * @author Oliver Gierke 42 | * @soundtrack The Intersphere - Out of phase (Live at Alte Feuerwache Mannheim) 43 | */ 44 | @Entity 45 | @Data 46 | @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) 47 | @RequiredArgsConstructor 48 | @EntityListeners(AuditingEntityListener.class) 49 | public class Customer { 50 | 51 | private @GeneratedValue @Id Long id; 52 | 53 | // TODO: 01 - ETag / Last modified date into headers 54 | private @Version Long version; 55 | private @JsonIgnore @LastModifiedDate LocalDateTime lastModifiedDate; 56 | 57 | private final String firstname, lastname; 58 | private final Gender gender; 59 | 60 | @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) // 61 | private final Address address; 62 | 63 | static enum Gender { 64 | MALE, FEMALE; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /10-rest-headers/src/main/java/example/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import org.springframework.data.repository.CrudRepository; 19 | 20 | /** 21 | * Spring Data repository interface to manage {@link Customer} instances. 22 | * 23 | * @author Oliver Gierke 24 | * @soundtrack The Intersphere - Out of phase (Live at Alte Feuerwache Mannheim) 25 | */ 26 | public interface CustomerRepository extends CrudRepository {} 27 | -------------------------------------------------------------------------------- /10-rest-headers/src/test/java/example/ApplicationIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.hamcrest.Matchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import example.Application; 22 | import example.Customer; 23 | import example.CustomerRepository; 24 | 25 | import org.junit.Test; 26 | import org.junit.runner.RunWith; 27 | import org.springframework.beans.factory.annotation.Autowired; 28 | import org.springframework.boot.test.SpringApplicationConfiguration; 29 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 30 | 31 | /** 32 | * Integration tests to bootstrap the application. 33 | * 34 | * @author Oliver Gierke 35 | * @soundtrack The Intersphere - Out of phase (Live at Alte Feuerwache Mannheim) 36 | */ 37 | @RunWith(SpringJUnit4ClassRunner.class) 38 | @SpringApplicationConfiguration(classes = Application.class) 39 | public class ApplicationIntegrationTests { 40 | 41 | @Autowired CustomerRepository repository; 42 | 43 | @Test 44 | public void initializesRepositoryWithSampleData() { 45 | 46 | Iterable result = repository.findAll(); 47 | 48 | assertThat(result, is(iterableWithSize(1))); 49 | assertThat(result.iterator().next().getLastModifiedDate(), is(notNullValue())); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /10-rest-headers/src/test/java/example/WebIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.hamcrest.CoreMatchers.*; 19 | import static org.springframework.http.HttpHeaders.*; 20 | import static org.springframework.restdocs.RestDocumentation.*; 21 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 22 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 23 | 24 | import java.net.URI; 25 | 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.springframework.beans.factory.annotation.Autowired; 30 | import org.springframework.boot.test.SpringApplicationConfiguration; 31 | import org.springframework.mock.web.MockHttpServletResponse; 32 | import org.springframework.restdocs.config.RestDocumentationConfigurer; 33 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 34 | import org.springframework.test.context.web.WebAppConfiguration; 35 | import org.springframework.test.web.servlet.MockMvc; 36 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 37 | import org.springframework.web.context.WebApplicationContext; 38 | import org.springframework.web.util.UriTemplate; 39 | 40 | /** 41 | * @author Oliver Gierke 42 | * @soundtrack The Intersphere - Out of phase (Live at Alte Feuerwache Mannheim) 43 | */ 44 | @RunWith(SpringJUnit4ClassRunner.class) 45 | @WebAppConfiguration 46 | @SpringApplicationConfiguration(classes = Application.class) 47 | public class WebIntegrationTests { 48 | 49 | @Autowired WebApplicationContext context; 50 | @Autowired CustomerRepository customers; 51 | 52 | MockMvc mvc; 53 | 54 | @Before 55 | public void setUp() { 56 | 57 | this.mvc = MockMvcBuilders.webAppContextSetup(context).// 58 | apply(new RestDocumentationConfigurer()).// 59 | build(); 60 | } 61 | 62 | @Test 63 | public void executeConditionalGetRequests() throws Exception { 64 | 65 | // TODO: 02 - Executing conditional requests 66 | 67 | Customer customer = customers.findAll().iterator().next(); 68 | URI uri = new UriTemplate("/customers/{id}").expand(customer.getId()); 69 | 70 | MockHttpServletResponse response = mvc.perform(get(uri)).// 71 | andExpect(header().string(ETAG, is(notNullValue()))).// 72 | andExpect(header().string(LAST_MODIFIED, is(notNullValue()))).// 73 | andReturn().getResponse(); 74 | 75 | // ETag-based 76 | 77 | response = mvc.perform(get(uri).header(IF_NONE_MATCH, response.getHeader(ETAG))).// 78 | andExpect(status().isNotModified()).// 79 | andExpect(header().string(ETAG, is(notNullValue()))).// 80 | andExpect(header().string(LAST_MODIFIED, is(notNullValue()))).// 81 | andDo(document("if-none-match")).// 82 | andReturn().getResponse(); 83 | 84 | // Last-modified-based 85 | 86 | mvc.perform(get(uri).header(IF_MODIFIED_SINCE, response.getHeader(LAST_MODIFIED))).// 87 | andExpect(status().isNotModified()).// 88 | andExpect(header().string(ETAG, is(notNullValue()))).// 89 | andExpect(header().string(LAST_MODIFIED, is(notNullValue()))).// 90 | andDo(document("if-modified-since")); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /10-rest-headers/src/test/resources/documentation.properties: -------------------------------------------------------------------------------- 1 | org.springframework.restdocs.outputDir=target/generated-snippets -------------------------------------------------------------------------------- /11-rest-hal-browser/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | spring-data-rest-hal-browser 6 | 7 | What's new in Spring Data? - HAL browser & Querydsl 8 | 9 | 10 | com.springone2gx.2015 11 | whats-new-in-spring-data 12 | 1.0.0.BUILD-SNAPSHOT 13 | ../pom.xml 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-mongodb 23 | 24 | 25 | 26 | de.flapdoodle.embed 27 | de.flapdoodle.embed.mongo 28 | runtime 29 | 30 | 31 | 32 | com.querydsl 33 | querydsl-mongodb 34 | ${querydsl.version} 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.data 41 | spring-data-rest-webmvc 42 | 43 | 44 | 45 | org.springframework.data 46 | spring-data-rest-hal-browser 47 | runtime 48 | 49 | 50 | 51 | org.springframework.batch 52 | spring-batch-core 53 | 54 | 55 | 56 | com.jayway.jsonpath 57 | json-path 58 | runtime 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-starter-thymeleaf 66 | runtime 67 | 68 | 69 | 70 | org.webjars 71 | jquery 72 | 2.1.3 73 | runtime 74 | 75 | 76 | 77 | org.webjars 78 | bootstrap 79 | 3.3.4 80 | runtime 81 | 82 | 83 | 84 | org.webjars 85 | URI.js 86 | 1.14.1 87 | runtime 88 | 89 | 90 | 91 | org.webjars 92 | webjars-locator 93 | 0.22 94 | runtime 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | org.springframework.boot 103 | spring-boot-maven-plugin 104 | 105 | 106 | com.mysema.maven 107 | apt-maven-plugin 108 | ${apt.version} 109 | 110 | 111 | com.querydsl 112 | querydsl-apt 113 | ${querydsl.version} 114 | 115 | 116 | 117 | 118 | generate-sources 119 | 120 | process 121 | 122 | 123 | target/generated-sources/annotations 124 | org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor 125 | true 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /11-rest-hal-browser/src/main/java/example/Address.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.springframework.data.mongodb.core.index.GeoSpatialIndexType.*; 19 | 20 | import lombok.AccessLevel; 21 | import lombok.NoArgsConstructor; 22 | import lombok.RequiredArgsConstructor; 23 | import lombok.Value; 24 | 25 | import org.springframework.data.geo.Point; 26 | import org.springframework.data.mongodb.core.index.GeoSpatialIndexed; 27 | 28 | /** 29 | * Value object to represent an {@link Address}. 30 | * 31 | * @author Oliver Gierke 32 | */ 33 | @Value 34 | @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) 35 | @RequiredArgsConstructor 36 | public class Address { 37 | 38 | private final String street, city, zip; 39 | private final @GeoSpatialIndexed(type = GEO_2DSPHERE) Point location; 40 | 41 | /* 42 | * (non-Javadoc) 43 | * @see java.lang.Object#toString() 44 | */ 45 | public String toString() { 46 | return String.format("%s, %s %s", street, zip, city); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /11-rest-hal-browser/src/main/java/example/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import org.springframework.boot.SpringApplication; 19 | import org.springframework.boot.autoconfigure.SpringBootApplication; 20 | 21 | /** 22 | * Spring configuration class main application bootstrap point. 23 | * 24 | * @author Oliver Gierke 25 | */ 26 | @SpringBootApplication 27 | public class Application { 28 | 29 | public static void main(String[] args) { 30 | SpringApplication.run(Application.class, args); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /11-rest-hal-browser/src/main/java/example/Store.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.Data; 19 | 20 | import org.springframework.data.annotation.Id; 21 | import org.springframework.data.mongodb.core.mapping.Document; 22 | 23 | /** 24 | * Entity to represent a {@link Store}. 25 | * 26 | * @author Oliver Gierke 27 | */ 28 | @Data 29 | @Document 30 | public class Store { 31 | 32 | private final @Id String id; 33 | private final String name; 34 | private final Address address; 35 | 36 | public Store(String name, Address address) { 37 | 38 | this.name = name; 39 | this.address = address; 40 | this.id = null; 41 | } 42 | 43 | protected Store() { 44 | 45 | this.id = null; 46 | this.name = null; 47 | this.address = null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /11-rest-hal-browser/src/main/java/example/StoreInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.Scanner; 21 | 22 | import lombok.extern.slf4j.Slf4j; 23 | 24 | import org.springframework.batch.item.ExecutionContext; 25 | import org.springframework.batch.item.file.FlatFileItemReader; 26 | import org.springframework.batch.item.file.mapping.DefaultLineMapper; 27 | import org.springframework.batch.item.file.separator.DefaultRecordSeparatorPolicy; 28 | import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; 29 | import org.springframework.beans.factory.annotation.Autowired; 30 | import org.springframework.core.io.ClassPathResource; 31 | import org.springframework.data.geo.Point; 32 | import org.springframework.data.mongodb.core.MongoOperations; 33 | import org.springframework.stereotype.Component; 34 | 35 | /** 36 | * Component initializing a hand full of Starbucks stores and persisting them through a {@link StoreRepository}. 37 | * 38 | * @author Oliver Gierke 39 | */ 40 | @Slf4j 41 | @Component 42 | public class StoreInitializer { 43 | 44 | @Autowired 45 | public StoreInitializer(StoreRepository repository, MongoOperations operations) throws Exception { 46 | 47 | if (repository.count() != 0) { 48 | return; 49 | } 50 | 51 | List stores = readStores(); 52 | log.info("Importing {} stores into MongoDB…", stores.size()); 53 | repository.save(stores); 54 | log.info("Successfully imported {} stores.", repository.count()); 55 | } 56 | 57 | /** 58 | * Reads a file {@code starbucks.csv} from the class path and parses it into {@link Store} instances about to 59 | * persisted. 60 | * 61 | * @return 62 | * @throws Exception 63 | */ 64 | public static List readStores() throws Exception { 65 | 66 | ClassPathResource resource = new ClassPathResource("starbucks.csv"); 67 | Scanner scanner = new Scanner(resource.getInputStream()); 68 | String line = scanner.nextLine(); 69 | scanner.close(); 70 | 71 | FlatFileItemReader itemReader = new FlatFileItemReader(); 72 | itemReader.setResource(resource); 73 | 74 | // DelimitedLineTokenizer defaults to comma as its delimiter 75 | DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(); 76 | tokenizer.setNames(line.split(",")); 77 | tokenizer.setStrict(false); 78 | 79 | DefaultLineMapper lineMapper = new DefaultLineMapper(); 80 | lineMapper.setFieldSetMapper(fields -> { 81 | 82 | Point location = new Point(fields.readDouble("Longitude"), fields.readDouble("Latitude")); 83 | Address address = new Address(fields.readString("Street Address"), fields.readString("City"), fields 84 | .readString("Zip"), location); 85 | 86 | return new Store(fields.readString("Name"), address); 87 | }); 88 | 89 | lineMapper.setLineTokenizer(tokenizer); 90 | itemReader.setLineMapper(lineMapper); 91 | itemReader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy()); 92 | itemReader.setLinesToSkip(1); 93 | itemReader.open(new ExecutionContext()); 94 | 95 | List stores = new ArrayList<>(); 96 | Store store = null; 97 | 98 | do { 99 | 100 | store = itemReader.read(); 101 | 102 | if (store != null) { 103 | stores.add(store); 104 | } 105 | 106 | } while (store != null); 107 | 108 | return stores; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /11-rest-hal-browser/src/main/java/example/StoreRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import org.springframework.data.domain.Page; 19 | import org.springframework.data.domain.Pageable; 20 | import org.springframework.data.geo.Distance; 21 | import org.springframework.data.geo.Point; 22 | import org.springframework.data.querydsl.QueryDslPredicateExecutor; 23 | import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer; 24 | import org.springframework.data.querydsl.binding.QuerydslBindings; 25 | import org.springframework.data.repository.PagingAndSortingRepository; 26 | import org.springframework.data.repository.query.Param; 27 | import org.springframework.data.rest.core.annotation.RestResource; 28 | 29 | import com.querydsl.core.types.dsl.StringPath; 30 | 31 | /** 32 | * Repository interface for out-of-the-box paginating access to {@link Store}s and a query method to find stores by 33 | * location and distance. 34 | * 35 | * @author Oliver Gierke 36 | * @author Thomas Darimont 37 | */ 38 | public interface StoreRepository extends PagingAndSortingRepository, QueryDslPredicateExecutor, 39 | QuerydslBinderCustomizer { 40 | 41 | @RestResource(rel = "by-location") 42 | Page findByAddressLocationNear(@Param("location") Point location, @Param("distance") Distance distance, 43 | Pageable pageable); 44 | 45 | /** 46 | * Tweak the Querydsl binding if collection resources are filtered. 47 | * 48 | * @see org.springframework.data.web.querydsl.QuerydslBinderCustomizer#customize(org.springframework.data.web.querydsl.QuerydslBindings, 49 | * com.mysema.query.types.EntityPath) 50 | */ 51 | default void customize(QuerydslBindings bindings, QStore store) { 52 | 53 | bindings.bind(store.address.city).first((path, value) -> path.endsWith(value)); 54 | bindings.bind(String.class).first((StringPath path, String value) -> path.contains(value)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /11-rest-hal-browser/src/main/java/example/WebConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import org.springframework.context.annotation.Bean; 19 | import org.springframework.context.annotation.Configuration; 20 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 21 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 22 | import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; 23 | 24 | /** 25 | * Temporarily required manual configuration of resource handling to activate the resource chain handling. 26 | * 27 | * @author Brian Clozel 28 | */ 29 | @Configuration 30 | public class WebConfig extends WebMvcConfigurerAdapter { 31 | 32 | @Override 33 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 34 | registry.addResourceHandler("/webjars/**").// 35 | addResourceLocations("classpath:/META-INF/resources/webjars/").// 36 | resourceChain(true); 37 | } 38 | 39 | @Bean 40 | public ResourceUrlEncodingFilter resourceUrlEncodingFilter() { 41 | return new ResourceUrlEncodingFilter(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /11-rest-hal-browser/src/main/java/example/web/StoresController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example.web; 17 | 18 | import static org.springframework.data.geo.Metrics.*; 19 | 20 | import example.Store; 21 | import example.StoreRepository; 22 | 23 | import java.util.Arrays; 24 | import java.util.Collections; 25 | import java.util.HashMap; 26 | import java.util.List; 27 | import java.util.Map; 28 | import java.util.Optional; 29 | 30 | import lombok.RequiredArgsConstructor; 31 | 32 | import org.springframework.beans.factory.annotation.Autowired; 33 | import org.springframework.data.domain.Page; 34 | import org.springframework.data.domain.Pageable; 35 | import org.springframework.data.geo.Distance; 36 | import org.springframework.data.geo.Metrics; 37 | import org.springframework.data.geo.Point; 38 | import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks; 39 | import org.springframework.stereotype.Controller; 40 | import org.springframework.ui.Model; 41 | import org.springframework.web.bind.annotation.RequestMapping; 42 | import org.springframework.web.bind.annotation.RequestMethod; 43 | import org.springframework.web.bind.annotation.RequestParam; 44 | 45 | /** 46 | * A Spring MVC controller to produce an HTML frontend. 47 | * 48 | * @author Oliver Gierke 49 | */ 50 | @Controller 51 | @RequiredArgsConstructor(onConstructor = @__(@Autowired)) 52 | class StoresController { 53 | 54 | private static final List DISTANCES = Arrays.asList(new Distance(0.5, MILES), new Distance(1, MILES), 55 | new Distance(2, MILES)); 56 | private static final Distance DEFAULT_DISTANCE = new Distance(1, Metrics.MILES); 57 | private static final Map KNOWN_LOCATIONS; 58 | 59 | static { 60 | 61 | Map locations = new HashMap<>(); 62 | 63 | locations.put("Pivotal SF", new Point(-122.4041764, 37.7819286)); 64 | locations.put("Timesquare NY", new Point(-73.995146, 40.740337)); 65 | 66 | KNOWN_LOCATIONS = Collections.unmodifiableMap(locations); 67 | } 68 | 69 | private final StoreRepository repository; 70 | private final RepositoryEntityLinks entityLinks; 71 | 72 | /** 73 | * Looks up the stores in the given distance around the given location. 74 | * 75 | * @param model the {@link Model} to populate. 76 | * @param location the optional location, if none is given, no search results will be returned. 77 | * @param distance the distance to use, if none is given the {@link #DEFAULT_DISTANCE} is used. 78 | * @param pageable the pagination information 79 | * @return 80 | */ 81 | @RequestMapping(value = "/", method = RequestMethod.GET) 82 | String index(Model model, @RequestParam Optional location, @RequestParam Optional distance, 83 | Pageable pageable) { 84 | 85 | Point point = location.orElse(KNOWN_LOCATIONS.get("Timesquare NY")); 86 | 87 | Page stores = repository.findByAddressLocationNear(point, distance.orElse(DEFAULT_DISTANCE), pageable); 88 | 89 | model.addAttribute("stores", stores); 90 | model.addAttribute("distances", DISTANCES); 91 | model.addAttribute("selectedDistance", distance.orElse(DEFAULT_DISTANCE)); 92 | model.addAttribute("location", point); 93 | model.addAttribute("locations", KNOWN_LOCATIONS); 94 | model.addAttribute("api", entityLinks.linkToSearchResource(Store.class, "by-location", pageable).getHref()); 95 | 96 | return "index"; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /11-rest-hal-browser/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.data.rest.base-path=/api 2 | spring.thymeleaf.cache=false -------------------------------------------------------------------------------- /11-rest-hal-browser/src/main/resources/static/img/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springone2gx2015/whats-new-in-spring-data/fa8570b6d44335bee21a54245477965bc7ac12ea/11-rest-hal-browser/src/main/resources/static/img/map.png -------------------------------------------------------------------------------- /11-rest-hal-browser/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Starbucks Storefinder 5 | 6 | 7 | 8 | 9 | 11 | 12 | 21 | 22 | 23 | 24 | 25 |
26 | 27 |

Starbucks Storefinder

28 | 29 |
30 |
31 |

Search

32 |
33 |
34 | 35 |
36 | 37 |
38 | 40 |
41 | Foo 44 |
45 |
46 | 47 |
48 | 49 |
50 | 52 |
53 |
54 | 55 | 56 |
57 | 58 |
59 | 65 |
66 |
67 | 68 |
69 |
70 | 71 |
72 |
73 | 74 |
75 |
76 |
77 | 78 |
79 | 80 |
81 |

Results

82 |
83 | 84 |
85 | 86 |
87 | 88 |
89 |
90 |

Found 92 | 1 results.

93 |
    94 |
  1. Store 96 | name
  2. 97 |
98 |
99 |

No Results

101 |
102 | 103 |
104 | 105 |
106 |
107 | 108 | 110 | 111 | 113 | 114 | 115 | 116 | 118 | 119 | 204 | 205 | -------------------------------------------------------------------------------- /11-rest-hal-browser/src/test/java/example/StarbucksClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.springframework.hateoas.MediaTypes.*; 19 | 20 | import java.net.URI; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | import java.util.stream.StreamSupport; 24 | 25 | import lombok.extern.slf4j.Slf4j; 26 | 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.springframework.beans.factory.annotation.Autowired; 30 | import org.springframework.beans.factory.annotation.Value; 31 | import org.springframework.boot.autoconfigure.SpringBootApplication; 32 | import org.springframework.boot.test.SpringApplicationConfiguration; 33 | import org.springframework.boot.test.WebIntegrationTest; 34 | import org.springframework.context.annotation.Bean; 35 | import org.springframework.hateoas.Link; 36 | import org.springframework.hateoas.Links; 37 | import org.springframework.hateoas.MediaTypes; 38 | import org.springframework.hateoas.PagedResources; 39 | import org.springframework.hateoas.PagedResources.PageMetadata; 40 | import org.springframework.hateoas.Resource; 41 | import org.springframework.hateoas.Resources; 42 | import org.springframework.hateoas.client.Traverson; 43 | import org.springframework.hateoas.client.Traverson.TraversalBuilder; 44 | import org.springframework.hateoas.mvc.TypeReferences.PagedResourcesType; 45 | import org.springframework.hateoas.mvc.TypeReferences.ResourceType; 46 | import org.springframework.hateoas.mvc.TypeReferences.ResourcesType; 47 | import org.springframework.http.RequestEntity; 48 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 49 | import org.springframework.web.client.RestOperations; 50 | import org.springframework.web.client.RestTemplate; 51 | 52 | /** 53 | * A test case to discover the search resource and execute a predefined search with it. 54 | * 55 | * @author Oliver Gierke 56 | */ 57 | @RunWith(SpringJUnit4ClassRunner.class) 58 | @WebIntegrationTest(randomPort = true) 59 | @SpringApplicationConfiguration 60 | @Slf4j 61 | public class StarbucksClient { 62 | 63 | @SpringBootApplication 64 | static class Config { 65 | 66 | @Bean 67 | public RestTemplate restTemplate() { 68 | return new RestTemplate(); 69 | } 70 | } 71 | 72 | @Value("${local.server.port}") String port; 73 | 74 | private static final String SERVICE_URI = "http://localhost:%s/api"; 75 | 76 | @Test 77 | public void discoverStoreSearch() { 78 | 79 | Traverson traverson = new Traverson(URI.create(String.format(SERVICE_URI, port)), MediaTypes.HAL_JSON); 80 | 81 | // Set up path traversal 82 | TraversalBuilder builder = traverson. // 83 | follow("stores", "search", "by-location"); 84 | 85 | // Log discovered 86 | log.info(""); 87 | log.info("Discovered link: {}", builder.asTemplatedLink()); 88 | log.info(""); 89 | 90 | Map parameters = new HashMap<>(); 91 | parameters.put("location", "40.740337,-73.995146"); 92 | parameters.put("distance", "0.5miles"); 93 | 94 | PagedResources> resources = builder.// 95 | withTemplateParameters(parameters).// 96 | toObject(new PagedResourcesType>() {}); 97 | 98 | PageMetadata metadata = resources.getMetadata(); 99 | 100 | log.info("Got {} of {} stores: ", resources.getContent().size(), metadata.getTotalElements()); 101 | 102 | StreamSupport.stream(resources.spliterator(), false).// 103 | map(Resource::getContent).// 104 | forEach(store -> log.info("{} - {}", store.name, store.address)); 105 | } 106 | 107 | @Autowired RestOperations restOperations; 108 | 109 | @Test 110 | public void accessServiceUsingRestTemplate() { 111 | 112 | // Access root resource 113 | 114 | URI uri = URI.create(String.format(SERVICE_URI, port)); 115 | RequestEntity request = RequestEntity.get(uri).accept(HAL_JSON).build(); 116 | Resource rootLinks = restOperations.exchange(request, new ResourceType() {}).getBody(); 117 | Links links = new Links(rootLinks.getLinks()); 118 | 119 | // Follow stores link 120 | 121 | Link storesLink = links.getLink("stores").expand(); 122 | request = RequestEntity.get(URI.create(storesLink.getHref())).accept(HAL_JSON).build(); 123 | Resources stores = restOperations.exchange(request, new ResourcesType() {}).getBody(); 124 | 125 | stores.getContent().forEach(store -> log.info("{} - {}", store.name, store.address)); 126 | } 127 | 128 | static class Store { 129 | 130 | public String name; 131 | public Address address; 132 | 133 | static class Address { 134 | 135 | public String city, zip, street; 136 | public Location location; 137 | 138 | @Override 139 | public String toString() { 140 | return String.format("%s, %s %s - lat: %s, long: %s", street, zip, city, location.y, location.x); 141 | } 142 | 143 | static class Location { 144 | public double x, y; 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /11-rest-hal-browser/src/test/java/example/StoreRepositoryIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.hamcrest.Matchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import example.Address; 22 | import example.Store; 23 | import example.Application; 24 | import example.StoreRepository; 25 | 26 | import org.junit.After; 27 | import org.junit.Before; 28 | import org.junit.Test; 29 | import org.junit.runner.RunWith; 30 | import org.springframework.beans.factory.annotation.Autowired; 31 | import org.springframework.boot.test.SpringApplicationConfiguration; 32 | import org.springframework.data.domain.Page; 33 | import org.springframework.data.domain.PageRequest; 34 | import org.springframework.data.geo.Distance; 35 | import org.springframework.data.geo.Metrics; 36 | import org.springframework.data.geo.Point; 37 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 38 | import org.springframework.test.context.web.WebAppConfiguration; 39 | 40 | /** 41 | * Integration tests for {@link StoreRepository}. 42 | * 43 | * @author Oliver Gierke 44 | */ 45 | @RunWith(SpringJUnit4ClassRunner.class) 46 | @WebAppConfiguration 47 | @SpringApplicationConfiguration(classes = Application.class) 48 | public class StoreRepositoryIntegrationTests { 49 | 50 | @Autowired StoreRepository repository; 51 | 52 | @Before 53 | @After 54 | public void clearDb() { 55 | repository.deleteAll(); 56 | } 57 | 58 | @Test 59 | public void findsStoresByLocation() { 60 | 61 | Point location = new Point(-73.995146, 40.740337); 62 | Store store = new Store("Foo", new Address("street", "city", "zip", location)); 63 | 64 | store = repository.save(store); 65 | 66 | Page stores = repository.findByAddressLocationNear(location, new Distance(1.0, Metrics.KILOMETERS), 67 | new PageRequest(0, 10)); 68 | 69 | assertThat(stores.getContent(), hasSize(1)); 70 | assertThat(stores.getContent(), hasItem(store)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /11-rest-hal-browser/webui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springone2gx2015/whats-new-in-spring-data/fa8570b6d44335bee21a54245477965bc7ac12ea/11-rest-hal-browser/webui.png -------------------------------------------------------------------------------- /12-redis/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /12-redis/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | spring-data-redis-demo 6 | 7 | What's new in Spring Data? - Redis 8 | 9 | 10 | com.springone2gx.2015 11 | whats-new-in-spring-data 12 | 1.0.0.BUILD-SNAPSHOT 13 | 14 | 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-data-redis 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | com.github.kstyrc 37 | embedded-redis 38 | 0.6 39 | test 40 | 41 | 42 | 43 | com.fasterxml.jackson.core 44 | jackson-databind 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /12-redis/src/main/java/example/Vehicle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.Data; 19 | 20 | /** 21 | * @author Thomas Darimont 22 | * @author Oliver Gierke 23 | */ 24 | @Data 25 | public class Vehicle { 26 | 27 | String brand; 28 | 29 | static class Car extends Vehicle {} 30 | 31 | static class Truck extends Vehicle {} 32 | } 33 | -------------------------------------------------------------------------------- /12-redis/src/test/java/example/ObjectSerializationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.hamcrest.CoreMatchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import example.Vehicle.Car; 22 | import example.Vehicle.Truck; 23 | import redis.embedded.RedisServer; 24 | 25 | import org.junit.After; 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.springframework.beans.factory.annotation.Autowired; 30 | import org.springframework.boot.test.SpringApplicationConfiguration; 31 | import org.springframework.context.annotation.Bean; 32 | import org.springframework.context.annotation.Configuration; 33 | import org.springframework.data.redis.connection.RedisConnectionFactory; 34 | import org.springframework.data.redis.core.RedisOperations; 35 | import org.springframework.data.redis.core.RedisTemplate; 36 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 37 | import org.springframework.data.redis.serializer.StringRedisSerializer; 38 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 39 | 40 | /** 41 | * @author Thomas Darimont 42 | */ 43 | @RunWith(SpringJUnit4ClassRunner.class) 44 | @SpringApplicationConfiguration({ RedisTestConfiguration.class, ObjectSerializationTests.Config.class }) 45 | public class ObjectSerializationTests { 46 | 47 | private RedisServer redisServer; 48 | 49 | @Autowired private RedisOperations redis; 50 | 51 | @Configuration 52 | static class Config { 53 | 54 | @Bean(name = "redisTemplate") 55 | RedisOperations genericRedisTemplate(RedisConnectionFactory rcf) { 56 | 57 | RedisTemplate rt = new RedisTemplate(); 58 | rt.setConnectionFactory(rcf); 59 | rt.setKeySerializer(new StringRedisSerializer()); 60 | 61 | // Fixed to Vehicle type - no type information carried to Redis 62 | // rt.setValueSerializer(new Jackson2JsonRedisSerializer<>(Vehicle.class)); 63 | 64 | // Type is store in Redis 65 | rt.setValueSerializer(new GenericJackson2JsonRedisSerializer()); 66 | 67 | return rt; 68 | } 69 | } 70 | 71 | @Before 72 | public void setup() throws Exception { 73 | 74 | redisServer = new RedisServer(6379); 75 | redisServer.start(); 76 | } 77 | 78 | @After 79 | public void teardown() { 80 | redisServer.stop(); 81 | } 82 | 83 | @Test 84 | public void readWrite() { 85 | 86 | // monitor commands sent to redis via redis-cli > monitor 87 | 88 | Car car = new Car(); 89 | car.setBrand("Porsche"); 90 | 91 | Truck truck = new Truck(); 92 | truck.setBrand("MAN"); 93 | 94 | redis.opsForValue().set("v1", car); 95 | redis.opsForValue().set("v2", truck); 96 | 97 | Object v1 = redis.opsForValue().get("v1"); 98 | Object v2 = redis.opsForValue().get("v2"); 99 | 100 | assertThat(v1, is(car)); 101 | assertThat(v2, is(truck)); 102 | 103 | assertThat(v1, is(instanceOf(Car.class))); 104 | assertThat(v2, is(instanceOf(Truck.class))); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /12-redis/src/test/java/example/RedisOperationsTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import redis.embedded.RedisServer; 19 | 20 | import org.junit.After; 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | import org.junit.runner.RunWith; 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.boot.test.SpringApplicationConfiguration; 26 | import org.springframework.data.redis.connection.RedisConnection; 27 | import org.springframework.data.redis.connection.RedisConnectionFactory; 28 | import org.springframework.data.redis.connection.RedisZSetCommands.Range; 29 | import org.springframework.data.redis.core.BoundZSetOperations; 30 | import org.springframework.data.redis.core.RedisOperations; 31 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 32 | 33 | /** 34 | * @author Thomas Darimont 35 | */ 36 | @RunWith(SpringJUnit4ClassRunner.class) 37 | @SpringApplicationConfiguration(RedisTestConfiguration.class) 38 | public class RedisOperationsTests { 39 | 40 | RedisServer redisServer; 41 | 42 | @Autowired RedisConnectionFactory redisConnectionFactory; 43 | @Autowired RedisOperations redis; 44 | 45 | @Before 46 | public void setup() throws Exception { 47 | 48 | redisServer = new RedisServer(6379); 49 | redisServer.start(); 50 | } 51 | 52 | @After 53 | public void teardown() { 54 | redisServer.stop(); 55 | } 56 | 57 | @Test 58 | public void zrangeByLex() { 59 | 60 | BoundZSetOperations zsets = redis.boundZSetOps("myzset"); 61 | 62 | zsets.add("a", 0.0); 63 | zsets.add("b", 0.0); 64 | zsets.add("c", 0.0); 65 | zsets.add("d", 0.0); 66 | zsets.add("e", 0.0); 67 | zsets.add("f", 0.0); 68 | zsets.add("g", 0.0); 69 | 70 | zsets.persist(); 71 | 72 | RedisConnection redisConnection = redisConnectionFactory.getConnection(); 73 | 74 | redisConnection.zRangeByLex("myzset".getBytes(), Range.range().lte("c")).stream().// 75 | map(it -> new String(it)).// 76 | forEach(System.out::println); 77 | 78 | System.out.println("###"); 79 | 80 | redisConnection.zRangeByLex("myzset".getBytes(), Range.range().lt("c")).stream().// 81 | map(it -> new String(it)).// 82 | forEach(System.out::println); 83 | 84 | System.out.println("###"); 85 | 86 | redisConnection.zRangeByLex("myzset".getBytes(), Range.range().gt("aaa").lt("g")).stream().// 87 | map(it -> new String(it)).// 88 | forEach(System.out::println); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /12-redis/src/test/java/example/RedisTestConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import javax.annotation.PreDestroy; 19 | 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | import org.springframework.data.redis.connection.RedisConnectionFactory; 23 | 24 | /** 25 | * @author Thomas Darimont 26 | */ 27 | @SpringBootApplication 28 | public class RedisTestConfiguration { 29 | 30 | @Autowired RedisConnectionFactory factory; 31 | 32 | // @Bean 33 | // RedisConnectionFactory redisConnectionFactory() { 34 | // return new LettuceConnectionFactory(); 35 | // } 36 | // 37 | // @Bean 38 | // RedisOperations redisOperations(RedisConnectionFactory rcf) { 39 | // 40 | // RedisTemplate rt = new RedisTemplate<>(); 41 | // rt.setConnectionFactory(rcf); 42 | // rt.setKeySerializer(new StringRedisSerializer()); 43 | // rt.setValueSerializer(new StringRedisSerializer()); 44 | // 45 | // return rt; 46 | // } 47 | 48 | /** 49 | * Clear database before shut down. 50 | */ 51 | @PreDestroy 52 | public void flushTestDb() { 53 | factory.getConnection().flushDb(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /13-key-value/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | spring-data-keyvalue-repositories 6 | 7 | What's new in Spring Data? - Key-value repositories 8 | 9 | 10 | com.springone2gx.2015 11 | whats-new-in-spring-data 12 | 1.0.0.BUILD-SNAPSHOT 13 | ../pom.xml 14 | 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter 21 | 22 | 23 | 24 | org.springframework.data 25 | spring-data-keyvalue 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /13-key-value/src/main/java/example/Person.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import lombok.EqualsAndHashCode; 19 | import lombok.Getter; 20 | import lombok.RequiredArgsConstructor; 21 | 22 | import java.util.UUID; 23 | 24 | import org.springframework.data.annotation.Id; 25 | 26 | /** 27 | * A domain type. 28 | * 29 | * @author Oliver Gierke 30 | */ 31 | @Getter 32 | @EqualsAndHashCode 33 | @RequiredArgsConstructor 34 | public class Person { 35 | 36 | private final @Id UUID id = UUID.randomUUID(); 37 | private final String firstname, lastname; 38 | private final int age; 39 | } 40 | -------------------------------------------------------------------------------- /13-key-value/src/main/java/example/PersonRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import java.util.List; 19 | import java.util.UUID; 20 | 21 | import org.springframework.data.repository.CrudRepository; 22 | 23 | /** 24 | * A repository for {@link Person} instances. 25 | * 26 | * @author Oliver Gierke 27 | */ 28 | interface PersonRepository extends CrudRepository { 29 | 30 | /** 31 | * Returns all person older than the given age. 32 | * 33 | * @param age 34 | * @return 35 | */ 36 | List findByAgeGreaterThan(int age); 37 | } 38 | -------------------------------------------------------------------------------- /13-key-value/src/test/java/example/PersonRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.hamcrest.CoreMatchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import example.Person; 22 | import example.PersonRepository; 23 | 24 | import java.util.List; 25 | 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.boot.test.SpringApplicationConfiguration; 30 | import org.springframework.context.annotation.Configuration; 31 | import org.springframework.data.map.repository.config.EnableMapRepositories; 32 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 33 | 34 | /** 35 | * Integration tests for {@link PersonRepository}. 36 | * 37 | * @author Oliver Gierke 38 | */ 39 | @RunWith(SpringJUnit4ClassRunner.class) 40 | @SpringApplicationConfiguration 41 | public class PersonRepositoryIntegrationTest { 42 | 43 | @Configuration 44 | @EnableMapRepositories 45 | static class Config {} 46 | 47 | @Autowired PersonRepository repository; 48 | 49 | @Test 50 | public void storesPerson() { 51 | 52 | Person person = repository.save(new Person("Dave", "Matthews", 47)); 53 | 54 | assertThat(repository.findOne(person.getId()), is(person)); 55 | } 56 | 57 | @Test 58 | public void findsPersonByAge() { 59 | 60 | Person dave = repository.save(new Person("Dave", "Matthews", 47)); 61 | Person oliver = repository.save(new Person("Oliver August", "Matthews", 7)); 62 | 63 | List result = repository.findByAgeGreaterThan(18); 64 | 65 | assertThat(result, hasItem(dave)); 66 | assertThat(result, not(hasItem(oliver))); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /14-redis-repositories/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /14-redis-repositories/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | spring-data-redis-repository-support 6 | What's new in Spring Data? - Redis repositories 7 | 8 | 9 | com.springone2gx.2015 10 | whats-new-in-spring-data 11 | 1.0.0.BUILD-SNAPSHOT 12 | 13 | 14 | 15 | Hopper-BUILD-SNAPSHOT 16 | 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-redis 23 | 24 | 25 | 26 | org.springframework.data 27 | spring-data-keyvalue 28 | 29 | 30 | 31 | com.github.kstyrc 32 | embedded-redis 33 | 0.6 34 | test 35 | 36 | 37 | 38 | org.springframework.data 39 | spring-data-keyvalue 40 | 1.1.0.DATAKV-112-SNAPSHOT 41 | 42 | 43 | 44 | org.springframework.data 45 | spring-data-redis 46 | 1.7.0.DATAREDIS-425-SNAPSHOT 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /14-redis-repositories/src/main/java/example/City.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.keyvalue.annotation.KeySpace; 5 | 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @KeySpace("cities") 12 | class City { 13 | 14 | @Id String id; 15 | String name; 16 | 17 | public City(String name) { 18 | this.name = name; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /14-redis-repositories/src/main/java/example/Person.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | 6 | import org.springframework.data.annotation.Id; 7 | import org.springframework.data.annotation.Reference; 8 | import org.springframework.data.redis.core.RedisHash; 9 | import org.springframework.data.redis.core.index.Indexed; 10 | 11 | import lombok.Data; 12 | 13 | @Data 14 | @RedisHash("persons") 15 | class Person { 16 | 17 | @Id String id; 18 | @Indexed String firstname; 19 | String lastname; 20 | 21 | Map attributes = Collections.emptyMap(); 22 | 23 | City city; 24 | 25 | @Reference Person mother; 26 | } 27 | -------------------------------------------------------------------------------- /14-redis-repositories/src/main/java/example/PersonRepository.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.repository.CrudRepository; 6 | 7 | interface PersonRepository extends CrudRepository { 8 | 9 | List findByFirstname(String firstname); 10 | 11 | List findByLastname(String lastname); 12 | 13 | List findByFirstnameAndLastname(String firstname, String lastname); 14 | } 15 | -------------------------------------------------------------------------------- /14-redis-repositories/src/test/java/example/EmbeddedRedisRule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import redis.embedded.RedisServer; 19 | 20 | import java.io.IOException; 21 | 22 | import org.junit.rules.ExternalResource; 23 | 24 | /** 25 | * JUnit rule implementation to start and shut down an embedded Redis instance. 26 | * 27 | * @author Christoph Strobl 28 | * @author Oliver Gierke 29 | */ 30 | public class EmbeddedRedisRule extends ExternalResource { 31 | 32 | private RedisServer server; 33 | 34 | /* 35 | * (non-Javadoc) 36 | * @see org.junit.rules.ExternalResource#before() 37 | */ 38 | @Override 39 | protected void before() throws IOException { 40 | 41 | this.server = new RedisServer(6379); 42 | this.server.start(); 43 | } 44 | 45 | /* 46 | * (non-Javadoc) 47 | * @see org.junit.rules.ExternalResource#after() 48 | */ 49 | @Override 50 | protected void after() { 51 | this.server.stop(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /14-redis-repositories/src/test/java/example/RedisRepositoryTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import static org.hamcrest.CoreMatchers.*; 19 | import static org.junit.Assert.*; 20 | 21 | import java.util.Arrays; 22 | 23 | import org.junit.Before; 24 | import org.junit.ClassRule; 25 | import org.junit.Test; 26 | import org.junit.runner.RunWith; 27 | import org.springframework.beans.factory.annotation.Autowired; 28 | import org.springframework.boot.test.SpringApplicationConfiguration; 29 | import org.springframework.data.keyvalue.core.KeyValueTemplate; 30 | import org.springframework.data.redis.connection.RedisConnectionFactory; 31 | import org.springframework.data.redis.core.RedisOperations; 32 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 33 | 34 | /** 35 | * @author Thomas Darimont 36 | * @author Oliver Gierke 37 | */ 38 | @RunWith(SpringJUnit4ClassRunner.class) 39 | @SpringApplicationConfiguration(RedisTestConfiguration.class) 40 | public class RedisRepositoryTests { 41 | 42 | public static @ClassRule EmbeddedRedisRule embeddedRedis = new EmbeddedRedisRule(); 43 | 44 | @Autowired RedisConnectionFactory redisConnectionFactory; 45 | @Autowired RedisOperations redis; 46 | @Autowired KeyValueTemplate kvTemplate; 47 | 48 | @Autowired PersonRepository repository; 49 | 50 | @Before 51 | public void setup() { 52 | kvTemplate.delete(Person.class); 53 | kvTemplate.delete(City.class); 54 | } 55 | 56 | @Test 57 | public void simpleFindByMultipleProperties() { 58 | 59 | Person egwene = new Person(); 60 | egwene.firstname = "egwene"; 61 | egwene.lastname = "al'vere"; 62 | egwene.city = new City("new york"); 63 | 64 | Person marin = new Person(); 65 | marin.firstname = "marin"; 66 | marin.lastname = "al'vere"; 67 | 68 | repository.save(Arrays.asList(egwene, marin)); 69 | 70 | assertThat(repository.findByLastname("al'vere").size(), is(2)); 71 | 72 | assertThat(repository.findByFirstnameAndLastname("egwene", "al'vere").size(), is(1)); 73 | assertThat(repository.findByFirstnameAndLastname("egwene", "al'vere").get(0), is(egwene)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /14-redis-repositories/src/test/java/example/RedisTestConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | import example.RedisTestConfiguration.CustomIndexConfiguration; 19 | 20 | import java.util.Arrays; 21 | 22 | import javax.annotation.PreDestroy; 23 | 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.boot.autoconfigure.SpringBootApplication; 26 | import org.springframework.data.redis.connection.RedisConnectionFactory; 27 | import org.springframework.data.redis.core.index.IndexConfiguration; 28 | import org.springframework.data.redis.core.index.RedisIndexDefinition; 29 | import org.springframework.data.redis.core.index.SimpleIndexDefinition; 30 | import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; 31 | 32 | /** 33 | * @author Thomas Darimont 34 | * @author Oliver Gierke 35 | * @author Christoph Strobl 36 | */ 37 | @SpringBootApplication 38 | @EnableRedisRepositories(indexConfiguration = CustomIndexConfiguration.class) 39 | public class RedisTestConfiguration { 40 | 41 | @Autowired RedisConnectionFactory factory; 42 | 43 | /** 44 | * Clear database before shut down. 45 | */ 46 | @PreDestroy 47 | public void flushTestDb() { 48 | factory.getConnection().flushDb(); 49 | } 50 | 51 | static class CustomIndexConfiguration extends IndexConfiguration { 52 | 53 | @Override 54 | protected Iterable initialConfiguration() { 55 | return Arrays.asList(new SimpleIndexDefinition("persons", "lastname")); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.springone2gx.2015 6 | whats-new-in-spring-data 7 | 1.0.0.BUILD-SNAPSHOT 8 | pom 9 | 10 | What's new in Spring Data? 11 | 12 | 13 | org.springframework.boot 14 | spring-boot-starter-parent 15 | 1.4.0.M1 16 | 17 | 18 | 19 | 01-intro 20 | 02-bom 21 | 03-java8 22 | 04-custom-repository 23 | 05-web-projection 24 | 06-querydsl-web 25 | 07-jpa-entity-graph 26 | 08-mongodb-security 27 | 09-mongodb-java8 28 | 10-rest-headers 29 | 11-rest-hal-browser 30 | 12-redis 31 | 13-key-value 32 | 14-redis-repositories 33 | 34 | 35 | 36 | 37 | 1.1.3 38 | 1.8 39 | 4.0.9 40 | 41 | 42 | 43 | 44 | 45 | ogierke 46 | Oliver Gierke 47 | ogierke@pivotal.io 48 | 49 | 50 | tdarimont 51 | Thomas Darimont 52 | tdarimont@gopivotal.io 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.projectlombok 60 | lombok 61 | 1.16.6 62 | provided 63 | 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-devtools 68 | true 69 | 70 | 71 | 72 | 73 | 74 | org.springframework.boot 75 | spring-boot-starter-test 76 | test 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | org.apache.maven.plugins 85 | maven-compiler-plugin 86 | 87 | ${java.version} 88 | ${java.version} 89 | -parameters 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | spring-libs-snapshot 99 | https://repo.spring.io/libs-snapshot 100 | 101 | 102 | 103 | 104 | 105 | spring-libs-snapshot 106 | https://repo.spring.io/libs-snapshot 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /readme.adoc: -------------------------------------------------------------------------------- 1 | = What's new in Spring Data? 2 | 3 | image:https://travis-ci.org/springone2gx2015/whats-new-in-spring-data.svg?branch=master["Build Status", link="https://travis-ci.org/springone2gx2015/whats-new-in-spring-data"] --------------------------------------------------------------------------------