Add 'hateoas' sample

This commit is contained in:
Moritz Halbritter
2022-07-22 12:13:18 +02:00
parent d96232d7ff
commit c747e0ec17
15 changed files with 366 additions and 0 deletions

View File

@@ -12,6 +12,7 @@ smoke_tests:
- configuration-properties
- data-jdbc
- data-jpa
- hateoas
- jdbc
- logging-log4j2
- security-webflux

1
hateoas/README.adoc Normal file
View File

@@ -0,0 +1 @@
Tests if Spring HATEOAS is working.

19
hateoas/build.gradle Normal file
View File

@@ -0,0 +1,19 @@
plugins {
id 'java'
id 'org.springframework.boot'
id 'org.springframework.aot.smoke-test'
id 'org.graalvm.buildtools.native'
}
dependencies {
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
implementation("org.springframework.boot:spring-boot-starter-hateoas")
testImplementation("org.springframework.boot:spring-boot-starter-test")
aotTestImplementation(project(":aot-smoke-test-support"))
}
aotSmokeTest {
webApplication = true
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2022 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
*
* https://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 com.example.hateoas;
import org.junit.jupiter.api.Test;
import org.springframework.aot.smoketest.support.junit.AotSmokeTest;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.assertj.core.api.Assertions.assertThat;
@AotSmokeTest
class HateoasApplicationAotTests {
@Test
void employeeHasLinks(WebTestClient client) {
client.get().uri("/employee/1").exchange().expectStatus().isOk().expectBody().jsonPath("$.id").isEqualTo("1")
.jsonPath("$._links.self.href").value(v -> {
assertThat(v).isInstanceOf(String.class);
assertThat((String) v).endsWith("/employee/1");
}).jsonPath("$._links.manager.href").value(v -> {
assertThat(v).isInstanceOf(String.class);
assertThat((String) v).endsWith("/manager/1");
});
}
@Test
void managerHasLinks(WebTestClient client) {
client.get().uri("/manager/1").exchange().expectStatus().isOk().expectBody().jsonPath("$.id").isEqualTo("1")
.jsonPath("$._links.self.href").value(v -> {
assertThat(v).isInstanceOf(String.class);
assertThat((String) v).endsWith("/manager/1");
}).jsonPath("$._links.reports.href").value(v -> {
assertThat(v).isInstanceOf(String.class);
assertThat((String) v).endsWith("/manager/1/reports");
});
}
@Test
void reportsIsCollection(WebTestClient client) {
client.get().uri("/manager/1/reports").exchange().expectStatus().isOk().expectBody()
.jsonPath("$._links.self.href").value(v -> {
assertThat(v).isInstanceOf(String.class);
assertThat((String) v).endsWith("/manager/1/reports");
}).jsonPath("$._embedded").isMap().jsonPath("$._embedded.employees").isArray()
.jsonPath("$._embedded.employees[0].id").isEqualTo("1").jsonPath("$._embedded.employees[1].id")
.isEqualTo("2").jsonPath("$._embedded.employees[2].id").isEqualTo("3");
}
}

View File

@@ -0,0 +1,31 @@
package com.example.hateoas;
import com.example.hateoas.assembler.EmployeeModelAssembler;
import com.example.hateoas.model.Employee;
import com.example.hateoas.model.EmployeeModel;
import org.springframework.hateoas.server.ExposesResourceFor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(path = "/employee", produces = MediaType.APPLICATION_JSON_VALUE)
@ExposesResourceFor(Employee.class)
public class EmployeeController {
private final EmployeeModelAssembler employeeModelAssembler;
public EmployeeController(EmployeeModelAssembler employeeModelAssembler) {
this.employeeModelAssembler = employeeModelAssembler;
}
@GetMapping("{id}")
public EmployeeModel getById(@PathVariable String id) {
Employee employee = new Employee(id, "first-name", "last-name", id);
return employeeModelAssembler.toModel(employee);
}
}

View File

@@ -0,0 +1,16 @@
package com.example.hateoas;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
@SpringBootApplication
@EnableHypermediaSupport(type = HypermediaType.HAL)
public class HateoasApplication {
public static void main(String[] args) {
SpringApplication.run(HateoasApplication.class, args);
}
}

View File

@@ -0,0 +1,52 @@
package com.example.hateoas;
import java.util.List;
import java.util.Set;
import com.example.hateoas.assembler.EmployeeModelAssembler;
import com.example.hateoas.assembler.ManagerModelAssembler;
import com.example.hateoas.model.Employee;
import com.example.hateoas.model.EmployeeModel;
import com.example.hateoas.model.Manager;
import com.example.hateoas.model.ManagerModel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.server.ExposesResourceFor;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(path = "/manager", produces = MediaType.APPLICATION_JSON_VALUE)
@ExposesResourceFor(Manager.class)
public class ManagerController {
private final EmployeeModelAssembler employeeModelAssembler;
private final ManagerModelAssembler managerModelAssembler;
ManagerController(EmployeeModelAssembler employeeModelAssembler, ManagerModelAssembler managerModelAssembler) {
this.employeeModelAssembler = employeeModelAssembler;
this.managerModelAssembler = managerModelAssembler;
}
@GetMapping("{id}")
public ManagerModel getById(@PathVariable String id) {
Manager manager = new Manager(id, "first-name", "last-name", Set.of("1", "2", "3"));
return this.managerModelAssembler.toModel(manager);
}
@GetMapping("{id}/reports")
public CollectionModel<EmployeeModel> reports(@PathVariable String id) {
List<Employee> employees = List.of(new Employee("1", "first-name-1", "last-name-1", "1"),
new Employee("2", "first-name-2", "last-name-2", "1"),
new Employee("3", "first-name-3", "last-name-3", "1"));
return employeeModelAssembler.toCollectionModel(employees).withFallbackType(EmployeeModel.class)
.add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(ManagerController.class).reports(id))
.withSelfRel());
}
}

