Initial commit
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas;
|
||||
|
||||
/**
|
||||
* Analogous to {@link ResourceAssembler} but for resource collections.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public interface ResourcesAssembler<T, D extends ResourceSupport> {
|
||||
|
||||
/**
|
||||
* Converts all given entities into resources and wraps the collection as a resource as well.
|
||||
*
|
||||
* @see ResourceAssembler#toResource(Object)
|
||||
* @param entities must not be {@literal null}.
|
||||
* @return {@link Resources} containing {@link Resource} of {@code T}.
|
||||
*/
|
||||
Resources<D> toResources(Iterable<? extends T> entities);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas;
|
||||
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.hateoas.core.EvoInflectorRelProvider;
|
||||
import org.springframework.hateoas.mvc.ControllerLinkBuilder;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public class SimpleIdentifiableResourceAssembler<T extends Identifiable<?>> extends SimpleResourceAssembler<T> {
|
||||
|
||||
/**
|
||||
* The Spring MVC class for the {@link Identifiable} from which links will be built.
|
||||
*/
|
||||
private final Class<?> controllerClass;
|
||||
|
||||
/**
|
||||
* A {@link RelProvider} to look up names of links as options for resource paths.
|
||||
*/
|
||||
private final RelProvider relProvider;
|
||||
|
||||
/**
|
||||
* A {@link Class} depicting the {@link Identifiable}'s type.
|
||||
*/
|
||||
private final Class<?> resourceType;
|
||||
|
||||
/**
|
||||
* Default base path as empty.
|
||||
*/
|
||||
private String basePath = "";
|
||||
|
||||
/**
|
||||
* Default a assembler based on Spring MVC controller, resource type, and {@link RelProvider}. With this combination
|
||||
* of information, resources can be defined.
|
||||
*
|
||||
* @see #setBasePath(String) to adjust base path to something like "/api"/
|
||||
*
|
||||
* @param controllerClass - Spring MVC controller to base links off of
|
||||
* @param relProvider
|
||||
*/
|
||||
public SimpleIdentifiableResourceAssembler(Class<?> controllerClass, RelProvider relProvider) {
|
||||
|
||||
this.controllerClass = controllerClass;
|
||||
this.relProvider = relProvider;
|
||||
|
||||
// Find the "T" type contained in "T extends Identifiable<?>", e.g. SimpleIdentifiableResourceAssembler<User> -> User
|
||||
this.resourceType = GenericTypeResolver.resolveTypeArgument(this.getClass(), SimpleIdentifiableResourceAssembler.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternate constructor that falls back to {@link EvoInflectorRelProvider}.
|
||||
*
|
||||
* @param controllerClass
|
||||
*/
|
||||
public SimpleIdentifiableResourceAssembler(Class<?> controllerClass) {
|
||||
this(controllerClass, new EvoInflectorRelProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* Define links to add to every {@link Resource}.
|
||||
*
|
||||
* @param resource
|
||||
*/
|
||||
@Override
|
||||
protected void addLinks(Resource<T> resource) {
|
||||
|
||||
resource.add(getCollectionLinkBuilder().slash(resource.getContent()).withSelfRel());
|
||||
resource.add(getCollectionLinkBuilder().withRel(this.relProvider.getCollectionResourceRelFor(this.resourceType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define links to add to {@link Resources} collection.
|
||||
*
|
||||
* @param resources
|
||||
*/
|
||||
@Override
|
||||
protected void addLinks(Resources<Resource<T>> resources) {
|
||||
resources.add(getCollectionLinkBuilder().withSelfRel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Build up a URI for the collection using the Spring MVC controller followed by the resource type transformed
|
||||
* by the {@link RelProvider}.
|
||||
*
|
||||
* Assumption is that an {@link org.springframework.hateoas.examples.EmployeeController} serving up {@link org.springframework.hateoas.examples.Employee}
|
||||
* objects will be serving resources at {@code /employees} and {@code /employees/1}.
|
||||
*
|
||||
* If this is not the case, simply override this method in your concrete instance, or simply resort to
|
||||
* overriding {@link #addLinks(Resource)} and {@link #addLinks(Resources)} where you have full control over exactly
|
||||
* what links are put in the individual and collection resources.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected LinkBuilder getCollectionLinkBuilder() {
|
||||
|
||||
ControllerLinkBuilder linkBuilder = linkTo(this.controllerClass);
|
||||
|
||||
for (String pathComponent : (getPrefix() + this.relProvider.getCollectionResourceRelFor(this.resourceType)).split("/")) {
|
||||
if (!pathComponent.isEmpty()) {
|
||||
linkBuilder = linkBuilder.slash(pathComponent);
|
||||
}
|
||||
}
|
||||
|
||||
return linkBuilder;
|
||||
}
|
||||
|
||||
private String getPrefix() {
|
||||
return getBasePath().isEmpty() ? "" : getBasePath() + "/";
|
||||
}
|
||||
|
||||
public String getBasePath() {
|
||||
return this.basePath;
|
||||
}
|
||||
|
||||
public void setBasePath(String basePath) {
|
||||
this.basePath = basePath;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ResourceAssembler}/{@link ResourcesAssembler} that focuses purely on the domain type,
|
||||
* returning back {@link Resource} and {@link Resources} for that type instead of
|
||||
* {@link org.springframework.hateoas.ResourceSupport}.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public class SimpleResourceAssembler<T> implements ResourceAssembler<T, Resource<T>>, ResourcesAssembler<T, Resource<T>> {
|
||||
|
||||
/**
|
||||
* Converts the given entity into a {@link Resource}.
|
||||
*
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Resource<T> toResource(T entity) {
|
||||
|
||||
Resource<T> resource = new Resource<T>(entity);
|
||||
|
||||
addLinks(resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all given entities into resources and wraps the collection as a resource as well.
|
||||
*
|
||||
* @see #toResource(Object)
|
||||
* @param entities must not be {@literal null}.
|
||||
* @return {@link Resources} containing {@link Resource} of {@code T}.
|
||||
*/
|
||||
public Resources<Resource<T>> toResources(Iterable<? extends T> entities) {
|
||||
|
||||
Assert.notNull(entities, "Entities must not be null!");
|
||||
List<Resource<T>> result = new ArrayList<Resource<T>>();
|
||||
|
||||
for (T entity : entities) {
|
||||
result.add(toResource(entity));
|
||||
}
|
||||
|
||||
Resources<Resource<T>> resources = new Resources<>(result);
|
||||
|
||||
addLinks(resources);
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define links to add to every individual {@link Resource}.
|
||||
*
|
||||
* @param resource
|
||||
*/
|
||||
protected void addLinks(Resource<T> resource) {
|
||||
// Default adds no links
|
||||
}
|
||||
|
||||
/**
|
||||
* Define links to add to the {@link Resources} collection.
|
||||
*
|
||||
* @param resources
|
||||
*/
|
||||
protected void addLinks(Resources<Resource<T>> resources) {
|
||||
// Default adds no links.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.examples;
|
||||
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Pre-load some data using a Spring Boot {@link CommandLineRunner}.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@Component
|
||||
public class DatabaseLoader {
|
||||
|
||||
/**
|
||||
* Use Spring to inject a {@link EmployeeRepository} that can then load data. Since this will run
|
||||
* only after the app is operational, the database will be up.
|
||||
*
|
||||
* @param repository
|
||||
*/
|
||||
@Bean
|
||||
CommandLineRunner init(EmployeeRepository repository) {
|
||||
return args -> {
|
||||
repository.save(new Employee("Frodo", "Baggins", "ring bearer"));
|
||||
repository.save(new Employee("Bilbo", "Baggins", "burglar"));
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.examples;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import org.springframework.hateoas.Identifiable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
/**
|
||||
* Domain object representing a company employee. Project Lombok keeps actual code at a minimum.
|
||||
*
|
||||
* {@code @Data} - Generates getters, setters, toString, hash, and equals functions
|
||||
* {@code @Entity} - JPA annotation to flag this class for DB persistence
|
||||
* {@code @NoArgsConstructor} - Create a constructor with no args to support JPA
|
||||
* {@code @AllArgsConstructor} - Create a constructor with all args to support testing
|
||||
*
|
||||
* {@code @JsonIgnoreProperties(ignoreUnknow=true)}
|
||||
* When converting JSON to Java, ignore any unrecognized attributes. This is critical for REST because it
|
||||
* encourages adding new fields in later versions that won't break. It also allows things like _links to be
|
||||
* ignore as well, meaning HAL documents can be fetched and later posted to the server without adjustment.
|
||||
*
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Employee implements Identifiable<Long> {
|
||||
|
||||
@Id @GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
private String role;
|
||||
|
||||
/**
|
||||
* Useful constructor when id is not yet known.
|
||||
*
|
||||
* @param firstName
|
||||
* @param lastName
|
||||
* @param role
|
||||
*/
|
||||
Employee(String firstName, String lastName, String role) {
|
||||
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will create another piece of data in the REST resource representation. These types
|
||||
* of methods are key in supporting backward compatibility.
|
||||
*
|
||||
* By NOT removing old fields, and instead replacing them with methods like this, an API can evolve
|
||||
* without breaking old clients.
|
||||
*
|
||||
* Because of {@code @JsonIgnoreProperties} settings above, this attribute will be ignore if sent back
|
||||
* to the server, allowing API evolution.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getFullName() {
|
||||
return firstName + " " + lastName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.examples;
|
||||
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Spring Web {@link RestController} used to generate a REST API.
|
||||
*
|
||||
* Works by injecting an {@link EmployeeRepository} and an {@link EmployeeResourceAssembler} in the constructor, both
|
||||
* of which are used to retrieve data from the database, and assemble a REST resource.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@RestController
|
||||
public class EmployeeController {
|
||||
|
||||
private final EmployeeRepository repository;
|
||||
private final EmployeeResourceAssembler assembler;
|
||||
|
||||
public EmployeeController(EmployeeRepository repository,
|
||||
EmployeeResourceAssembler assembler) {
|
||||
|
||||
this.repository = repository;
|
||||
this.assembler = assembler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up all employees, and transform them into a REST collection resource using
|
||||
* {@link EmployeeResourceAssembler#toResources(Iterable)}. Then return them through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* NOTE: cURL will fetch things as HAL JSON directly, but browsers issue a different
|
||||
* default accept header, which allows XML to get requested first, so "produces"
|
||||
* forces it to HAL JSON for all clients.
|
||||
*/
|
||||
@GetMapping(value = "/employees", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
public ResponseEntity<Resources<Resource<Employee>>> findAll() {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResources(repository.findAll()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a single {@link Employee} and transform into a REST resource using
|
||||
* {@link EmployeeResourceAssembler#toResource(Object)}. Then return it through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* See {@link #findAll()} to explain "produces".
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@GetMapping(value = "/employees/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
public ResponseEntity<Resource<Employee>> findOne(@PathVariable String id) {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResource(repository.findOne(Long.valueOf(id))));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.examples;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public interface EmployeeRepository extends CrudRepository<Employee, Long> {
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.examples;
|
||||
|
||||
import org.springframework.hateoas.SimpleIdentifiableResourceAssembler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@Component
|
||||
public class EmployeeResourceAssembler extends SimpleIdentifiableResourceAssembler<Employee> {
|
||||
|
||||
/**
|
||||
* Link the {@link Employee} domain type to the {@link EmployeeController} using this
|
||||
* {@link SimpleIdentifiableResourceAssembler} in order to generate both {@link org.springframework.hateoas.Resource}
|
||||
* and {@link org.springframework.hateoas.Resources}.
|
||||
*/
|
||||
public EmployeeResourceAssembler() {
|
||||
super(EmployeeController.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.hateoas.examples;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.hateoas.core.EvoInflectorRelProvider;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SpringHateoasBasicsApplication {
|
||||
|
||||
public static void main(String... args) {
|
||||
SpringApplication.run(SpringHateoasBasicsApplication.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format embedded collections by pluralizing the resource's type.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
EvoInflectorRelProvider relProvider() {
|
||||
return new EvoInflectorRelProvider();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.hateoas;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import lombok.Data;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public class SimpleResourceAssemblerTest {
|
||||
|
||||
@Test
|
||||
public void convertingToResourceShouldWork() {
|
||||
|
||||
TestResourceAssembler assembler = new TestResourceAssembler();
|
||||
Resource<Employee> resource = assembler.toResource(new Employee("Frodo"));
|
||||
assertThat(resource.getContent().getName(), is("Frodo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertingToResourcesShouldWork() {
|
||||
|
||||
TestResourceAssembler assembler = new TestResourceAssembler();
|
||||
Resources<Resource<Employee>> resources = assembler.toResources(Arrays.asList(new Employee("Frodo")));
|
||||
assertThat(resources.getContent(), hasSize(1));
|
||||
assertThat(resources.getContent(), Matchers.<Resource<Employee>>contains(new Resource(new Employee("Frodo"))));
|
||||
assertThat(resources.getLinks(), is(Matchers.<Link>empty()));
|
||||
|
||||
assertThat(resources.getContent().iterator().next(), is(new Resource(new Employee("Frodo"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertingToResourceWithCustomLinksShouldWork() {
|
||||
|
||||
ResourceAssemblerWithCustomLink assembler = new ResourceAssemblerWithCustomLink();
|
||||
Resource<Employee> resource = assembler.toResource(new Employee("Frodo"));
|
||||
assertThat(resource.getContent().getName(), is("Frodo"));
|
||||
assertThat(resource.getLinks(), hasSize(1));
|
||||
assertThat(resource.getLinks(), hasItem(new Link("/employees").withRel("employees")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertingToResourcesWithCustomLinksShouldWork() {
|
||||
|
||||
ResourceAssemblerWithCustomLink assembler = new ResourceAssemblerWithCustomLink();
|
||||
Resources<Resource<Employee>> resources = assembler.toResources(Arrays.asList(new Employee("Frodo")));
|
||||
assertThat(resources.getContent(), hasSize(1));
|
||||
assertThat(resources.getContent(),
|
||||
Matchers.<Resource<Employee>>contains(new Resource(new Employee("Frodo"), new Link("/employees").withRel("employees"))));
|
||||
assertThat(resources.getLinks(), is(Matchers.<Link>empty()));
|
||||
|
||||
assertThat(resources.getContent().iterator().next(),
|
||||
is(new Resource(new Employee("Frodo"), new Link("/employees").withRel("employees"))));
|
||||
}
|
||||
|
||||
|
||||
class TestResourceAssembler extends SimpleResourceAssembler<Employee> {}
|
||||
|
||||
class ResourceAssemblerWithCustomLink extends SimpleResourceAssembler<Employee> {
|
||||
|
||||
@Override
|
||||
protected void addLinks(Resource<Employee> resource) {
|
||||
resource.add(new Link("/employees").withRel("employees"));
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
class Employee {
|
||||
private final String name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.examples;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(EmployeeController.class)
|
||||
@Import({EmployeeResourceAssembler.class})
|
||||
public class EmployeeControllerTests {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
|
||||
@MockBean
|
||||
private EmployeeRepository repository;
|
||||
|
||||
@Test
|
||||
public void noop() throws Exception {
|
||||
|
||||
given(repository.findAll()).willReturn(
|
||||
Arrays.asList(
|
||||
new Employee(1L,"Frodo", "Baggins", "ring bearer"),
|
||||
new Employee(2L,"Bilbo", "Baggins", "burglar")));
|
||||
|
||||
mvc.perform(get("/employees").accept(MediaTypes.HAL_JSON_VALUE))
|
||||
.andDo(print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8"))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].id", is(1)))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].firstName", is("Frodo")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].lastName", is("Baggins")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].role", is("ring bearer")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0]._links.self.href", is("http://localhost/employees/1")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0]._links.employees.href", is("http://localhost/employees")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].id", is(2)))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].firstName", is("Bilbo")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].lastName", is("Baggins")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].role", is("burglar")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1]._links.self.href", is("http://localhost/employees/2")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1]._links.employees.href", is("http://localhost/employees")))
|
||||
.andExpect(jsonPath("$._links.self.href", is("http://localhost/employees")))
|
||||
.andReturn();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user