TSK-1085: Hateoas self-links which contain variables are not working for Paged representationmodels
Bug Fix * update Aspect * update unit-test and test "href-self" part of json * fix checkstyl-finding
This commit is contained in:
parent
d6c1040bb0
commit
5030415f17
|
@ -1,15 +1,11 @@
|
||||||
package pro.taskana.resource.rest;
|
package pro.taskana.resource.rest;
|
||||||
|
|
||||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.reflect.MethodSignature;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.hateoas.IanaLinkRelations;
|
import org.springframework.hateoas.IanaLinkRelations;
|
||||||
import org.springframework.hateoas.Link;
|
import org.springframework.hateoas.Link;
|
||||||
|
@ -17,6 +13,7 @@ import org.springframework.hateoas.PagedModel.PageMetadata;
|
||||||
import org.springframework.hateoas.RepresentationModel;
|
import org.springframework.hateoas.RepresentationModel;
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,12 +28,7 @@ public class PageLinksAspect {
|
||||||
public <T extends RepresentationModel<? extends T> & ProceedingJoinPoint>
|
public <T extends RepresentationModel<? extends T> & ProceedingJoinPoint>
|
||||||
RepresentationModel<T> addLinksToPageResource(
|
RepresentationModel<T> addLinksToPageResource(
|
||||||
ProceedingJoinPoint joinPoint, List<?> data, PageMetadata page) throws Throwable {
|
ProceedingJoinPoint joinPoint, List<?> data, PageMetadata page) throws Throwable {
|
||||||
HttpServletRequest request =
|
final UriComponentsBuilder original = originalUri();
|
||||||
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
|
||||||
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
|
|
||||||
PageLinks pageLinks = method.getAnnotation(PageLinks.class);
|
|
||||||
String relativeUrl = pageLinks.value();
|
|
||||||
UriComponentsBuilder original = originalUri(relativeUrl, request);
|
|
||||||
RepresentationModel<T> resourceSupport = (RepresentationModel<T>) joinPoint.proceed();
|
RepresentationModel<T> resourceSupport = (RepresentationModel<T>) joinPoint.proceed();
|
||||||
resourceSupport.add(Link.of(original.toUriString()).withSelfRel());
|
resourceSupport.add(Link.of(original.toUriString()).withSelfRel());
|
||||||
if (page != null) {
|
if (page != null) {
|
||||||
|
@ -60,10 +52,11 @@ public class PageLinksAspect {
|
||||||
return resourceSupport;
|
return resourceSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UriComponentsBuilder originalUri(String relativeUrl, HttpServletRequest request) {
|
private UriComponentsBuilder originalUri() {
|
||||||
// argument to linkTo does not matter as we just want to have the default baseUrl
|
final HttpServletRequest request =
|
||||||
UriComponentsBuilder baseUri = linkTo(PageLinksAspect.class).toUriComponentsBuilder();
|
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||||
baseUri.path(relativeUrl);
|
final UriComponentsBuilder baseUri =
|
||||||
|
ServletUriComponentsBuilder.fromServletMapping(request).path(request.getRequestURI());
|
||||||
for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
|
for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
|
||||||
for (String value : entry.getValue()) {
|
for (String value : entry.getValue()) {
|
||||||
baseUri.queryParam(entry.getKey(), value);
|
baseUri.queryParam(entry.getKey(), value);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.taskana.doc.api;
|
package pro.taskana.doc.api;
|
||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||||
|
@ -351,6 +352,8 @@ class WorkbasketControllerRestDocumentation extends BaseRestDocumentation {
|
||||||
.accept("application/hal+json")
|
.accept("application/hal+json")
|
||||||
.header("Authorization", TEAMLEAD_1_CREDENTIALS))
|
.header("Authorization", TEAMLEAD_1_CREDENTIALS))
|
||||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||||
|
.andExpect(MockMvcResultMatchers.jsonPath("_links.self.href",
|
||||||
|
is("http://localhost:8080/api/v1/workbaskets/WBI:100000000000000000000000000000000001")))
|
||||||
.andDo(
|
.andDo(
|
||||||
MockMvcRestDocumentation.document(
|
MockMvcRestDocumentation.document(
|
||||||
"GetSpecificWorkbasketDocTest", responseFields(workbasketFieldDescriptors)));
|
"GetSpecificWorkbasketDocTest", responseFields(workbasketFieldDescriptors)));
|
||||||
|
@ -383,6 +386,8 @@ class WorkbasketControllerRestDocumentation extends BaseRestDocumentation {
|
||||||
.accept("application/hal+json")
|
.accept("application/hal+json")
|
||||||
.header("Authorization", TEAMLEAD_1_CREDENTIALS))
|
.header("Authorization", TEAMLEAD_1_CREDENTIALS))
|
||||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||||
|
.andExpect(MockMvcResultMatchers.jsonPath("_links.self.href",
|
||||||
|
is("http://localhost:8080/api/v1/workbaskets/WBI:100000000000000000000000000000000001")))
|
||||||
.andDo(
|
.andDo(
|
||||||
MockMvcRestDocumentation.document(
|
MockMvcRestDocumentation.document(
|
||||||
"WorkbasketSubset", responseFields(workbasketSubsetFieldDescriptors)));
|
"WorkbasketSubset", responseFields(workbasketSubsetFieldDescriptors)));
|
||||||
|
@ -411,6 +416,8 @@ class WorkbasketControllerRestDocumentation extends BaseRestDocumentation {
|
||||||
"WBI:100000000000000000000000000000000002"))
|
"WBI:100000000000000000000000000000000002"))
|
||||||
.header("Authorization", TEAMLEAD_1_CREDENTIALS))
|
.header("Authorization", TEAMLEAD_1_CREDENTIALS))
|
||||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||||
|
.andExpect(MockMvcResultMatchers.jsonPath("_links.self.href",
|
||||||
|
is("http://localhost:8080/api/v1/workbaskets/WBI:100000000000000000000000000000000002/distribution-targets")))
|
||||||
.andDo(
|
.andDo(
|
||||||
MockMvcRestDocumentation.document(
|
MockMvcRestDocumentation.document(
|
||||||
"GetAllWorkbasketDistributionTargets",
|
"GetAllWorkbasketDistributionTargets",
|
||||||
|
@ -470,6 +477,8 @@ class WorkbasketControllerRestDocumentation extends BaseRestDocumentation {
|
||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
.content(modifiedWorkbasket))
|
.content(modifiedWorkbasket))
|
||||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||||
|
.andExpect(MockMvcResultMatchers.jsonPath("_links.self.href",
|
||||||
|
is("http://localhost:8080/api/v1/workbaskets/WBI:100000000000000000000000000000000002")))
|
||||||
.andDo(
|
.andDo(
|
||||||
MockMvcRestDocumentation.document(
|
MockMvcRestDocumentation.document(
|
||||||
"UpdateWorkbasketDocTest",
|
"UpdateWorkbasketDocTest",
|
||||||
|
@ -500,6 +509,8 @@ class WorkbasketControllerRestDocumentation extends BaseRestDocumentation {
|
||||||
.accept("application/hal+json")
|
.accept("application/hal+json")
|
||||||
.header("Authorization", TEAMLEAD_1_CREDENTIALS))
|
.header("Authorization", TEAMLEAD_1_CREDENTIALS))
|
||||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||||
|
.andExpect(MockMvcResultMatchers.jsonPath("_links.self.href",
|
||||||
|
is("http://localhost:8080/api/v1/workbaskets/WBI:100000000000000000000000000000000001/workbasketAccessItems")))
|
||||||
.andDo(
|
.andDo(
|
||||||
MockMvcRestDocumentation.document(
|
MockMvcRestDocumentation.document(
|
||||||
"AccessItemsDocTest", responseFields(accessItemFieldDescriptors)));
|
"AccessItemsDocTest", responseFields(accessItemFieldDescriptors)));
|
||||||
|
|
|
@ -5,11 +5,13 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import static pro.taskana.common.rest.RestHelper.TEMPLATE;
|
import static pro.taskana.common.rest.RestHelper.TEMPLATE;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Optional;
|
||||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
import org.springframework.hateoas.IanaLinkRelations;
|
import org.springframework.hateoas.IanaLinkRelations;
|
||||||
|
import org.springframework.hateoas.Link;
|
||||||
import org.springframework.hateoas.MediaTypes;
|
import org.springframework.hateoas.MediaTypes;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
@ -49,14 +51,18 @@ class WorkbasketControllerIntTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetWorkbasket() {
|
void testGetWorkbasket() {
|
||||||
|
final String url = restHelper.toUrl(Mapping.URL_WORKBASKET_ID,
|
||||||
|
"WBI:100000000000000000000000000000000006");
|
||||||
ResponseEntity<WorkbasketRepresentationModel> response =
|
ResponseEntity<WorkbasketRepresentationModel> response =
|
||||||
TEMPLATE.exchange(
|
TEMPLATE.exchange(
|
||||||
restHelper.toUrl(Mapping.URL_WORKBASKET_ID, "WBI:100000000000000000000000000000000006"),
|
url,
|
||||||
HttpMethod.GET,
|
HttpMethod.GET,
|
||||||
restHelper.defaultRequest(),
|
restHelper.defaultRequest(),
|
||||||
ParameterizedTypeReference.forType(WorkbasketRepresentationModel.class));
|
ParameterizedTypeReference.forType(WorkbasketRepresentationModel.class));
|
||||||
assertThat(response.getBody()).isNotNull();
|
assertThat(response.getBody()).isNotNull();
|
||||||
assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull();
|
assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull();
|
||||||
|
assertThat(response.getBody().getLink(IanaLinkRelations.SELF))
|
||||||
|
.isEqualTo(Optional.of(Link.of(url)));
|
||||||
assertThat(response.getHeaders().getContentType()).isEqualTo(MediaTypes.HAL_JSON);
|
assertThat(response.getHeaders().getContentType()).isEqualTo(MediaTypes.HAL_JSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue