diff --git a/spring-boot-rest/README.md b/spring-boot-rest/README.md
index 2b955ddc5b..2c89a64a00 100644
--- a/spring-boot-rest/README.md
+++ b/spring-boot-rest/README.md
@@ -2,3 +2,4 @@ Module for the articles that are part of the Spring REST E-book:
1. [Bootstrap a Web Application with Spring 5](https://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration)
2. [Error Handling for REST with Spring](http://www.baeldung.com/exception-handling-for-rest-with-spring)
+3. [REST Pagination in Spring](http://www.baeldung.com/rest-api-pagination-in-spring)
\ No newline at end of file
diff --git a/spring-boot-rest/pom.xml b/spring-boot-rest/pom.xml
index f05d242072..bcd0381603 100644
--- a/spring-boot-rest/pom.xml
+++ b/spring-boot-rest/pom.xml
@@ -1,5 +1,6 @@
-
4.0.0
com.baeldung.web
@@ -24,7 +25,7 @@
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
-
+
org.hibernate
hibernate-entitymanager
@@ -32,6 +33,30 @@
org.springframework
spring-jdbc
+
+ org.springframework.data
+ spring-data-jpa
+
+
+ com.h2database
+ h2
+
+
+ org.springframework
+ spring-tx
+
+
+ org.springframework.data
+ spring-data-commons
+
+
+
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
org.springframework.boot
@@ -58,5 +83,6 @@
com.baeldung.SpringBootRestApplication
2.32
+ 27.0.1-jre
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/SpringBootRestApplication.java b/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java
similarity index 92%
rename from spring-boot-rest/src/main/java/com/baeldung/web/SpringBootRestApplication.java
rename to spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java
index c945b20aa1..62aae7619d 100644
--- a/spring-boot-rest/src/main/java/com/baeldung/web/SpringBootRestApplication.java
+++ b/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java
@@ -1,4 +1,4 @@
-package com.baeldung.web;
+package com.baeldung;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java
new file mode 100644
index 0000000000..d8996ca50d
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java
@@ -0,0 +1,16 @@
+package com.baeldung.persistence;
+
+import java.io.Serializable;
+
+import org.springframework.data.domain.Page;
+
+public interface IOperations {
+
+ // read - all
+
+ Page findPaginated(int page, int size);
+
+ // write
+
+ T create(final T entity);
+}
diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/dao/IFooDao.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/dao/IFooDao.java
new file mode 100644
index 0000000000..59394d0d28
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/dao/IFooDao.java
@@ -0,0 +1,9 @@
+package com.baeldung.persistence.dao;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.baeldung.persistence.model.Foo;
+
+public interface IFooDao extends JpaRepository {
+
+}
diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java
new file mode 100644
index 0000000000..9af3d07bed
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java
@@ -0,0 +1,83 @@
+package com.baeldung.persistence.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Foo implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+
+ @Column(nullable = false)
+ private String name;
+
+ public Foo() {
+ super();
+ }
+
+ public Foo(final String name) {
+ super();
+
+ this.name = name;
+ }
+
+ // API
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(final long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ //
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final Foo other = (Foo) obj;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Foo [name=").append(name).append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/service/IFooService.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/IFooService.java
new file mode 100644
index 0000000000..0f165238eb
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/IFooService.java
@@ -0,0 +1,13 @@
+package com.baeldung.persistence.service;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+import com.baeldung.persistence.IOperations;
+import com.baeldung.persistence.model.Foo;
+
+public interface IFooService extends IOperations {
+
+ Page findPaginated(Pageable pageable);
+
+}
diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java
new file mode 100644
index 0000000000..871f768895
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java
@@ -0,0 +1,31 @@
+package com.baeldung.persistence.service.common;
+
+import java.io.Serializable;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.repository.PagingAndSortingRepository;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.persistence.IOperations;
+
+@Transactional
+public abstract class AbstractService implements IOperations {
+
+ // read - all
+
+ @Override
+ public Page findPaginated(final int page, final int size) {
+ return getDao().findAll(PageRequest.of(page, size));
+ }
+
+ // write
+
+ @Override
+ public T create(final T entity) {
+ return getDao().save(entity);
+ }
+
+ protected abstract PagingAndSortingRepository getDao();
+
+}
diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/service/impl/FooService.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/impl/FooService.java
new file mode 100644
index 0000000000..9d705f51d3
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/impl/FooService.java
@@ -0,0 +1,40 @@
+package com.baeldung.persistence.service.impl;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.repository.PagingAndSortingRepository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.persistence.dao.IFooDao;
+import com.baeldung.persistence.model.Foo;
+import com.baeldung.persistence.service.IFooService;
+import com.baeldung.persistence.service.common.AbstractService;
+
+@Service
+@Transactional
+public class FooService extends AbstractService implements IFooService {
+
+ @Autowired
+ private IFooDao dao;
+
+ public FooService() {
+ super();
+ }
+
+ // API
+
+ @Override
+ protected PagingAndSortingRepository getDao() {
+ return dao;
+ }
+
+ // custom methods
+
+ @Override
+ public Page findPaginated(Pageable pageable) {
+ return dao.findAll(pageable);
+ }
+
+}
diff --git a/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java b/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java
new file mode 100644
index 0000000000..4a4b9eee3f
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java
@@ -0,0 +1,85 @@
+package com.baeldung.spring;
+
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import com.google.common.base.Preconditions;
+
+@Configuration
+@EnableTransactionManagement
+@PropertySource({ "classpath:persistence-${envTarget:h2}.properties" })
+@ComponentScan({ "com.baeldung.persistence" })
+// @ImportResource("classpath*:springDataPersistenceConfig.xml")
+@EnableJpaRepositories(basePackages = "com.baeldung.persistence.dao")
+public class PersistenceConfig {
+
+ @Autowired
+ private Environment env;
+
+ public PersistenceConfig() {
+ super();
+ }
+
+ @Bean
+ public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
+ final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
+ em.setDataSource(dataSource());
+ em.setPackagesToScan(new String[] { "com.baeldung.persistence.model" });
+
+ final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ // vendorAdapter.set
+ em.setJpaVendorAdapter(vendorAdapter);
+ em.setJpaProperties(additionalProperties());
+
+ return em;
+ }
+
+ @Bean
+ public DataSource dataSource() {
+ final DriverManagerDataSource dataSource = new DriverManagerDataSource();
+ dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
+ dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
+ dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
+ dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
+
+ return dataSource;
+ }
+
+ @Bean
+ public PlatformTransactionManager transactionManager() {
+ final JpaTransactionManager transactionManager = new JpaTransactionManager();
+ transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
+
+ return transactionManager;
+ }
+
+ @Bean
+ public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
+ return new PersistenceExceptionTranslationPostProcessor();
+ }
+
+ final Properties additionalProperties() {
+ final Properties hibernateProperties = new Properties();
+ hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
+ hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
+ // hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", "true");
+ return hibernateProperties;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java b/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java
new file mode 100644
index 0000000000..39aade174b
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java
@@ -0,0 +1,43 @@
+package com.baeldung.spring;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.web.servlet.ViewResolver;
+import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import org.springframework.web.servlet.view.InternalResourceViewResolver;
+
+@Configuration
+@ComponentScan("com.baeldung.web")
+@EnableWebMvc
+public class WebConfig implements WebMvcConfigurer {
+
+ public WebConfig() {
+ super();
+ }
+
+ @Bean
+ public ViewResolver viewResolver() {
+ final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
+ viewResolver.setPrefix("/WEB-INF/view/");
+ viewResolver.setSuffix(".jsp");
+ return viewResolver;
+ }
+
+ // API
+ @Override
+ public void addViewControllers(final ViewControllerRegistry registry) {
+ registry.addViewController("/graph.html");
+ registry.addViewController("/homepage.html");
+ }
+
+ @Override
+ public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
+ configurer.defaultContentType(MediaType.APPLICATION_JSON);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java b/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java
index e3716ec113..cf3f9c4dbd 100644
--- a/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java
@@ -27,5 +27,4 @@ public class MyErrorController extends BasicErrorController {
HttpStatus status = getStatus(request);
return new ResponseEntity<>(body, status);
}
-
}
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java b/spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java
deleted file mode 100644
index 808e946218..0000000000
--- a/spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.baeldung.web.config;
-
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class WebConfig {
-
-}
\ No newline at end of file
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java
new file mode 100644
index 0000000000..b35295cf99
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java
@@ -0,0 +1,89 @@
+package com.baeldung.web.controller;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import com.baeldung.persistence.model.Foo;
+import com.baeldung.persistence.service.IFooService;
+import com.baeldung.web.exception.MyResourceNotFoundException;
+import com.baeldung.web.hateoas.event.PaginatedResultsRetrievedEvent;
+import com.baeldung.web.hateoas.event.ResourceCreatedEvent;
+import com.google.common.base.Preconditions;
+
+@Controller
+@RequestMapping(value = "/auth/foos")
+public class FooController {
+
+ @Autowired
+ private ApplicationEventPublisher eventPublisher;
+
+ @Autowired
+ private IFooService service;
+
+ public FooController() {
+ super();
+ }
+
+ // API
+
+ // read - all
+
+ @RequestMapping(params = { "page", "size" }, method = RequestMethod.GET)
+ @ResponseBody
+ public List findPaginated(@RequestParam("page") final int page, @RequestParam("size") final int size,
+ final UriComponentsBuilder uriBuilder, final HttpServletResponse response) {
+ final Page resultPage = service.findPaginated(page, size);
+ if (page > resultPage.getTotalPages()) {
+ throw new MyResourceNotFoundException();
+ }
+ eventPublisher.publishEvent(new PaginatedResultsRetrievedEvent(Foo.class, uriBuilder, response, page,
+ resultPage.getTotalPages(), size));
+
+ return resultPage.getContent();
+ }
+
+ @GetMapping("/pageable")
+ @ResponseBody
+ public List findPaginatedWithPageable(Pageable pageable, final UriComponentsBuilder uriBuilder,
+ final HttpServletResponse response) {
+ final Page resultPage = service.findPaginated(pageable);
+ if (pageable.getPageNumber() > resultPage.getTotalPages()) {
+ throw new MyResourceNotFoundException();
+ }
+ eventPublisher.publishEvent(new PaginatedResultsRetrievedEvent(Foo.class, uriBuilder, response,
+ pageable.getPageNumber(), resultPage.getTotalPages(), pageable.getPageSize()));
+
+ return resultPage.getContent();
+ }
+
+ // write
+
+ @RequestMapping(method = RequestMethod.POST)
+ @ResponseStatus(HttpStatus.CREATED)
+ @ResponseBody
+ public Foo create(@RequestBody final Foo resource, final HttpServletResponse response) {
+ Preconditions.checkNotNull(resource);
+ final Foo foo = service.create(resource);
+ final Long idOfCreatedResource = foo.getId();
+
+ eventPublisher.publishEvent(new ResourceCreatedEvent(this, response, idOfCreatedResource));
+
+ return foo;
+ }
+}
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java
new file mode 100644
index 0000000000..436e41e8eb
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java
@@ -0,0 +1,40 @@
+package com.baeldung.web.controller;
+
+import java.net.URI;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.util.UriTemplate;
+
+import com.baeldung.web.util.LinkUtil;
+
+@Controller
+@RequestMapping(value = "/auth/")
+public class RootController {
+
+ public RootController() {
+ super();
+ }
+
+ // API
+
+ // discover
+
+ @RequestMapping(value = "admin", method = RequestMethod.GET)
+ @ResponseStatus(value = HttpStatus.NO_CONTENT)
+ public void adminRoot(final HttpServletRequest request, final HttpServletResponse response) {
+ final String rootUri = request.getRequestURL()
+ .toString();
+
+ final URI fooUri = new UriTemplate("{rootUri}/{resource}").expand(rootUri, "foo");
+ final String linkToFoo = LinkUtil.createLinkHeader(fooUri.toASCIIString(), "collection");
+ response.addHeader("Link", linkToFoo);
+ }
+
+}
diff --git a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java
similarity index 97%
rename from spring-rest-full/src/main/java/org/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java
rename to spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java
index 01f7e658f1..f62fbf6247 100644
--- a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java
@@ -1,4 +1,4 @@
-package org.baeldung.web.hateoas.event;
+package com.baeldung.web.hateoas.event;
import java.io.Serializable;
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/ResourceCreatedEvent.java b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/ResourceCreatedEvent.java
new file mode 100644
index 0000000000..b602f7ec4b
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/ResourceCreatedEvent.java
@@ -0,0 +1,28 @@
+package com.baeldung.web.hateoas.event;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.context.ApplicationEvent;
+
+public class ResourceCreatedEvent extends ApplicationEvent {
+ private final HttpServletResponse response;
+ private final long idOfNewResource;
+
+ public ResourceCreatedEvent(final Object source, final HttpServletResponse response, final long idOfNewResource) {
+ super(source);
+
+ this.response = response;
+ this.idOfNewResource = idOfNewResource;
+ }
+
+ // API
+
+ public HttpServletResponse getResponse() {
+ return response;
+ }
+
+ public long getIdOfNewResource() {
+ return idOfNewResource;
+ }
+
+}
diff --git a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java
similarity index 62%
rename from spring-rest-full/src/main/java/org/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java
rename to spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java
index 603c91007d..31555ef353 100644
--- a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java
@@ -1,13 +1,15 @@
-package org.baeldung.web.hateoas.listener;
+package com.baeldung.web.hateoas.listener;
+
+import java.util.StringJoiner;
import javax.servlet.http.HttpServletResponse;
-import org.baeldung.web.hateoas.event.PaginatedResultsRetrievedEvent;
-import org.baeldung.web.util.LinkUtil;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
+import com.baeldung.web.hateoas.event.PaginatedResultsRetrievedEvent;
+import com.baeldung.web.util.LinkUtil;
import com.google.common.base.Preconditions;
import com.google.common.net.HttpHeaders;
@@ -27,32 +29,32 @@ class PaginatedResultsRetrievedDiscoverabilityListener implements ApplicationLis
public final void onApplicationEvent(final PaginatedResultsRetrievedEvent ev) {
Preconditions.checkNotNull(ev);
- addLinkHeaderOnPagedResourceRetrieval(ev.getUriBuilder(), ev.getResponse(), ev.getClazz(), ev.getPage(), ev.getTotalPages(), ev.getPageSize());
+ addLinkHeaderOnPagedResourceRetrieval(ev.getUriBuilder(), ev.getResponse(), ev.getClazz(), ev.getPage(),
+ ev.getTotalPages(), ev.getPageSize());
}
// - note: at this point, the URI is transformed into plural (added `s`) in a hardcoded way - this will change in the future
- final void addLinkHeaderOnPagedResourceRetrieval(final UriComponentsBuilder uriBuilder, final HttpServletResponse response, final Class clazz, final int page, final int totalPages, final int pageSize) {
+ final void addLinkHeaderOnPagedResourceRetrieval(final UriComponentsBuilder uriBuilder,
+ final HttpServletResponse response, final Class clazz, final int page, final int totalPages,
+ final int pageSize) {
plural(uriBuilder, clazz);
- final StringBuilder linkHeader = new StringBuilder();
+ final StringJoiner linkHeader = new StringJoiner(", ");
if (hasNextPage(page, totalPages)) {
final String uriForNextPage = constructNextPageUri(uriBuilder, page, pageSize);
- linkHeader.append(LinkUtil.createLinkHeader(uriForNextPage, LinkUtil.REL_NEXT));
+ linkHeader.add(LinkUtil.createLinkHeader(uriForNextPage, LinkUtil.REL_NEXT));
}
if (hasPreviousPage(page)) {
final String uriForPrevPage = constructPrevPageUri(uriBuilder, page, pageSize);
- appendCommaIfNecessary(linkHeader);
- linkHeader.append(LinkUtil.createLinkHeader(uriForPrevPage, LinkUtil.REL_PREV));
+ linkHeader.add(LinkUtil.createLinkHeader(uriForPrevPage, LinkUtil.REL_PREV));
}
if (hasFirstPage(page)) {
final String uriForFirstPage = constructFirstPageUri(uriBuilder, pageSize);
- appendCommaIfNecessary(linkHeader);
- linkHeader.append(LinkUtil.createLinkHeader(uriForFirstPage, LinkUtil.REL_FIRST));
+ linkHeader.add(LinkUtil.createLinkHeader(uriForFirstPage, LinkUtil.REL_FIRST));
}
if (hasLastPage(page, totalPages)) {
final String uriForLastPage = constructLastPageUri(uriBuilder, totalPages, pageSize);
- appendCommaIfNecessary(linkHeader);
- linkHeader.append(LinkUtil.createLinkHeader(uriForLastPage, LinkUtil.REL_LAST));
+ linkHeader.add(LinkUtil.createLinkHeader(uriForLastPage, LinkUtil.REL_LAST));
}
if (linkHeader.length() > 0) {
@@ -61,19 +63,35 @@ class PaginatedResultsRetrievedDiscoverabilityListener implements ApplicationLis
}
final String constructNextPageUri(final UriComponentsBuilder uriBuilder, final int page, final int size) {
- return uriBuilder.replaceQueryParam(PAGE, page + 1).replaceQueryParam("size", size).build().encode().toUriString();
+ return uriBuilder.replaceQueryParam(PAGE, page + 1)
+ .replaceQueryParam("size", size)
+ .build()
+ .encode()
+ .toUriString();
}
final String constructPrevPageUri(final UriComponentsBuilder uriBuilder, final int page, final int size) {
- return uriBuilder.replaceQueryParam(PAGE, page - 1).replaceQueryParam("size", size).build().encode().toUriString();
+ return uriBuilder.replaceQueryParam(PAGE, page - 1)
+ .replaceQueryParam("size", size)
+ .build()
+ .encode()
+ .toUriString();
}
final String constructFirstPageUri(final UriComponentsBuilder uriBuilder, final int size) {
- return uriBuilder.replaceQueryParam(PAGE, 0).replaceQueryParam("size", size).build().encode().toUriString();
+ return uriBuilder.replaceQueryParam(PAGE, 0)
+ .replaceQueryParam("size", size)
+ .build()
+ .encode()
+ .toUriString();
}
final String constructLastPageUri(final UriComponentsBuilder uriBuilder, final int totalPages, final int size) {
- return uriBuilder.replaceQueryParam(PAGE, totalPages).replaceQueryParam("size", size).build().encode().toUriString();
+ return uriBuilder.replaceQueryParam(PAGE, totalPages)
+ .replaceQueryParam("size", size)
+ .build()
+ .encode()
+ .toUriString();
}
final boolean hasNextPage(final int page, final int totalPages) {
@@ -92,16 +110,11 @@ class PaginatedResultsRetrievedDiscoverabilityListener implements ApplicationLis
return (totalPages > 1) && hasNextPage(page, totalPages);
}
- final void appendCommaIfNecessary(final StringBuilder linkHeader) {
- if (linkHeader.length() > 0) {
- linkHeader.append(", ");
- }
- }
-
// template
protected void plural(final UriComponentsBuilder uriBuilder, final Class clazz) {
- final String resourceName = clazz.getSimpleName().toLowerCase() + "s";
+ final String resourceName = clazz.getSimpleName()
+ .toLowerCase() + "s";
uriBuilder.path("/auth/" + resourceName);
}
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/ResourceCreatedDiscoverabilityListener.java b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/ResourceCreatedDiscoverabilityListener.java
new file mode 100644
index 0000000000..37afcdace4
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/ResourceCreatedDiscoverabilityListener.java
@@ -0,0 +1,36 @@
+package com.baeldung.web.hateoas.listener;
+
+import java.net.URI;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.http.HttpHeaders;
+import com.baeldung.web.hateoas.event.ResourceCreatedEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+
+import com.google.common.base.Preconditions;
+
+@Component
+class ResourceCreatedDiscoverabilityListener implements ApplicationListener {
+
+ @Override
+ public void onApplicationEvent(final ResourceCreatedEvent resourceCreatedEvent) {
+ Preconditions.checkNotNull(resourceCreatedEvent);
+
+ final HttpServletResponse response = resourceCreatedEvent.getResponse();
+ final long idOfNewResource = resourceCreatedEvent.getIdOfNewResource();
+
+ addLinkHeaderOnResourceCreation(response, idOfNewResource);
+ }
+
+ void addLinkHeaderOnResourceCreation(final HttpServletResponse response, final long idOfNewResource) {
+ // final String requestUrl = request.getRequestURL().toString();
+ // final URI uri = new UriTemplate("{requestUrl}/{idOfNewResource}").expand(requestUrl, idOfNewResource);
+
+ final URI uri = ServletUriComponentsBuilder.fromCurrentRequestUri().path("/{idOfNewResource}").buildAndExpand(idOfNewResource).toUri();
+ response.setHeader(HttpHeaders.LOCATION, uri.toASCIIString());
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/util/LinkUtil.java b/spring-boot-rest/src/main/java/com/baeldung/web/util/LinkUtil.java
new file mode 100644
index 0000000000..3ebba8ae1c
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/util/LinkUtil.java
@@ -0,0 +1,36 @@
+package com.baeldung.web.util;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Provides some constants and utility methods to build a Link Header to be stored in the {@link HttpServletResponse} object
+ */
+public final class LinkUtil {
+
+ public static final String REL_COLLECTION = "collection";
+ public static final String REL_NEXT = "next";
+ public static final String REL_PREV = "prev";
+ public static final String REL_FIRST = "first";
+ public static final String REL_LAST = "last";
+
+ private LinkUtil() {
+ throw new AssertionError();
+ }
+
+ //
+
+ /**
+ * Creates a Link Header to be stored in the {@link HttpServletResponse} to provide Discoverability features to the user
+ *
+ * @param uri
+ * the base uri
+ * @param rel
+ * the relative path
+ *
+ * @return the complete url
+ */
+ public static String createLinkHeader(final String uri, final String rel) {
+ return "<" + uri + ">; rel=\"" + rel + "\"";
+ }
+
+}
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/util/RestPreconditions.java b/spring-boot-rest/src/main/java/com/baeldung/web/util/RestPreconditions.java
new file mode 100644
index 0000000000..d86aeeebd1
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/util/RestPreconditions.java
@@ -0,0 +1,48 @@
+package com.baeldung.web.util;
+
+import org.springframework.http.HttpStatus;
+
+import com.baeldung.web.exception.MyResourceNotFoundException;
+
+/**
+ * Simple static methods to be called at the start of your own methods to verify correct arguments and state. If the Precondition fails, an {@link HttpStatus} code is thrown
+ */
+public final class RestPreconditions {
+
+ private RestPreconditions() {
+ throw new AssertionError();
+ }
+
+ // API
+
+ /**
+ * Check if some value was found, otherwise throw exception.
+ *
+ * @param expression
+ * has value true if found, otherwise false
+ * @throws MyResourceNotFoundException
+ * if expression is false, means value not found.
+ */
+ public static void checkFound(final boolean expression) {
+ if (!expression) {
+ throw new MyResourceNotFoundException();
+ }
+ }
+
+ /**
+ * Check if some value was found, otherwise throw exception.
+ *
+ * @param expression
+ * has value true if found, otherwise false
+ * @throws MyResourceNotFoundException
+ * if expression is false, means value not found.
+ */
+ public static T checkFound(final T resource) {
+ if (resource == null) {
+ throw new MyResourceNotFoundException();
+ }
+
+ return resource;
+ }
+
+}
diff --git a/spring-boot-rest/src/main/resources/application.properties b/spring-boot-rest/src/main/resources/application.properties
index e65440e2b9..a0179f1e4b 100644
--- a/spring-boot-rest/src/main/resources/application.properties
+++ b/spring-boot-rest/src/main/resources/application.properties
@@ -1,3 +1,6 @@
+server.port=8082
+server.servlet.context-path=/spring-boot-rest
+
### Spring Boot default error handling configurations
#server.error.whitelabel.enabled=false
#server.error.include-stacktrace=always
\ No newline at end of file
diff --git a/spring-boot-rest/src/main/resources/persistence-h2.properties b/spring-boot-rest/src/main/resources/persistence-h2.properties
new file mode 100644
index 0000000000..839a466533
--- /dev/null
+++ b/spring-boot-rest/src/main/resources/persistence-h2.properties
@@ -0,0 +1,22 @@
+## jdbc.X
+#jdbc.driverClassName=com.mysql.jdbc.Driver
+#jdbc.url=jdbc:mysql://localhost:3306/spring_hibernate4_01?createDatabaseIfNotExist=true
+#jdbc.user=tutorialuser
+#jdbc.pass=tutorialmy5ql
+#
+## hibernate.X
+#hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
+#hibernate.show_sql=false
+#hibernate.hbm2ddl.auto=create-drop
+
+
+# jdbc.X
+jdbc.driverClassName=org.h2.Driver
+jdbc.url=jdbc:h2:mem:security_permission;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+jdbc.user=sa
+jdbc.pass=
+
+# hibernate.X
+hibernate.dialect=org.hibernate.dialect.H2Dialect
+hibernate.show_sql=false
+hibernate.hbm2ddl.auto=create-drop
diff --git a/spring-boot-rest/src/main/resources/persistence-mysql.properties b/spring-boot-rest/src/main/resources/persistence-mysql.properties
new file mode 100644
index 0000000000..8263b0d9ac
--- /dev/null
+++ b/spring-boot-rest/src/main/resources/persistence-mysql.properties
@@ -0,0 +1,10 @@
+# jdbc.X
+jdbc.driverClassName=com.mysql.jdbc.Driver
+jdbc.url=jdbc:mysql://localhost:3306/spring_hibernate4_01?createDatabaseIfNotExist=true
+jdbc.user=tutorialuser
+jdbc.pass=tutorialmy5ql
+
+# hibernate.X
+hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
+hibernate.show_sql=false
+hibernate.hbm2ddl.auto=create-drop
diff --git a/spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml b/spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml
new file mode 100644
index 0000000000..5ea2d9c05b
--- /dev/null
+++ b/spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-rest/src/test/java/com/baeldung/Consts.java b/spring-boot-rest/src/test/java/com/baeldung/Consts.java
new file mode 100644
index 0000000000..e33efd589e
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/Consts.java
@@ -0,0 +1,5 @@
+package com.baeldung;
+
+public interface Consts {
+ int APPLICATION_PORT = 8082;
+}
diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/SpringContextIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java
similarity index 92%
rename from spring-boot-rest/src/test/java/com/baeldung/web/SpringContextIntegrationTest.java
rename to spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java
index 1e49df2909..25fbc4cc02 100644
--- a/spring-boot-rest/src/test/java/com/baeldung/web/SpringContextIntegrationTest.java
+++ b/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java
@@ -1,4 +1,4 @@
-package com.baeldung.web;
+package com.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java
new file mode 100644
index 0000000000..61eb9400cc
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java
@@ -0,0 +1,103 @@
+package com.baeldung.common.web;
+
+import static com.baeldung.web.util.HTTPLinkHeaderUtil.extractURIByRel;
+import static org.apache.commons.lang3.RandomStringUtils.randomNumeric;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.google.common.net.HttpHeaders;
+
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+
+public abstract class AbstractBasicLiveTest extends AbstractLiveTest {
+
+ public AbstractBasicLiveTest(final Class clazzToSet) {
+ super(clazzToSet);
+ }
+
+ // find - all - paginated
+
+ @Test
+ public void whenResourcesAreRetrievedPaged_then200IsReceived() {
+ create();
+
+ final Response response = RestAssured.get(getURL() + "?page=0&size=10");
+
+ assertThat(response.getStatusCode(), is(200));
+ }
+
+ @Test
+ public void whenPageOfResourcesAreRetrievedOutOfBounds_then404IsReceived() {
+ final String url = getURL() + "?page=" + randomNumeric(5) + "&size=10";
+ final Response response = RestAssured.get(url);
+
+ assertThat(response.getStatusCode(), is(404));
+ }
+
+ @Test
+ public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() {
+ create();
+
+ final Response response = RestAssured.get(getURL() + "?page=0&size=10");
+
+ assertFalse(response.body().as(List.class).isEmpty());
+ }
+
+ @Test
+ public void whenFirstPageOfResourcesAreRetrieved_thenSecondPageIsNext() {
+ create();
+ create();
+ create();
+
+ final Response response = RestAssured.get(getURL() + "?page=0&size=2");
+
+ final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next");
+ assertEquals(getURL() + "?page=1&size=2", uriToNextPage);
+ }
+
+ @Test
+ public void whenFirstPageOfResourcesAreRetrieved_thenNoPreviousPage() {
+ final Response response = RestAssured.get(getURL() + "?page=0&size=2");
+
+ final String uriToPrevPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "prev");
+ assertNull(uriToPrevPage);
+ }
+
+ @Test
+ public void whenSecondPageOfResourcesAreRetrieved_thenFirstPageIsPrevious() {
+ create();
+ create();
+
+ final Response response = RestAssured.get(getURL() + "?page=1&size=2");
+
+ final String uriToPrevPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "prev");
+ assertEquals(getURL() + "?page=0&size=2", uriToPrevPage);
+ }
+
+ @Test
+ public void whenLastPageOfResourcesIsRetrieved_thenNoNextPageIsDiscoverable() {
+ create();
+ create();
+ create();
+
+ final Response first = RestAssured.get(getURL() + "?page=0&size=2");
+ final String uriToLastPage = extractURIByRel(first.getHeader(HttpHeaders.LINK), "last");
+
+ final Response response = RestAssured.get(uriToLastPage);
+
+ final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next");
+ assertNull(uriToNextPage);
+ }
+
+ // count
+
+}
diff --git a/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java
new file mode 100644
index 0000000000..d26632bc38
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java
@@ -0,0 +1,65 @@
+package com.baeldung.common.web;
+
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+
+import static com.baeldung.Consts.APPLICATION_PORT;
+
+import java.io.Serializable;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.baeldung.test.IMarshaller;
+import com.google.common.base.Preconditions;
+import com.google.common.net.HttpHeaders;
+
+public abstract class AbstractLiveTest {
+
+ protected final Class clazz;
+
+ @Autowired
+ protected IMarshaller marshaller;
+
+ public AbstractLiveTest(final Class clazzToSet) {
+ super();
+
+ Preconditions.checkNotNull(clazzToSet);
+ clazz = clazzToSet;
+ }
+
+ // template method
+
+ public abstract void create();
+
+ public abstract String createAsUri();
+
+ protected final void create(final T resource) {
+ createAsUri(resource);
+ }
+
+ protected final String createAsUri(final T resource) {
+ final Response response = createAsResponse(resource);
+ Preconditions.checkState(response.getStatusCode() == 201, "create operation: " + response.getStatusCode());
+
+ final String locationOfCreatedResource = response.getHeader(HttpHeaders.LOCATION);
+ Preconditions.checkNotNull(locationOfCreatedResource);
+ return locationOfCreatedResource;
+ }
+
+ final Response createAsResponse(final T resource) {
+ Preconditions.checkNotNull(resource);
+
+ final String resourceAsString = marshaller.encode(resource);
+ return RestAssured.given()
+ .contentType(marshaller.getMime())
+ .body(resourceAsString)
+ .post(getURL());
+ }
+
+ //
+
+ protected String getURL() {
+ return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/auth/foos";
+ }
+
+}
diff --git a/spring-boot-rest/src/test/java/com/baeldung/spring/ConfigIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/spring/ConfigIntegrationTest.java
new file mode 100644
index 0000000000..da8421ea6c
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/spring/ConfigIntegrationTest.java
@@ -0,0 +1,17 @@
+package com.baeldung.spring;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@ComponentScan("com.baeldung.test")
+public class ConfigIntegrationTest implements WebMvcConfigurer {
+
+ public ConfigIntegrationTest() {
+ super();
+ }
+
+ // API
+
+}
\ No newline at end of file
diff --git a/spring-boot-rest/src/test/java/com/baeldung/test/IMarshaller.java b/spring-boot-rest/src/test/java/com/baeldung/test/IMarshaller.java
new file mode 100644
index 0000000000..e2198ecb59
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/test/IMarshaller.java
@@ -0,0 +1,15 @@
+package com.baeldung.test;
+
+import java.util.List;
+
+public interface IMarshaller {
+
+ String encode(final T entity);
+
+ T decode(final String entityAsString, final Class clazz);
+
+ List decodeList(final String entitiesAsString, final Class clazz);
+
+ String getMime();
+
+}
diff --git a/spring-boot-rest/src/test/java/com/baeldung/test/JacksonMarshaller.java b/spring-boot-rest/src/test/java/com/baeldung/test/JacksonMarshaller.java
new file mode 100644
index 0000000000..23b5d60b6b
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/test/JacksonMarshaller.java
@@ -0,0 +1,81 @@
+package com.baeldung.test;
+
+import java.io.IOException;
+import java.util.List;
+
+import com.baeldung.persistence.model.Foo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.MediaType;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Preconditions;
+
+public final class JacksonMarshaller implements IMarshaller {
+ private final Logger logger = LoggerFactory.getLogger(JacksonMarshaller.class);
+
+ private final ObjectMapper objectMapper;
+
+ public JacksonMarshaller() {
+ super();
+
+ objectMapper = new ObjectMapper();
+ }
+
+ // API
+
+ @Override
+ public final String encode(final T resource) {
+ Preconditions.checkNotNull(resource);
+ String entityAsJSON = null;
+ try {
+ entityAsJSON = objectMapper.writeValueAsString(resource);
+ } catch (final IOException ioEx) {
+ logger.error("", ioEx);
+ }
+
+ return entityAsJSON;
+ }
+
+ @Override
+ public final T decode(final String resourceAsString, final Class clazz) {
+ Preconditions.checkNotNull(resourceAsString);
+
+ T entity = null;
+ try {
+ entity = objectMapper.readValue(resourceAsString, clazz);
+ } catch (final IOException ioEx) {
+ logger.error("", ioEx);
+ }
+
+ return entity;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public final List decodeList(final String resourcesAsString, final Class clazz) {
+ Preconditions.checkNotNull(resourcesAsString);
+
+ List entities = null;
+ try {
+ if (clazz.equals(Foo.class)) {
+ entities = objectMapper.readValue(resourcesAsString, new TypeReference>() {
+ // ...
+ });
+ } else {
+ entities = objectMapper.readValue(resourcesAsString, List.class);
+ }
+ } catch (final IOException ioEx) {
+ logger.error("", ioEx);
+ }
+
+ return entities;
+ }
+
+ @Override
+ public final String getMime() {
+ return MediaType.APPLICATION_JSON.toString();
+ }
+
+}
diff --git a/spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java b/spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java
new file mode 100644
index 0000000000..740ee07839
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java
@@ -0,0 +1,49 @@
+package com.baeldung.test;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Profile;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+
+@Component
+@Profile("test")
+public class TestMarshallerFactory implements FactoryBean {
+
+ @Autowired
+ private Environment env;
+
+ public TestMarshallerFactory() {
+ super();
+ }
+
+ // API
+
+ @Override
+ public IMarshaller getObject() {
+ final String testMime = env.getProperty("test.mime");
+ if (testMime != null) {
+ switch (testMime) {
+ case "json":
+ return new JacksonMarshaller();
+ case "xml":
+ // If we need to implement xml marshaller we can include spring-rest-full XStreamMarshaller
+ throw new IllegalStateException();
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ return new JacksonMarshaller();
+ }
+
+ @Override
+ public Class getObjectType() {
+ return IMarshaller.class;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/FooLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooLiveTest.java
new file mode 100644
index 0000000000..f721489eff
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooLiveTest.java
@@ -0,0 +1,36 @@
+package com.baeldung.web;
+
+import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
+
+import org.junit.runner.RunWith;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+
+import com.baeldung.common.web.AbstractBasicLiveTest;
+import com.baeldung.persistence.model.Foo;
+import com.baeldung.spring.ConfigIntegrationTest;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { ConfigIntegrationTest.class }, loader = AnnotationConfigContextLoader.class)
+@ActiveProfiles("test")
+public class FooLiveTest extends AbstractBasicLiveTest {
+
+ public FooLiveTest() {
+ super(Foo.class);
+ }
+
+ // API
+
+ @Override
+ public final void create() {
+ create(new Foo(randomAlphabetic(6)));
+ }
+
+ @Override
+ public final String createAsUri() {
+ return createAsUri(new Foo(randomAlphabetic(6)));
+ }
+
+}
diff --git a/spring-rest-full/src/test/java/org/baeldung/web/FooPageableLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java
similarity index 86%
rename from spring-rest-full/src/test/java/org/baeldung/web/FooPageableLiveTest.java
rename to spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java
index 3f637c5213..359a62a4d8 100644
--- a/spring-rest-full/src/test/java/org/baeldung/web/FooPageableLiveTest.java
+++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java
@@ -1,19 +1,14 @@
-package org.baeldung.web;
+package com.baeldung.web;
+import static com.baeldung.Consts.APPLICATION_PORT;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.apache.commons.lang3.RandomStringUtils.randomNumeric;
-import static org.baeldung.Consts.APPLICATION_PORT;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
-import io.restassured.RestAssured;
-import io.restassured.response.Response;
import java.util.List;
-import org.baeldung.common.web.AbstractBasicLiveTest;
-import org.baeldung.persistence.model.Foo;
-import org.baeldung.spring.ConfigIntegrationTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ActiveProfiles;
@@ -21,6 +16,13 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
+import com.baeldung.common.web.AbstractBasicLiveTest;
+import com.baeldung.persistence.model.Foo;
+import com.baeldung.spring.ConfigIntegrationTest;
+
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ConfigIntegrationTest.class }, loader = AnnotationConfigContextLoader.class)
@ActiveProfiles("test")
@@ -34,7 +36,7 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest {
@Override
public final void create() {
- create(new Foo(randomAlphabetic(6)));
+ super.create(new Foo(randomAlphabetic(6)));
}
@Override
@@ -45,6 +47,8 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest {
@Override
@Test
public void whenResourcesAreRetrievedPaged_then200IsReceived() {
+ this.create();
+
final Response response = RestAssured.get(getPageableURL() + "?page=0&size=10");
assertThat(response.getStatusCode(), is(200));
@@ -70,7 +74,7 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest {
}
protected String getPageableURL() {
- return "http://localhost:" + APPLICATION_PORT + "/spring-rest-full/auth/foos/pageable";
+ return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/auth/foos/pageable";
}
}
diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java
new file mode 100644
index 0000000000..1e2ddd5ec5
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java
@@ -0,0 +1,14 @@
+package com.baeldung.web;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+// @formatter:off
+ FooLiveTest.class
+ ,FooPageableLiveTest.class
+}) //
+public class LiveTestSuiteLiveTest {
+
+}
diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/error/ErrorHandlingLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/error/ErrorHandlingLiveTest.java
index ea1b6ab227..3e21af524f 100644
--- a/spring-boot-rest/src/test/java/com/baeldung/web/error/ErrorHandlingLiveTest.java
+++ b/spring-boot-rest/src/test/java/com/baeldung/web/error/ErrorHandlingLiveTest.java
@@ -6,6 +6,7 @@ import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isA;
import static org.hamcrest.Matchers.not;
+import static com.baeldung.Consts.APPLICATION_PORT;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
@@ -16,8 +17,8 @@ import com.gargoylesoftware.htmlunit.html.HtmlPage;
public class ErrorHandlingLiveTest {
- private static final String BASE_URL = "http://localhost:8080";
- private static final String EXCEPTION_ENDPOINT = "/exception";
+ private static final String BASE_URL = "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest";
+ private static final String EXCEPTION_ENDPOINT = BASE_URL + "/exception";
private static final String ERROR_RESPONSE_KEY_PATH = "error";
private static final String XML_RESPONSE_KEY_PATH = "xmlkey";
@@ -57,7 +58,7 @@ public class ErrorHandlingLiveTest {
try (WebClient webClient = new WebClient()) {
webClient.getOptions()
.setThrowExceptionOnFailingStatusCode(false);
- HtmlPage page = webClient.getPage(BASE_URL + EXCEPTION_ENDPOINT);
+ HtmlPage page = webClient.getPage(EXCEPTION_ENDPOINT);
assertThat(page.getBody()
.asText()).contains("Whitelabel Error Page");
}
diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/util/HTTPLinkHeaderUtil.java b/spring-boot-rest/src/test/java/com/baeldung/web/util/HTTPLinkHeaderUtil.java
new file mode 100644
index 0000000000..54d62b64e8
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/web/util/HTTPLinkHeaderUtil.java
@@ -0,0 +1,36 @@
+package com.baeldung.web.util;
+
+public final class HTTPLinkHeaderUtil {
+
+ private HTTPLinkHeaderUtil() {
+ throw new AssertionError();
+ }
+
+ //
+
+ public static String extractURIByRel(final String linkHeader, final String rel) {
+ if (linkHeader == null) {
+ return null;
+ }
+
+ String uriWithSpecifiedRel = null;
+ final String[] links = linkHeader.split(", ");
+ String linkRelation;
+ for (final String link : links) {
+ final int positionOfSeparator = link.indexOf(';');
+ linkRelation = link.substring(positionOfSeparator + 1, link.length()).trim();
+ if (extractTypeOfRelation(linkRelation).equals(rel)) {
+ uriWithSpecifiedRel = link.substring(1, positionOfSeparator - 1);
+ break;
+ }
+ }
+
+ return uriWithSpecifiedRel;
+ }
+
+ private static Object extractTypeOfRelation(final String linkRelation) {
+ final int positionOfEquals = linkRelation.indexOf('=');
+ return linkRelation.substring(positionOfEquals + 2, linkRelation.length() - 1).trim();
+ }
+
+}
diff --git a/spring-rest-full/README.md b/spring-rest-full/README.md
index 3a8d0a727a..2ef3a09e37 100644
--- a/spring-rest-full/README.md
+++ b/spring-rest-full/README.md
@@ -8,7 +8,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
### Relevant Articles:
-- [REST Pagination in Spring](http://www.baeldung.com/rest-api-pagination-in-spring)
- [HATEOAS for a Spring REST Service](http://www.baeldung.com/rest-api-discoverability-with-spring)
- [REST API Discoverability and HATEOAS](http://www.baeldung.com/restful-web-service-discoverability)
- [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring)
diff --git a/spring-rest-full/src/main/java/org/baeldung/persistence/IOperations.java b/spring-rest-full/src/main/java/org/baeldung/persistence/IOperations.java
index d4f3f0982c..8c5593c3e8 100644
--- a/spring-rest-full/src/main/java/org/baeldung/persistence/IOperations.java
+++ b/spring-rest-full/src/main/java/org/baeldung/persistence/IOperations.java
@@ -3,8 +3,6 @@ package org.baeldung.persistence;
import java.io.Serializable;
import java.util.List;
-import org.springframework.data.domain.Page;
-
public interface IOperations {
// read - one
@@ -15,8 +13,6 @@ public interface IOperations {
List findAll();
- Page findPaginated(int page, int size);
-
// write
T create(final T entity);
diff --git a/spring-rest-full/src/main/java/org/baeldung/persistence/service/IFooService.java b/spring-rest-full/src/main/java/org/baeldung/persistence/service/IFooService.java
index a3d16d9c15..60d607b9ef 100644
--- a/spring-rest-full/src/main/java/org/baeldung/persistence/service/IFooService.java
+++ b/spring-rest-full/src/main/java/org/baeldung/persistence/service/IFooService.java
@@ -2,13 +2,9 @@ package org.baeldung.persistence.service;
import org.baeldung.persistence.IOperations;
import org.baeldung.persistence.model.Foo;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
public interface IFooService extends IOperations {
Foo retrieveByName(String name);
-
- Page findPaginated(Pageable pageable);
}
diff --git a/spring-rest-full/src/main/java/org/baeldung/persistence/service/common/AbstractService.java b/spring-rest-full/src/main/java/org/baeldung/persistence/service/common/AbstractService.java
index 5987bbae5f..59ccea8b12 100644
--- a/spring-rest-full/src/main/java/org/baeldung/persistence/service/common/AbstractService.java
+++ b/spring-rest-full/src/main/java/org/baeldung/persistence/service/common/AbstractService.java
@@ -4,8 +4,6 @@ import java.io.Serializable;
import java.util.List;
import org.baeldung.persistence.IOperations;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.transaction.annotation.Transactional;
@@ -30,11 +28,6 @@ public abstract class AbstractService implements IOperat
return Lists.newArrayList(getDao().findAll());
}
- @Override
- public Page findPaginated(final int page, final int size) {
- return getDao().findAll(new PageRequest(page, size));
- }
-
// write
@Override
diff --git a/spring-rest-full/src/main/java/org/baeldung/persistence/service/impl/FooService.java b/spring-rest-full/src/main/java/org/baeldung/persistence/service/impl/FooService.java
index 376082b2d5..d46f1bfe90 100644
--- a/spring-rest-full/src/main/java/org/baeldung/persistence/service/impl/FooService.java
+++ b/spring-rest-full/src/main/java/org/baeldung/persistence/service/impl/FooService.java
@@ -7,8 +7,6 @@ import org.baeldung.persistence.model.Foo;
import org.baeldung.persistence.service.IFooService;
import org.baeldung.persistence.service.common.AbstractService;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -48,9 +46,4 @@ public class FooService extends AbstractService implements IFooService {
return Lists.newArrayList(getDao().findAll());
}
- @Override
- public Page findPaginated(Pageable pageable) {
- return dao.findAll(pageable);
- }
-
}
diff --git a/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java b/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java
index 484a59f8ef..443d0908ee 100644
--- a/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java
+++ b/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java
@@ -6,27 +6,20 @@ import javax.servlet.http.HttpServletResponse;
import org.baeldung.persistence.model.Foo;
import org.baeldung.persistence.service.IFooService;
-import org.baeldung.web.exception.MyResourceNotFoundException;
-import org.baeldung.web.hateoas.event.PaginatedResultsRetrievedEvent;
import org.baeldung.web.hateoas.event.ResourceCreatedEvent;
import org.baeldung.web.hateoas.event.SingleResourceRetrievedEvent;
import org.baeldung.web.util.RestPreconditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.util.UriComponentsBuilder;
import com.google.common.base.Preconditions;
@@ -72,30 +65,6 @@ public class FooController {
return service.findAll();
}
- @RequestMapping(params = { "page", "size" }, method = RequestMethod.GET)
- @ResponseBody
- public List findPaginated(@RequestParam("page") final int page, @RequestParam("size") final int size, final UriComponentsBuilder uriBuilder, final HttpServletResponse response) {
- final Page resultPage = service.findPaginated(page, size);
- if (page > resultPage.getTotalPages()) {
- throw new MyResourceNotFoundException();
- }
- eventPublisher.publishEvent(new PaginatedResultsRetrievedEvent(Foo.class, uriBuilder, response, page, resultPage.getTotalPages(), size));
-
- return resultPage.getContent();
- }
-
- @GetMapping("/pageable")
- @ResponseBody
- public List findPaginatedWithPageable(Pageable pageable, final UriComponentsBuilder uriBuilder, final HttpServletResponse response) {
- final Page resultPage = service.findPaginated(pageable);
- if (pageable.getPageNumber() > resultPage.getTotalPages()) {
- throw new MyResourceNotFoundException();
- }
- eventPublisher.publishEvent(new PaginatedResultsRetrievedEvent(Foo.class, uriBuilder, response, pageable.getPageNumber(), resultPage.getTotalPages(), pageable.getPageSize()));
-
- return resultPage.getContent();
- }
-
// write
@RequestMapping(method = RequestMethod.POST)
diff --git a/spring-rest-full/src/main/java/org/baeldung/web/util/RestPreconditions.java b/spring-rest-full/src/main/java/org/baeldung/web/util/RestPreconditions.java
index 18cb8219ec..4e211ccb10 100644
--- a/spring-rest-full/src/main/java/org/baeldung/web/util/RestPreconditions.java
+++ b/spring-rest-full/src/main/java/org/baeldung/web/util/RestPreconditions.java
@@ -1,8 +1,9 @@
package org.baeldung.web.util;
-import org.baeldung.web.exception.MyResourceNotFoundException;
import org.springframework.http.HttpStatus;
+import org.baeldung.web.exception.MyResourceNotFoundException;
+
/**
* Simple static methods to be called at the start of your own methods to verify correct arguments and state. If the Precondition fails, an {@link HttpStatus} code is thrown
*/
diff --git a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java
index 4e0007d036..d64807d97f 100644
--- a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java
+++ b/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java
@@ -1,26 +1,19 @@
package org.baeldung.common.web;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
-import static org.apache.commons.lang3.RandomStringUtils.randomNumeric;
-import static org.baeldung.web.util.HTTPLinkHeaderUtil.extractURIByRel;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
-import io.restassured.RestAssured;
-import io.restassured.response.Response;
import java.io.Serializable;
-import java.util.List;
import org.junit.Ignore;
import org.junit.Test;
import com.google.common.net.HttpHeaders;
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+
public abstract class AbstractBasicLiveTest extends AbstractLiveTest {
public AbstractBasicLiveTest(final Class clazzToSet) {
@@ -104,71 +97,4 @@ public abstract class AbstractBasicLiveTest extends Abst
// find - one
// find - all
-
- // find - all - paginated
-
- @Test
- public void whenResourcesAreRetrievedPaged_then200IsReceived() {
- final Response response = RestAssured.get(getURL() + "?page=0&size=10");
-
- assertThat(response.getStatusCode(), is(200));
- }
-
- @Test
- public void whenPageOfResourcesAreRetrievedOutOfBounds_then404IsReceived() {
- final String url = getURL() + "?page=" + randomNumeric(5) + "&size=10";
- final Response response = RestAssured.get(url);
-
- assertThat(response.getStatusCode(), is(404));
- }
-
- @Test
- public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() {
- create();
-
- final Response response = RestAssured.get(getURL() + "?page=0&size=10");
-
- assertFalse(response.body().as(List.class).isEmpty());
- }
-
- @Test
- public void whenFirstPageOfResourcesAreRetrieved_thenSecondPageIsNext() {
- final Response response = RestAssured.get(getURL() + "?page=0&size=2");
-
- final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next");
- assertEquals(getURL() + "?page=1&size=2", uriToNextPage);
- }
-
- @Test
- public void whenFirstPageOfResourcesAreRetrieved_thenNoPreviousPage() {
- final Response response = RestAssured.get(getURL() + "?page=0&size=2");
-
- final String uriToPrevPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "prev");
- assertNull(uriToPrevPage);
- }
-
- @Test
- public void whenSecondPageOfResourcesAreRetrieved_thenFirstPageIsPrevious() {
- create();
- create();
-
- final Response response = RestAssured.get(getURL() + "?page=1&size=2");
-
- final String uriToPrevPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "prev");
- assertEquals(getURL() + "?page=0&size=2", uriToPrevPage);
- }
-
- @Test
- public void whenLastPageOfResourcesIsRetrieved_thenNoNextPageIsDiscoverable() {
- final Response first = RestAssured.get(getURL() + "?page=0&size=2");
- final String uriToLastPage = extractURIByRel(first.getHeader(HttpHeaders.LINK), "last");
-
- final Response response = RestAssured.get(uriToLastPage);
-
- final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next");
- assertNull(uriToNextPage);
- }
-
- // count
-
}
diff --git a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractDiscoverabilityLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractDiscoverabilityLiveTest.java
index c2dd3d84c7..96d796349a 100644
--- a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractDiscoverabilityLiveTest.java
+++ b/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractDiscoverabilityLiveTest.java
@@ -5,8 +5,6 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
-import io.restassured.RestAssured;
-import io.restassured.response.Response;
import java.io.Serializable;
@@ -18,6 +16,9 @@ import org.springframework.http.MediaType;
import com.google.common.net.HttpHeaders;
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+
public abstract class AbstractDiscoverabilityLiveTest extends AbstractLiveTest {
public AbstractDiscoverabilityLiveTest(final Class clazzToSet) {
diff --git a/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java
index 71a61ed338..da736392c4 100644
--- a/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java
+++ b/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java
@@ -8,7 +8,6 @@ import org.junit.runners.Suite;
// @formatter:off
FooDiscoverabilityLiveTest.class
,FooLiveTest.class
- ,FooPageableLiveTest.class
}) //
public class LiveTestSuiteLiveTest {