View File

@@ -0,0 +1,34 @@
package com.example.hateoas.assembler;
import com.example.hateoas.EmployeeController;
import com.example.hateoas.model.Employee;
import com.example.hateoas.model.EmployeeModel;
import com.example.hateoas.model.Manager;
import org.springframework.hateoas.server.EntityLinks;
import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport;
import org.springframework.stereotype.Component;
@Component
public class EmployeeModelAssembler extends RepresentationModelAssemblerSupport<Employee, EmployeeModel> {
private final EntityLinks entityLinks;
EmployeeModelAssembler(EntityLinks entityLinks) {
super(EmployeeController.class, EmployeeModel.class);
this.entityLinks = entityLinks;
}
@Override
protected EmployeeModel instantiateModel(Employee entity) {
return new EmployeeModel(entity);
}
@Override
public EmployeeModel toModel(Employee entity) {
EmployeeModel model = createModelWithId(entity.getId(), entity);
model.add(this.entityLinks.linkToItemResource(Manager.class, entity.getManagerId()).withRel("manager"));
return model;
}
}

View File

@@ -0,0 +1,31 @@
package com.example.hateoas.assembler;
import com.example.hateoas.ManagerController;
import com.example.hateoas.model.Manager;
import com.example.hateoas.model.ManagerModel;
import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
import org.springframework.stereotype.Component;
@Component
public class ManagerModelAssembler extends RepresentationModelAssemblerSupport<Manager, ManagerModel> {
public ManagerModelAssembler() {
super(ManagerController.class, ManagerModel.class);
}
@Override
public ManagerModel toModel(Manager entity) {
ManagerModel model = createModelWithId(entity.getId(), entity);
model.add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(ManagerController.class).reports(entity.getId()))
.withRel("reports"));
return model;
}
@Override
protected ManagerModel instantiateModel(Manager entity) {
return new ManagerModel(entity);
}
}

View File

@@ -0,0 +1,39 @@
package com.example.hateoas.model;
import org.springframework.hateoas.server.core.Relation;
@Relation(itemRelation = "employee", collectionRelation = "employees")
public class Employee {
private final String id;
private final String firstName;
private final String lastName;
private final String managerId;
public Employee(String id, String firstName, String lastName, String managerId) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.managerId = managerId;
}
public String getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getManagerId() {
return managerId;
}
}

View File

@@ -0,0 +1,11 @@
package com.example.hateoas.model;
import org.springframework.hateoas.EntityModel;
public class EmployeeModel extends EntityModel<Employee> {
public EmployeeModel(Employee employee) {
super(employee);
}
}

View File

@@ -0,0 +1,41 @@
package com.example.hateoas.model;
import java.util.Set;
import org.springframework.hateoas.server.core.Relation;
@Relation(itemRelation = "manager", collectionRelation = "managers")
public class Manager {
private final String id;
private final String firstName;
private final String lastName;
private final Set<String> reports;
public Manager(String id, String firstName, String lastName, Set<String> reports) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.reports = reports;
}
public String getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Set<String> getReports() {
return reports;
}
}

View File

@@ -0,0 +1,11 @@
package com.example.hateoas.model;
import org.springframework.hateoas.EntityModel;
public class ManagerModel extends EntityModel<Manager> {
public ManagerModel(Manager manager) {
super(manager);
}
}

View File

@@ -0,0 +1,14 @@
package com.example.hateoas;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class HateoasApplicationTests {
@Test
void contextLoads() {
}
}

View File

@@ -40,6 +40,7 @@ include "conditional"
include "configuration-properties"
include "data-jdbc"
include "data-jpa"
include "hateoas"
include "jdbc"
include "logging-log4j2"
include "scheduled"