#695 - Remove Jaxb annotations.
By removing all Jaxb annotations, requesting data from a hypermedia-enabled endpoint inside a browser (which defaults to accept:application/xhtml+xml,*/*), Spring HATEOAS will yield HAL.
This commit is contained in:
@@ -30,10 +30,6 @@ import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -47,7 +43,6 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@XmlType(name = "link", namespace = Link.ATOM_NAMESPACE)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(value = "templated", ignoreUnknown = true)
|
||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
@@ -66,15 +61,15 @@ public class Link implements Serializable {
|
||||
public static final String REL_NEXT = "next";
|
||||
public static final String REL_LAST = "last";
|
||||
|
||||
private @XmlAttribute @Wither String rel;
|
||||
private @XmlAttribute @Wither String href;
|
||||
private @XmlAttribute @Wither String hreflang;
|
||||
private @XmlAttribute @Wither String media;
|
||||
private @XmlAttribute @Wither String title;
|
||||
private @XmlAttribute @Wither String type;
|
||||
private @XmlAttribute @Wither String deprecation;
|
||||
private @XmlTransient @JsonIgnore UriTemplate template;
|
||||
private @XmlTransient @JsonIgnore List<Affordance> affordances;
|
||||
private @Wither String rel;
|
||||
private @Wither String href;
|
||||
private @Wither String hreflang;
|
||||
private @Wither String media;
|
||||
private @Wither String title;
|
||||
private @Wither String type;
|
||||
private @Wither String deprecation;
|
||||
private @JsonIgnore UriTemplate template;
|
||||
private @JsonIgnore List<Affordance> affordances;
|
||||
|
||||
/**
|
||||
* Creates a new link to the given URI with the self rel.
|
||||
|
||||
@@ -20,9 +20,6 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
@@ -33,10 +30,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "pagedEntities")
|
||||
public class PagedResources<T> extends Resources<T> {
|
||||
|
||||
public static PagedResources<?> NO_PAGE = new PagedResources<Object>();
|
||||
public static PagedResources<?> NO_PAGE = new PagedResources<>();
|
||||
|
||||
private PageMetadata metadata;
|
||||
|
||||
@@ -169,10 +165,10 @@ public class PagedResources<T> extends Resources<T> {
|
||||
*/
|
||||
public static class PageMetadata {
|
||||
|
||||
@XmlAttribute @JsonProperty private long size;
|
||||
@XmlAttribute @JsonProperty private long totalElements;
|
||||
@XmlAttribute @JsonProperty private long totalPages;
|
||||
@XmlAttribute @JsonProperty private long number;
|
||||
@JsonProperty private long size;
|
||||
@JsonProperty private long totalElements;
|
||||
@JsonProperty private long totalPages;
|
||||
@JsonProperty private long number;
|
||||
|
||||
protected PageMetadata() {
|
||||
|
||||
|
||||
@@ -18,9 +18,6 @@ package org.springframework.hateoas;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAnyElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||
@@ -31,7 +28,6 @@ import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class Resource<T> extends ResourceSupport {
|
||||
|
||||
private final T content;
|
||||
@@ -73,7 +69,6 @@ public class Resource<T> extends ResourceSupport {
|
||||
* @return the content
|
||||
*/
|
||||
@JsonUnwrapped
|
||||
@XmlAnyElement
|
||||
public T getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
@@ -104,7 +102,6 @@ public class ResourceSupport implements Identifiable<Link> {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@XmlElement(name = "link", namespace = Link.ATOM_NAMESPACE)
|
||||
@JsonProperty("links")
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
|
||||
@@ -21,10 +21,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAnyElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -34,7 +30,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "entities")
|
||||
public class Resources<T> extends ResourceSupport implements Iterable<T> {
|
||||
|
||||
private final Collection<T> content;
|
||||
@@ -98,8 +93,6 @@ public class Resources<T> extends ResourceSupport implements Iterable<T> {
|
||||
*
|
||||
* @return the content will never be {@literal null}.
|
||||
*/
|
||||
@XmlAnyElement
|
||||
@XmlElementWrapper
|
||||
@JsonProperty("content")
|
||||
public Collection<T> getContent() {
|
||||
return Collections.unmodifiableCollection(content);
|
||||
|
||||
@@ -20,11 +20,6 @@ import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -38,10 +33,8 @@ import com.fasterxml.jackson.annotation.JsonValue;
|
||||
* @see https://github.com/blongden/vnd.error
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "errors")
|
||||
public class VndErrors implements Iterable<VndErrors.VndError> {
|
||||
|
||||
@XmlElement(name = "error")//
|
||||
private final List<VndError> vndErrors;
|
||||
|
||||
/**
|
||||
@@ -162,11 +155,10 @@ public class VndErrors implements Iterable<VndErrors.VndError> {
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlType
|
||||
public static class VndError extends ResourceSupport {
|
||||
|
||||
@XmlAttribute @JsonProperty private final String logref;
|
||||
@XmlElement @JsonProperty private final String message;
|
||||
@JsonProperty private final String logref;
|
||||
@JsonProperty private final String message;
|
||||
|
||||
/**
|
||||
* Creates a new {@link VndError} with the given logref, a message as well as some {@link Link}s.
|
||||
|
||||
@@ -17,8 +17,6 @@ package org.springframework.hateoas.hal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
|
||||
@@ -38,7 +36,6 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
public abstract class ResourceSupportMixin extends ResourceSupport {
|
||||
|
||||
@Override
|
||||
@XmlElement(name = "link")
|
||||
@JsonProperty("_links")
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
@JsonSerialize(using = Jackson2HalModule.HalLinkListSerializer.class)
|
||||
|
||||
@@ -17,8 +17,6 @@ package org.springframework.hateoas.hal;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
||||
import org.springframework.hateoas.Resources;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
@@ -39,7 +37,6 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
public abstract class ResourcesMixin<T> extends Resources<T> {
|
||||
|
||||
@Override
|
||||
@XmlElement(name = "embedded")
|
||||
@JsonProperty("_embedded")
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
@JsonSerialize(using = Jackson2HalModule.HalResourcesSerializer.class)
|
||||
|
||||
@@ -19,8 +19,6 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.hateoas.Link;
|
||||
@@ -89,7 +87,6 @@ public class Jackson2HalFormsModule extends SimpleModule {
|
||||
abstract class ResourcesMixin<T> extends Resources<T> {
|
||||
|
||||
@Override
|
||||
@XmlElement(name = "embedded")
|
||||
@JsonProperty("_embedded")
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
@JsonDeserialize(using = HalFormsResourcesDeserializer.class)
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-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.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
/**
|
||||
* Test for marshalling / unmarshalling of {@link PagedResources}.
|
||||
*
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
public class PagedResourcesMarshallingTest {
|
||||
|
||||
Marshaller marshaller;
|
||||
Unmarshaller unmarshaller;
|
||||
|
||||
String xmlReference;
|
||||
PagedResources<Inner> pagedResources;
|
||||
|
||||
public PagedResourcesMarshallingTest() throws IOException {
|
||||
xmlReference = readFile(new ClassPathResource("pagedresources.xml"));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
JAXBContext context = JAXBContext.newInstance(PagedResources.class);
|
||||
marshaller = context.createMarshaller();
|
||||
unmarshaller = context.createUnmarshaller();
|
||||
|
||||
pagedResources = new PagedResources<>(new ArrayList<>(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #98
|
||||
*/
|
||||
@Test
|
||||
public void jaxbUnMarshalling() throws Exception {
|
||||
|
||||
assertThat(unmarshaller.unmarshal(new StringReader(xmlReference))).isEqualTo(pagedResources);
|
||||
}
|
||||
|
||||
public static class Inner {}
|
||||
|
||||
private static String readFile(org.springframework.core.io.Resource resource) throws IOException {
|
||||
|
||||
try (FileInputStream stream = new FileInputStream(resource.getFile())) {
|
||||
FileChannel fc = stream.getChannel();
|
||||
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
|
||||
return Charset.defaultCharset().decode(bb).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,6 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
|
||||
public class ResourceIntegrationTest extends AbstractJackson2MarshallingIntegrationTest {
|
||||
|
||||
static final String REFERENCE = "{\"firstname\":\"Dave\",\"lastname\":\"Matthews\",\"links\":[{\"rel\":\"self\",\"href\":\"localhost\"}]}";
|
||||
static final String XML_REFERENCE = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><personResource xmlns:ns2=\"http://www.w3.org/2005/Atom\"><ns2:link href=\"/foo\" rel=\"bar\"/><person lastname=\"Matthews\" firstname=\"Dave\"/></personResource>";
|
||||
|
||||
@Test
|
||||
public void inlinesContent() throws Exception {
|
||||
@@ -53,29 +52,6 @@ public class ResourceIntegrationTest extends AbstractJackson2MarshallingIntegrat
|
||||
assertThat(write(resource)).isEqualTo(REFERENCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #124
|
||||
* @see #154
|
||||
*/
|
||||
@Test
|
||||
public void marshalsResourceToXml() throws Exception {
|
||||
|
||||
Person person = new Person();
|
||||
person.firstname = "Dave";
|
||||
person.lastname = "Matthews";
|
||||
|
||||
PersonResource resource = new PersonResource(person);
|
||||
resource.add(new Link("/foo", "bar"));
|
||||
|
||||
JAXBContext context = JAXBContext.newInstance(PersonResource.class, Person.class);
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
Marshaller marshaller = context.createMarshaller();
|
||||
marshaller.marshal(resource, writer);
|
||||
|
||||
assertThat(new Diff(XML_REFERENCE, writer.toString()).similar()).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #14
|
||||
*/
|
||||
@@ -90,7 +66,6 @@ public class ResourceIntegrationTest extends AbstractJackson2MarshallingIntegrat
|
||||
assertThat(result.getContent().lastname).isEqualTo("Matthews");
|
||||
}
|
||||
|
||||
@XmlRootElement
|
||||
static class PersonResource extends Resource<Person> {
|
||||
|
||||
public PersonResource(Person person) {
|
||||
@@ -101,10 +76,9 @@ public class ResourceIntegrationTest extends AbstractJackson2MarshallingIntegrat
|
||||
}
|
||||
|
||||
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
|
||||
@XmlRootElement
|
||||
static class Person {
|
||||
|
||||
@XmlAttribute String firstname;
|
||||
@XmlAttribute String lastname;
|
||||
String firstname;
|
||||
String lastname;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,6 @@ import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
public class VndErrorsMarshallingTest {
|
||||
|
||||
ObjectMapper jackson2Mapper;
|
||||
Marshaller marshaller;
|
||||
Unmarshaller unmarshaller;
|
||||
|
||||
RelProvider relProvider = new EvoInflectorRelProvider();
|
||||
|
||||
@@ -74,10 +72,6 @@ public class VndErrorsMarshallingTest {
|
||||
jackson2Mapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(relProvider, null, null));
|
||||
jackson2Mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
|
||||
|
||||
JAXBContext context = JAXBContext.newInstance(VndErrors.class);
|
||||
marshaller = context.createMarshaller();
|
||||
unmarshaller = context.createUnmarshaller();
|
||||
|
||||
VndError error = new VndError("42", "Validation failed!", //
|
||||
new Link("http://...", "describes"), new Link("http://...", "help"));
|
||||
errors = new VndErrors(error, error, error);
|
||||
@@ -91,18 +85,6 @@ public class VndErrorsMarshallingTest {
|
||||
assertThat(jackson2Mapper.writeValueAsString(errors)).isEqualToIgnoringWhitespace(json2Reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #62, #154
|
||||
*/
|
||||
@Test
|
||||
public void jaxbMarshalling() throws Exception {
|
||||
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(errors, writer);
|
||||
|
||||
assertThat(new Diff(xmlReference, writer.toString()).similar()).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #93, #94
|
||||
*/
|
||||
@@ -111,15 +93,6 @@ public class VndErrorsMarshallingTest {
|
||||
assertThat(jackson2Mapper.readValue(jsonReference, VndErrors.class)).isEqualTo(errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #93, #94
|
||||
*/
|
||||
@Test
|
||||
public void jaxbUnMarshalling() throws Exception {
|
||||
VndErrors actual = (VndErrors) unmarshaller.unmarshal(new StringReader(xmlReference));
|
||||
assertThat(actual).isEqualTo(errors);
|
||||
}
|
||||
|
||||
private static String readFile(org.springframework.core.io.Resource resource) throws IOException {
|
||||
|
||||
try (FileInputStream stream = new FileInputStream(resource.getFile())) {
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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.hal;
|
||||
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;
|
||||
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 static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Wither;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.hateoas.config.EnableHypermediaSupport;
|
||||
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebAppConfiguration
|
||||
@ContextConfiguration
|
||||
public class RenderHypermediaForDefaultAcceptHeadersTest {
|
||||
|
||||
@Autowired WebApplicationContext context;
|
||||
|
||||
MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.mockMvc = webAppContextSetup(this.context).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the default {@literal Accept} header used by a browser (which favors XML/HTML) still yields HAL-JSON.
|
||||
*/
|
||||
@Test
|
||||
public void browserBasedDefaultAcceptHeadersShouldProduceHalJson() throws Exception {
|
||||
|
||||
this.mockMvc.perform(get("/employees").accept(MediaType.APPLICATION_XHTML_XML, MediaType.ALL)) //
|
||||
.andDo(print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_UTF8_VALUE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the default {@literal Accept} header used by cURL still yields HAL-JSON.
|
||||
*/
|
||||
@Test
|
||||
public void curlBasedDefaultAcceptHeadersShouldProduceHalJson() throws Exception {
|
||||
|
||||
this.mockMvc.perform(get("/employees").accept(MediaType.ALL)) //
|
||||
.andDo(print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_UTF8_VALUE));
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class EmployeeController {
|
||||
|
||||
private final static Map<Integer, Employee> EMPLOYEES = new TreeMap<>();
|
||||
|
||||
static {
|
||||
EMPLOYEES.put(0, new Employee("Frodo Baggins", "ring bearer"));
|
||||
EMPLOYEES.put(1, new Employee("Bilbo Baggins", "burglar"));
|
||||
}
|
||||
|
||||
@GetMapping("/employees")
|
||||
public Resources<Resource<Employee>> all() {
|
||||
|
||||
// Create a list of Resource<Employee>'s to return
|
||||
List<Resource<Employee>> employees = new ArrayList<>();
|
||||
|
||||
// Fetch each Resource<Employee> using the controller's findOne method.
|
||||
for (int i = 0; i < EMPLOYEES.size(); i++) {
|
||||
employees.add(findOne(i));
|
||||
}
|
||||
|
||||
// Generate an "Affordance" based on this method (the "self" link)
|
||||
Link selfLink = linkTo(methodOn(EmployeeController.class).all()).withSelfRel();
|
||||
|
||||
// Return the collection of employee resources along with the composite affordance
|
||||
return new Resources<>(employees, selfLink);
|
||||
}
|
||||
|
||||
@GetMapping("/employees/{id}")
|
||||
public Resource<Employee> findOne(@PathVariable Integer id) {
|
||||
|
||||
// Start the affordance with the "self" link, i.e. this method.
|
||||
Link findOneLink = linkTo(methodOn(EmployeeController.class).findOne(id)).withSelfRel();
|
||||
|
||||
// Define final link as means to find entire collection.
|
||||
Link employeesLink = linkTo(methodOn(EmployeeController.class).all()).withRel("employees");
|
||||
|
||||
// Return the affordance + a link back to the entire collection resource.
|
||||
return new Resource<>(EMPLOYEES.get(id), findOneLink, employeesLink);
|
||||
}
|
||||
|
||||
@PostMapping("/employees")
|
||||
public ResponseEntity<?> newEmployee(@RequestBody Employee employee) {
|
||||
|
||||
int newEmployeeId = EMPLOYEES.size();
|
||||
|
||||
EMPLOYEES.put(newEmployeeId, employee);
|
||||
|
||||
try {
|
||||
return ResponseEntity.noContent().location(new URI(findOne(newEmployeeId).getLink(Link.REL_SELF).map(link -> link.expand().getHref()).orElse("")))
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/employees/{id}")
|
||||
public ResponseEntity<?> updateEmployee(@RequestBody Employee employee, @PathVariable Integer id) {
|
||||
|
||||
EMPLOYEES.put(id, employee);
|
||||
|
||||
try {
|
||||
return ResponseEntity.noContent().location(new URI(findOne(id).getLink(Link.REL_SELF).map(link -> link.expand().getHref()).orElse("")))
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PatchMapping("/employees/{id}")
|
||||
public ResponseEntity<?> partiallyUpdateEmployee(@RequestBody Employee employee, @PathVariable Integer id) {
|
||||
|
||||
Employee oldEmployee = EMPLOYEES.get(id);
|
||||
Employee newEmployee = oldEmployee;
|
||||
|
||||
if (employee.getName() != null) {
|
||||
newEmployee = newEmployee.withName(employee.getName());
|
||||
}
|
||||
|
||||
if (employee.getRole() != null) {
|
||||
newEmployee = newEmployee.withRole(employee.getRole());
|
||||
}
|
||||
|
||||
EMPLOYEES.put(id, newEmployee);
|
||||
|
||||
try {
|
||||
return ResponseEntity.noContent().location(new URI(findOne(id).getLink(Link.REL_SELF).map(link -> link.expand().getHref()).orElse("")))
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@EnableHypermediaSupport(type = { HypermediaType.HAL })
|
||||
static class TestConfig {
|
||||
|
||||
@Bean
|
||||
EmployeeController employeeController() {
|
||||
return new EmployeeController();
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@Wither
|
||||
static class Employee {
|
||||
|
||||
private final String name;
|
||||
private final String role;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user