Add 'hateoas' sample
This commit is contained in:
@@ -12,6 +12,7 @@ smoke_tests:
|
||||
- configuration-properties
|
||||
- data-jdbc
|
||||
- data-jpa
|
||||
- hateoas
|
||||
- jdbc
|
||||
- logging-log4j2
|
||||
- security-webflux
|
||||
|
||||
1
hateoas/README.adoc
Normal file
1
hateoas/README.adoc
Normal file
@@ -0,0 +1 @@
|
||||
Tests if Spring HATEOAS is working.
|
||||
19
hateoas/build.gradle
Normal file
19
hateoas/build.gradle
Normal 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
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
41
hateoas/src/main/java/com/example/hateoas/model/Manager.java
Normal file
41
hateoas/src/main/java/com/example/hateoas/model/Manager.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,6 +40,7 @@ include "conditional"
|
||||
include "configuration-properties"
|
||||
include "data-jdbc"
|
||||
include "data-jpa"
|
||||
include "hateoas"
|
||||
include "jdbc"
|
||||
include "logging-log4j2"
|
||||
include "scheduled"
|
||||
|
||||
Reference in New Issue
Block a user