Java 16 migration for REST examples.

See #606.
This commit is contained in:
Mark Paluch
2021-04-29 10:52:40 +02:00
parent b9c0e501d7
commit af86e0219f
19 changed files with 102 additions and 118 deletions

View File

@@ -49,7 +49,7 @@ public class Order {
* @param orderDate
*/
public Order(String customerId, Date orderDate) {
this(null, customerId, orderDate, new ArrayList<LineItem>());
this(null, customerId, orderDate, new ArrayList<>());
}
/**

View File

@@ -15,9 +15,6 @@
*/
package example.springdata.multistore;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import example.springdata.multistore.customer.Customer;
import example.springdata.multistore.shop.Order;
@@ -31,6 +28,8 @@ import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.repository.support.Repositories;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test to check repository interfaces are assigned to the correct store modules.
*
@@ -45,9 +44,9 @@ public class ApplicationConfigurationTest {
@Test
public void repositoriesAreAssignedToAppropriateStores() {
Repositories repositories = new Repositories(context);
var repositories = new Repositories(context);
assertThat(repositories.getEntityInformationFor(Customer.class), is(instanceOf(JpaEntityInformation.class)));
assertThat(repositories.getEntityInformationFor(Order.class), is(instanceOf(MongoEntityInformation.class)));
assertThat(repositories.getEntityInformationFor(Customer.class)).isInstanceOf(JpaEntityInformation.class);
assertThat(repositories.getEntityInformationFor(Order.class)).isInstanceOf(MongoEntityInformation.class);
}
}

View File

@@ -62,7 +62,7 @@ public class Customer {
this.gender = null;
}
static enum Gender {
MALE, FEMALE;
enum Gender {
MALE, FEMALE
}
}

View File

@@ -15,14 +15,13 @@
*/
package example.springdata.rest.headers;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests to bootstrap the application.
*
@@ -37,9 +36,9 @@ public class ApplicationIntegrationTests {
@Test
public void initializesRepositoryWithSampleData() {
Iterable<Customer> result = repository.findAll();
var result = repository.findAll();
assertThat(result, is(iterableWithSize(1)));
assertThat(result.iterator().next().getLastModifiedDate(), is(notNullValue()));
assertThat(result).hasSize(1);
assertThat(result.iterator().next().getLastModifiedDate()).isNotNull();
}
}

View File

@@ -41,7 +41,7 @@ public class CrossOriginIntegrationTests {
@Autowired WebApplicationContext context;
@Autowired CustomerRepository customers;
MockMvc mvc;
private MockMvc mvc;
@BeforeEach
public void setUp() {
@@ -51,8 +51,8 @@ public class CrossOriginIntegrationTests {
@Test
public void executePreflightRequest() throws Exception {
String origin = "http://localhost:1234";
URI uri = URI.create("/customers");
var origin = "http://localhost:1234";
var uri = URI.create("/customers");
mvc.perform(options(uri).header(ORIGIN, origin).header(ACCESS_CONTROL_REQUEST_METHOD, "POST")) //
.andExpect(header().string(ACCESS_CONTROL_ALLOW_ORIGIN, is(origin))) //
@@ -63,8 +63,8 @@ public class CrossOriginIntegrationTests {
@Test
public void executeCrossOriginRequest() throws Exception {
String origin = "http://localhost:1234";
URI uri = URI.create("/customers");
var origin = "http://localhost:1234";
var uri = URI.create("/customers");
mvc.perform(get(uri).header(ORIGIN, origin)) //
.andExpect(status().isOk()) //
@@ -74,8 +74,8 @@ public class CrossOriginIntegrationTests {
@Test
public void rejectCrossOriginRequest() throws Exception {
String origin = "http://foo.bar";
URI uri = URI.create("/customers");
var origin = "http://foo.bar";
var uri = URI.create("/customers");
mvc.perform(get(uri).header(ORIGIN, origin)) //
.andExpect(status().isForbidden());

View File

@@ -44,7 +44,7 @@ public class WebIntegrationTests {
@Autowired WebApplicationContext context;
@Autowired CustomerRepository customers;
MockMvc mvc;
private MockMvc mvc;
@BeforeEach
public void setUp() {
@@ -57,10 +57,10 @@ public class WebIntegrationTests {
@Test
public void executeConditionalGetRequests() throws Exception {
Customer customer = customers.findAll().iterator().next();
URI uri = new UriTemplate("/customers/{id}").expand(customer.getId());
var customer = customers.findAll().iterator().next();
var uri = new UriTemplate("/customers/{id}").expand(customer.getId());
MockHttpServletResponse response = mvc.perform(get(uri)).//
var response = mvc.perform(get(uri)).//
andExpect(header().string(ETAG, is(notNullValue()))).//
andExpect(header().string(LAST_MODIFIED, is(notNullValue()))).//
andReturn().getResponse();

View File

@@ -43,7 +43,7 @@ public class ApplicationIntegrationTests {
personRepository.save(new Person("Frodo", "Baggins"));
personRepository.save(new Person("Bilbo", "Baggins"));
for (Person person : personRepository.findAll()) {
for (var person : personRepository.findAll()) {
log.info("Hello " + person.toString());
}
@@ -51,7 +51,7 @@ public class ApplicationIntegrationTests {
treasureRepository.save(new Treasure("Sting", "Made by the Elves"));
treasureRepository.save(new Treasure("Sauron's ring", "One ring to rule them all"));
for (Treasure treasure : treasureRepository.findAll()) {
for (var treasure : treasureRepository.findAll()) {
log.info("Found treasure " + treasure.toString());
}
}

View File

@@ -40,10 +40,10 @@ public class Application {
public @PostConstruct void init() {
Customer dave = customers.save(new Customer("Dave", "Matthews", Gender.MALE, //
var dave = customers.save(new Customer("Dave", "Matthews", Gender.MALE, //
new Address("4711 Some Place", "54321", "Charlottesville", "VA")));
Order order = new Order();
var order = new Order();
order.setCustomer(dave);
order.add(new LineItem("Lakewood guitar", new BigDecimal(1299.0)));

View File

@@ -46,7 +46,7 @@ public class Customer {
this.gender = null;
}
static enum Gender {
MALE, FEMALE;
enum Gender {
MALE, FEMALE
}
}

View File

@@ -15,13 +15,12 @@
*/
package example.springdata.rest.projections;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests to bootstrap the application.
*
@@ -35,8 +34,8 @@ public class ApplicationIntegrationTests {
@Test
public void initializesRepositoryWithSampleData() {
Iterable<Order> result = repository.findAll();
var result = repository.findAll();
assertThat(result, is(iterableWithSize(1)));
assertThat(result).hasSize(1);
}
}

View File

@@ -15,9 +15,6 @@
*/
package example.springdata.rest.projections;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*;
import java.util.HashMap;
import java.util.Map;
@@ -27,6 +24,8 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test cases showing the programatic use of a {@link ProjectionFactory}.
*
@@ -40,16 +39,16 @@ class SimpleProjectionTests {
@Test
void createMapBackedProjection() {
Customer customer = factory.createProjection(Customer.class);
var customer = factory.createProjection(Customer.class);
customer.setFirstname("Dave");
customer.setLastname("Matthews");
// Verify accessors work
assertThat(customer.getFirstname(), is("Dave"));
assertThat(customer.getLastname(), is("Matthews"));
assertThat(customer.getFirstname()).isEqualTo("Dave");
assertThat(customer.getLastname()).isEqualTo("Matthews");
// Verify evaluating a SpEL expression
assertThat(customer.getFullName(), is("Dave Matthews"));
assertThat(customer.getFullName()).isEqualTo("Dave Matthews");
}
@Test
@@ -59,11 +58,11 @@ class SimpleProjectionTests {
backingMap.put("firstname", "Dave");
backingMap.put("lastname", "Matthews");
Customer customer = factory.createProjection(Customer.class, backingMap);
var customer = factory.createProjection(Customer.class, backingMap);
// Verify accessors work
assertThat(customer.getFirstname(), is("Dave"));
assertThat(customer.getLastname(), is("Matthews"));
assertThat(customer.getFirstname()).isEqualTo("Dave");
assertThat(customer.getLastname()).isEqualTo("Matthews");
}
interface Customer {

View File

@@ -31,6 +31,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.User.UserBuilder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
/**
@@ -88,10 +89,10 @@ public class Application {
@Bean
InMemoryUserDetailsManager userDetailsManager() {
UserBuilder builder = User.withDefaultPasswordEncoder();
var builder = User.builder().passwordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder()::encode);
UserDetails greg = builder.username("greg").password("turnquist").roles("USER").build();
UserDetails ollie = builder.username("ollie").password("gierke").roles("USER", "ADMIN").build();
var greg = builder.username("greg").password("turnquist").roles("USER").build();
var ollie = builder.username("ollie").password("gierke").roles("USER", "ADMIN").build();
return new InMemoryUserDetailsManager(greg, ollie);
}

View File

@@ -26,6 +26,9 @@ import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.context.SecurityContextHolder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
/**
* Collection of test cases used to verify method-level security.
*
@@ -96,7 +99,7 @@ class MethodLevelSecurityTests {
itemRepository.findAll();
Item item = itemRepository.save(new Item("MacBook Pro"));
var item = itemRepository.save(new Item("MacBook Pro"));
itemRepository.deleteById(item.getId());
}

View File

@@ -15,8 +15,7 @@
*/
package example.springdata.rest.security;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
@@ -85,7 +84,7 @@ class UrlLevelSecurityTests {
@Test
void allowsGetRequestsButRejectsPostForUser() throws Exception {
HttpHeaders headers = new HttpHeaders();
var headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT, MediaTypes.HAL_JSON_VALUE);
headers.add(HttpHeaders.AUTHORIZATION,
"Basic " + new String(Base64.getEncoder().encodeToString(("greg:turnquist").getBytes())));
@@ -103,7 +102,7 @@ class UrlLevelSecurityTests {
@Test
void allowsPostRequestForAdmin() throws Exception {
HttpHeaders headers = new HttpHeaders();
var headers = new HttpHeaders();
headers.set(HttpHeaders.ACCEPT, MediaTypes.HAL_JSON_VALUE);
headers.set(HttpHeaders.AUTHORIZATION,
"Basic " + new String(Base64.getEncoder().encodeToString(("ollie:gierke").getBytes())));
@@ -115,20 +114,20 @@ class UrlLevelSecurityTests {
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
String location = mvc.perform(post("/employees").//
var location = mvc.perform(post("/employees").//
content(PAYLOAD).//
headers(headers)).//
andExpect(status().isCreated()).//
andReturn().getResponse().getHeader(HttpHeaders.LOCATION);
ObjectMapper mapper = new ObjectMapper();
var mapper = new ObjectMapper();
String content = mvc.perform(get(location)).//
var content = mvc.perform(get(location)).//
andReturn().getResponse().getContentAsString();
Employee employee = mapper.readValue(content, Employee.class);
var employee = mapper.readValue(content, Employee.class);
assertThat(employee.getFirstName(), is("Saruman"));
assertThat(employee.getLastName(), is("the White"));
assertThat(employee.getTitle(), is("Wizard"));
assertThat(employee.getFirstName()).isEqualTo("Saruman");
assertThat(employee.getLastName()).isEqualTo("the White");
assertThat(employee.getTitle()).isEqualTo("Wizard");
}
}

View File

@@ -53,13 +53,13 @@ public class StoreInitializer {
return;
}
Iterable<? extends IndexDefinition> indexDefinitions = IndexResolver
var indexDefinitions = IndexResolver
.create(operations.getConverter().getMappingContext())
.resolveIndexFor(Store.class);
indexDefinitions.forEach(operations.indexOps(Store.class)::ensureIndex);
List<Store> stores = readStores();
var stores = readStores();
log.info("Importing {} stores into MongoDB…", stores.size());
repository.saveAll(stores);
log.info("Successfully imported {} stores.", repository.count());
@@ -72,26 +72,26 @@ public class StoreInitializer {
* @return
* @throws Exception
*/
public static List<Store> readStores() throws Exception {
private static List<Store> readStores() throws Exception {
ClassPathResource resource = new ClassPathResource("starbucks.csv");
Scanner scanner = new Scanner(resource.getInputStream());
String line = scanner.nextLine();
var resource = new ClassPathResource("starbucks.csv");
var scanner = new Scanner(resource.getInputStream());
var line = scanner.nextLine();
scanner.close();
FlatFileItemReader<Store> itemReader = new FlatFileItemReader<Store>();
var itemReader = new FlatFileItemReader<Store>();
itemReader.setResource(resource);
// DelimitedLineTokenizer defaults to comma as its delimiter
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
var tokenizer = new DelimitedLineTokenizer();
tokenizer.setNames(line.split(","));
tokenizer.setStrict(false);
DefaultLineMapper<Store> lineMapper = new DefaultLineMapper<Store>();
var lineMapper = new DefaultLineMapper<Store>();
lineMapper.setFieldSetMapper(fields -> {
Point location = new Point(fields.readDouble("Longitude"), fields.readDouble("Latitude"));
Address address = new Address(fields.readString("Street Address"), fields.readString("City"),
var location = new Point(fields.readDouble("Longitude"), fields.readDouble("Latitude"));
var address = new Address(fields.readString("Street Address"), fields.readString("City"),
fields.readString("Zip"), location);
return new Store(UUID.randomUUID(), fields.readString("Name"), address);

View File

@@ -23,9 +23,11 @@ import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Point;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.querydsl.binding.QuerydslBindings;
import org.springframework.data.querydsl.binding.SingleValueBinding;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RestResource;
import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.core.types.dsl.StringPath;
/**
@@ -47,7 +49,7 @@ public interface StoreRepository extends PagingAndSortingRepository<Store, UUID>
*/
default void customize(QuerydslBindings bindings, QStore store) {
bindings.bind(store.address.city).first((path, value) -> path.endsWith(value));
bindings.bind(String.class).first((StringPath path, String value) -> path.contains(value));
bindings.bind(store.address.city).first(StringExpression::endsWith);
bindings.bind(String.class).first((SingleValueBinding<StringPath, String>) StringExpression::contains);
}
}

View File

@@ -57,12 +57,8 @@ class StoresController {
static {
Map<String, Point> locations = new HashMap<>();
locations.put("Pivotal SF", new Point(-122.4041764, 37.7819286));
locations.put("Timesquare NY", new Point(-73.995146, 40.740337));
KNOWN_LOCATIONS = Collections.unmodifiableMap(locations);
KNOWN_LOCATIONS = Map.of("Pivotal SF", new Point(-122.4041764, 37.7819286), "Timesquare NY",
new Point(-73.995146, 40.740337));
}
private final StoreRepository repository;
@@ -81,9 +77,9 @@ class StoresController {
String index(Model model, @RequestParam Optional<Point> location, @RequestParam Optional<Distance> distance,
Pageable pageable) {
Point point = location.orElse(KNOWN_LOCATIONS.get("Timesquare NY"));
var point = location.orElse(KNOWN_LOCATIONS.get("Timesquare NY"));
Page<Store> stores = repository.findByAddressLocationNear(point, distance.orElse(DEFAULT_DISTANCE), pageable);
var stores = repository.findByAddressLocationNear(point, distance.orElse(DEFAULT_DISTANCE), pageable);
model.addAttribute("stores", stores);
model.addAttribute("distances", DISTANCES);

View File

@@ -31,15 +31,9 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Bean;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.PagedModel.PageMetadata;
import org.springframework.hateoas.client.Traverson;
import org.springframework.hateoas.client.Traverson.TraversalBuilder;
import org.springframework.hateoas.server.core.TypeReferences.CollectionModelType;
import org.springframework.hateoas.server.core.TypeReferences.EntityModelType;
import org.springframework.hateoas.server.core.TypeReferences.PagedModelType;
@@ -68,15 +62,17 @@ class StarbucksClient {
@LocalServerPort int port;
@Autowired RestOperations restOperations;
private static final String SERVICE_URI = "http://localhost:%s/api";
@Test
void discoverStoreSearch() {
Traverson traverson = new Traverson(URI.create(String.format(SERVICE_URI, port)), MediaTypes.HAL_JSON);
var traverson = new Traverson(URI.create(String.format(SERVICE_URI, port)), MediaTypes.HAL_JSON);
// Set up path traversal
TraversalBuilder builder = traverson. //
var builder = traverson. //
follow("stores", "search", "by-location");
// Log discovered
@@ -88,11 +84,11 @@ class StarbucksClient {
parameters.put("location", "40.740337,-73.995146");
parameters.put("distance", "0.5miles");
PagedModel<EntityModel<Store>> resources = builder.//
var resources = builder.//
withTemplateParameters(parameters).//
toObject(new PagedModelType<EntityModel<Store>>() {});
PageMetadata metadata = resources.getMetadata();
var metadata = resources.getMetadata();
log.info("Got {} of {} stores: ", resources.getContent().size(), metadata.getTotalElements());
@@ -101,45 +97,37 @@ class StarbucksClient {
forEach(store -> log.info("{} - {}", store.name, store.address));
}
@Autowired RestOperations restOperations;
@Test
void accessServiceUsingRestTemplate() {
// Access root resource
URI uri = URI.create(String.format(SERVICE_URI, port));
RequestEntity<Void> request = RequestEntity.get(uri).accept(HAL_JSON).build();
EntityModel<Object> rootLinks = restOperations.exchange(request, new EntityModelType<Object>() {}).getBody();
Links links = rootLinks.getLinks();
var uri = URI.create(String.format(SERVICE_URI, port));
var request = RequestEntity.get(uri).accept(HAL_JSON).build();
var rootLinks = restOperations.exchange(request, new EntityModelType<>() {}).getBody();
var links = rootLinks.getLinks();
// Follow stores link
Link storesLink = links.getRequiredLink("stores").expand();
var storesLink = links.getRequiredLink("stores").expand();
request = RequestEntity.get(URI.create(storesLink.getHref())).accept(HAL_JSON).build();
CollectionModel<Store> stores = restOperations.exchange(request, new CollectionModelType<Store>() {}).getBody();
var stores = restOperations.exchange(request, new CollectionModelType<Store>() {}).getBody();
stores.getContent().forEach(store -> log.info("{} - {}", store.name, store.address));
}
static class Store {
record Store(String name, StarbucksClient.Store.Address address) {
public String name;
Address address;
static class Address {
String city, zip, street;
Location location;
record Address(String city, String zip, String street, Store.Address.Location location) {
@Override
public String toString() {
return String.format("%s, %s %s - lat: %s, long: %s", street, zip, city, location.y, location.x);
}
static class Location {
double x, y;
record Location(double x, double y) {
}
}
}

View File

@@ -15,9 +15,6 @@
*/
package example.springdata.rest.stores;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import example.springdata.rest.stores.Store.Address;
import java.util.UUID;
@@ -33,6 +30,8 @@ import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link StoreRepository}.
*
@@ -53,15 +52,15 @@ public class StoreRepositoryIntegrationTests {
@Test
public void findsStoresByLocation() {
Point location = new Point(-73.995146, 40.740337);
Store store = new Store(UUID.randomUUID(), "Foo", new Address("street", "city", "zip", location));
var location = new Point(-73.995146, 40.740337);
var store = new Store(UUID.randomUUID(), "Foo", new Address("street", "city", "zip", location));
store = repository.save(store);
Page<Store> stores = repository.findByAddressLocationNear(location, new Distance(1.0, Metrics.KILOMETERS),
var stores = repository.findByAddressLocationNear(location, new Distance(1.0, Metrics.KILOMETERS),
PageRequest.of(0, 10));
assertThat(stores.getContent(), hasSize(1));
assertThat(stores.getContent(), hasItem(store));
assertThat(stores.getContent()).hasSize(1);
assertThat(stores.getContent()).contains(store);
}
}