diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml
index d5b6acda5b..16c5c4e79e 100644
--- a/spring-boot-samples/pom.xml
+++ b/spring-boot-samples/pom.xml
@@ -44,6 +44,7 @@
spring-boot-sample-jetty-sslspring-boot-sample-jetty8spring-boot-sample-jetty8-ssl
+ spring-boot-sample-jpaspring-boot-sample-jta-atomikosspring-boot-sample-jta-bitronixspring-boot-sample-jta-jndi
diff --git a/spring-boot-samples/spring-boot-sample-jpa/pom.xml b/spring-boot-samples/spring-boot-sample-jpa/pom.xml
new file mode 100644
index 0000000000..76195c85ff
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/pom.xml
@@ -0,0 +1,53 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-samples
+ 1.2.0.BUILD-SNAPSHOT
+
+ spring-boot-sample-jpa
+ Spring Boot JPA Sample
+ Spring Boot JPA Sample
+ http://projects.spring.io/spring-boot/
+
+ Pivotal Software, Inc.
+ http://www.spring.io
+
+
+ ${basedir}/../..
+
+
+
+ org.springframework.boot
+ spring-boot-starter-freemarker
+
+
+ org.hibernate
+ hibernate-entitymanager
+
+
+ org.hsqldb
+ hsqldb
+ runtime
+
+
+ org.springframework
+ spring-orm
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/SampleJpaApplication.java b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/SampleJpaApplication.java
new file mode 100644
index 0000000000..9f1855247d
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/SampleJpaApplication.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sample.jpa;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SampleJpaApplication {
+
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(SampleJpaApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/domain/Note.java b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/domain/Note.java
new file mode 100644
index 0000000000..9a2442c3c2
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/domain/Note.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sample.jpa.domain;
+
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+
+@Entity
+public class Note {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+
+ private String title;
+
+ private String body;
+
+ @ManyToMany
+ private List tags;
+
+ public long getId() {
+ return this.id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return this.title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getBody() {
+ return this.body;
+ }
+
+ public void setBody(String body) {
+ this.body = body;
+ }
+
+ public List getTags() {
+ return this.tags;
+ }
+
+ public void setTags(List tags) {
+ this.tags = tags;
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/domain/Tag.java b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/domain/Tag.java
new file mode 100644
index 0000000000..4d8bfc09d1
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/domain/Tag.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sample.jpa.domain;
+
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+
+@Entity
+public class Tag {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+
+ private String name;
+
+ @ManyToMany(mappedBy = "tags")
+ private List notes;
+
+ public long getId() {
+ return this.id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getNotes() {
+ return this.notes;
+ }
+
+ public void setNotes(List notes) {
+ this.notes = notes;
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/JpaNoteRepository.java b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/JpaNoteRepository.java
new file mode 100644
index 0000000000..0bd11447a0
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/JpaNoteRepository.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sample.jpa.repository;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.springframework.stereotype.Repository;
+
+import sample.jpa.domain.Note;
+
+@Repository
+class JpaNoteRepository implements NoteRepository {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Override
+ public List findAll() {
+ return this.entityManager.createQuery("SELECT n FROM Note n", Note.class)
+ .getResultList();
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/JpaTagRepository.java b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/JpaTagRepository.java
new file mode 100644
index 0000000000..7322c42cab
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/JpaTagRepository.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sample.jpa.repository;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.springframework.stereotype.Repository;
+
+import sample.jpa.domain.Tag;
+
+@Repository
+class JpaTagRepository implements TagRepository {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Override
+ public List findAll() {
+ return this.entityManager.createQuery("SELECT t FROM Tag t", Tag.class)
+ .getResultList();
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/NoteRepository.java b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/NoteRepository.java
new file mode 100644
index 0000000000..b27af92e3c
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/NoteRepository.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sample.jpa.repository;
+
+import java.util.List;
+
+import sample.jpa.domain.Note;
+
+public interface NoteRepository {
+
+ List findAll();
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/TagRepository.java b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/TagRepository.java
new file mode 100644
index 0000000000..897ef7f08f
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/repository/TagRepository.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sample.jpa.repository;
+
+import java.util.List;
+
+import sample.jpa.domain.Tag;
+
+public interface TagRepository {
+
+ List findAll();
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/web/IndexController.java b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/web/IndexController.java
new file mode 100644
index 0000000000..61a0f80afe
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/main/java/sample/jpa/web/IndexController.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sample.jpa.web;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+import sample.jpa.domain.Note;
+import sample.jpa.repository.NoteRepository;
+
+@Controller
+public class IndexController {
+
+ @Autowired
+ private NoteRepository noteRepository;
+
+ @RequestMapping("/")
+ @Transactional(readOnly = true)
+ public ModelAndView index() {
+ List notes = this.noteRepository.findAll();
+ ModelAndView modelAndView = new ModelAndView("index");
+ modelAndView.addObject("notes", notes);
+ return modelAndView;
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/main/resources/import.sql b/spring-boot-samples/spring-boot-sample-jpa/src/main/resources/import.sql
new file mode 100644
index 0000000000..a3d2222035
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/main/resources/import.sql
@@ -0,0 +1,17 @@
+insert into tag(name) values ('Spring projects')
+insert into tag(name) values ('Apache projects')
+insert into tag(name) values ('Open source')
+
+insert into note(title, body) values ('Spring Boot', 'Takes an opinionated view of building production-ready Spring applications.')
+insert into note(title, body) values ('Spring Framework', 'Core support for dependency injection, transaction management, web applications, data access, messaging, testing and more.')
+insert into note(title, body) values ('Spring Integration', 'Extends the Spring programming model to support the well-known Enterprise Integration Patterns.')
+insert into note(title, body) values ('Tomcat', 'Apache Tomcat is an open source software implementation of the Java Servlet and JavaServer Pages technologies.')
+
+insert into note_tags(notes_id, tags_id) values (1, 1)
+insert into note_tags(notes_id, tags_id) values (2, 1)
+insert into note_tags(notes_id, tags_id) values (3, 1)
+insert into note_tags(notes_id, tags_id) values (1, 3)
+insert into note_tags(notes_id, tags_id) values (2, 3)
+insert into note_tags(notes_id, tags_id) values (3, 3)
+insert into note_tags(notes_id, tags_id) values (4, 2)
+insert into note_tags(notes_id, tags_id) values (4, 3)
\ No newline at end of file
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/main/resources/templates/index.ftl b/spring-boot-samples/spring-boot-sample-jpa/src/main/resources/templates/index.ftl
new file mode 100644
index 0000000000..100e1b660e
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/main/resources/templates/index.ftl
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
Title
+
Body
+
Tags
+
+
+
+<#list notes as note>
+
+
${note.title}
+
${note.body}
+
+<#list note.tags as tag>
+ ${tag.name}
+#list>
+
+
+#list>
+
+
+
+
+
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/test/java/sample/jpa/SampleJpaApplicationTests.java b/spring-boot-samples/spring-boot-sample-jpa/src/test/java/sample/jpa/SampleJpaApplicationTests.java
new file mode 100644
index 0000000000..1f14e18c21
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/test/java/sample/jpa/SampleJpaApplicationTests.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sample.jpa;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.SpringApplicationConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
+
+/**
+ * Integration test to run the application.
+ *
+ * @author Oliver Gierke
+ * @author Dave Syer
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringApplicationConfiguration(classes = SampleJpaApplication.class)
+@WebAppConfiguration
+public class SampleJpaApplicationTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setUp() {
+ this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
+ }
+
+ @Test
+ public void testHome() throws Exception {
+ this.mvc.perform(get("/")).andExpect(status().isOk())
+ .andExpect(xpath("//tbody/tr").nodeCount(4));
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/test/java/sample/jpa/repository/JpaNoteRepositoryIntegrationTests.java b/spring-boot-samples/spring-boot-sample-jpa/src/test/java/sample/jpa/repository/JpaNoteRepositoryIntegrationTests.java
new file mode 100644
index 0000000000..d8a5237f12
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/test/java/sample/jpa/repository/JpaNoteRepositoryIntegrationTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package sample.jpa.repository;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.SpringApplicationConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import sample.jpa.SampleJpaApplication;
+import sample.jpa.domain.Note;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Integration tests for {@link JpaNoteRepository}.
+ *
+ * @author Andy Wilkinson
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringApplicationConfiguration(classes = SampleJpaApplication.class)
+public class JpaNoteRepositoryIntegrationTests {
+
+ @Autowired
+ JpaNoteRepository repository;
+
+ @Test
+ public void findsAllNotes() {
+ List notes = this.repository.findAll();
+ assertEquals(4, notes.size());
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-jpa/src/test/java/sample/jpa/repository/JpaTagRepositoryIntegrationTests.java b/spring-boot-samples/spring-boot-sample-jpa/src/test/java/sample/jpa/repository/JpaTagRepositoryIntegrationTests.java
new file mode 100644
index 0000000000..add24b39d0
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-jpa/src/test/java/sample/jpa/repository/JpaTagRepositoryIntegrationTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package sample.jpa.repository;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.SpringApplicationConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import sample.jpa.SampleJpaApplication;
+import sample.jpa.domain.Tag;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Integration tests for {@link JpaTagRepository}.
+ *
+ * @author Andy Wilkinson
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringApplicationConfiguration(classes = SampleJpaApplication.class)
+public class JpaTagRepositoryIntegrationTests {
+
+ @Autowired
+ JpaTagRepository repository;
+
+ @Test
+ public void findsAllTags() {
+ List tags = this.repository.findAll();
+ assertEquals(3, tags.size());
+ }
+
+}