Skip to content

Commit 6ec23a7

Browse files
committed
Update version to 1.10.1
Fix missing @NoArgsConstructor annotation on Meta class for proper jackson response deserialization
1 parent cfcb19b commit 6ec23a7

7 files changed

Lines changed: 200 additions & 85 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## [1.10.1] - 2023-06-17
4+
### Fixed:
5+
- Missing **@NoArgsConstructor** annotation on **Meta** class for proper jackson response deserialization
6+
37
## [1.10.0] - 2023-02-21
48
### Changed:
59
- Add id field to attributes (more usable for api clients)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Add dependency to your project:
1616
<dependency>
1717
<groupId>com.slm-dev</groupId>
1818
<artifactId>jsonapi-simple</artifactId>
19-
<version>1.10.0</version>
19+
<version>1.10.1</version>
2020
</dependency>
2121
```
2222

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<modelVersion>4.0.0</modelVersion>
55
<groupId>com.slm-dev</groupId>
66
<artifactId>jsonapi-simple</artifactId>
7-
<version>1.10.0</version>
7+
<version>1.10.1</version>
88
<name>jsonapi-simple</name>
99
<description>Simple implementation of the JSON:API specification</description>
1010
<url>https://slm-dev.com/jsonapi-simple/</url>

src/main/java/com/slmdev/jsonapi/simple/response/Meta.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class Meta {
1919
private Trace trace;
2020

2121
@Data
22+
@NoArgsConstructor
2223
@AllArgsConstructor
2324
@JsonInclude(JsonInclude.Include.NON_NULL)
2425
public static class Page {
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.slmdev.jsonapi.simple.response;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.fasterxml.jackson.databind.json.JsonMapper;
5+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
6+
import lombok.NonNull;
7+
import org.springframework.http.HttpStatus;
8+
9+
import java.time.LocalDateTime;
10+
import java.time.ZoneOffset;
11+
import java.util.List;
12+
import java.util.Map;
13+
import java.util.UUID;
14+
15+
import static org.hamcrest.MatcherAssert.assertThat;
16+
import static org.hamcrest.Matchers.*;
17+
18+
abstract class BaseTest {
19+
protected static final String TEST_RESPONSE_URI = "/api/v1";
20+
protected static final UUID TEST_DTO_1_ID = UUID.randomUUID();
21+
protected static final String TEST_DTO_1_NAME = "TEST-1";
22+
protected static final LocalDateTime TEST_DTO_1_DATE_CREATE = LocalDateTime.now(ZoneOffset.UTC);
23+
protected static final UUID TEST_DTO_2_ID = UUID.randomUUID();
24+
protected static final String TEST_DTO_2_NAME = "TEST-2";
25+
protected static final LocalDateTime TEST_DTO_2_DATE_CREATE = LocalDateTime.now(ZoneOffset.UTC);
26+
protected static final String ERROR_CODE = "TEST_ERROR_CODE";
27+
protected static final String ERROR_DESCRIPTION = "TEST";
28+
29+
protected final ObjectMapper objectMapper = JsonMapper.builder()
30+
.addModule(new JavaTimeModule())
31+
.build();
32+
33+
protected TestDto buildTestDto1() {
34+
return new TestDto()
35+
.setId(TEST_DTO_1_ID)
36+
.setName(TEST_DTO_1_NAME)
37+
.setCreateDate(TEST_DTO_1_DATE_CREATE);
38+
}
39+
40+
protected TestDto buildTestDto2() {
41+
return new TestDto()
42+
.setId(TEST_DTO_2_ID)
43+
.setName(TEST_DTO_2_NAME)
44+
.setCreateDate(TEST_DTO_2_DATE_CREATE);
45+
}
46+
47+
protected String buildSelfLink(final @NonNull TestDto testDto) {
48+
return buildSelfLink("", testDto);
49+
}
50+
51+
protected String buildSelfLink(final @NonNull String uri, final @NonNull TestDto testDto) {
52+
return uri + "/" + TestDto.API_TYPE + "/" + testDto.getId();
53+
}
54+
55+
protected void assertResponseErrorCode(final @NonNull Response<?> response) {
56+
assertThat(response.getErrors().get(0).getCode(), is(ERROR_CODE));
57+
}
58+
59+
protected void assertErrorResponse(final @NonNull Response<?> response) {
60+
assertThat(response.getData(), nullValue());
61+
62+
assertThat(response.getErrors().get(0).getStatus(), is(HttpStatus.BAD_REQUEST.value()));
63+
assertThat(response.getErrors().get(0).getDetail(), is(ERROR_DESCRIPTION));
64+
65+
assertThat(response.getMeta().getApi().getVersion(), is("1"));
66+
assertThat(response.getMeta().getPage().getMaxSize(), is(25));
67+
assertThat(response.getMeta().getPage().getTotal(), is(0L));
68+
}
69+
70+
@SuppressWarnings("unchecked")
71+
protected void assertThatAttributesIdFieldIsPresentInCollection(final @NonNull Object response) {
72+
final Map<String, Object> responseMap = objectMapper.convertValue(response, Map.class);
73+
74+
((List<Object>)responseMap.get("data")).forEach(dataItem -> {
75+
final Object idAttributeField = ((Map<String, Object>)((Map<String, Object>)dataItem)
76+
.get("attributes"))
77+
.get("id");
78+
79+
assertThat(idAttributeField, notNullValue());
80+
});
81+
}
82+
83+
@SuppressWarnings("unchecked")
84+
protected void assertThatAttributesIdFieldIsPresentInObject(final @NonNull Object response) {
85+
final Map<String, Object> responseMap = objectMapper.convertValue(response, Map.class);
86+
87+
final Object idAttributeField = ((Map<String, Object>)((Map<String, Object>)responseMap
88+
.get("data"))
89+
.get("attributes"))
90+
.get("id");
91+
92+
assertThat(idAttributeField, notNullValue());
93+
}
94+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package com.slmdev.jsonapi.simple.response;
2+
3+
import com.fasterxml.jackson.databind.JavaType;
4+
import org.hamcrest.Matchers;
5+
import org.junit.jupiter.api.Test;
6+
import org.springframework.http.HttpStatus;
7+
8+
import java.util.Arrays;
9+
import java.util.List;
10+
11+
import static org.hamcrest.MatcherAssert.assertThat;
12+
import static org.hamcrest.Matchers.is;
13+
import static org.hamcrest.Matchers.nullValue;
14+
15+
public class ResponseDeserializationTest extends BaseTest {
16+
@Test
17+
public void shouldDeserializeResponseWithDataAs1ObjectWithoutErrorsAndUriSpecified() throws Exception {
18+
final TestDto testDto = buildTestDto1();
19+
final Response<Data<TestDto>> response = Response.<Data<TestDto>, TestDto>builder()
20+
.data(testDto)
21+
.build();
22+
23+
final String json = objectMapper.writeValueAsString(response);
24+
final JavaType dataType = objectMapper.getTypeFactory().constructParametricType(Data.class, TestDto.class);
25+
final Response<Data<TestDto>> deserealizedResponse = objectMapper.readValue(json, objectMapper.getTypeFactory().constructParametricType(Response.class, dataType));
26+
27+
assertThat(deserealizedResponse.getData().getAttributes().getId(), is(TEST_DTO_1_ID));
28+
assertThat(deserealizedResponse.getData().getAttributes().getName(), is(TEST_DTO_1_NAME));
29+
assertThat(deserealizedResponse.getData().getAttributes().getCreateDate(), is(TEST_DTO_1_DATE_CREATE));
30+
assertThat(deserealizedResponse.getData().getId(), is(TEST_DTO_1_ID.toString()));
31+
assertThat(deserealizedResponse.getData().getType(), Matchers.is(TestDto.API_TYPE));
32+
assertThat(deserealizedResponse.getData().getLinks().getSelf(), is(buildSelfLink(testDto)));
33+
assertThat(deserealizedResponse.getData().getLinks().getRelated(), nullValue());
34+
35+
assertThat(deserealizedResponse.getErrors(), nullValue());
36+
37+
assertThat(deserealizedResponse.getMeta().getApi().getVersion(), is("1"));
38+
assertThat(deserealizedResponse.getMeta().getPage().getMaxSize(), is(25));
39+
assertThat(deserealizedResponse.getMeta().getPage().getTotal(), is(1L));
40+
41+
assertThatAttributesIdFieldIsPresentInObject(deserealizedResponse);
42+
}
43+
44+
@Test
45+
public void shouldDeserializeResponseWithDataListWithoutErrorsAndUriSpecified() throws Exception {
46+
final TestDto testDto1 = buildTestDto1();
47+
final TestDto testDto2 = buildTestDto2();
48+
final Response<List<Data<TestDto>>> response = Response.<List<Data<TestDto>>, TestDto>builder()
49+
.data(
50+
Arrays.asList(testDto1, testDto2)
51+
).build();
52+
53+
final String json = objectMapper.writeValueAsString(response);
54+
final JavaType dataType = objectMapper.getTypeFactory().constructParametricType(Data.class, TestDto.class);
55+
final JavaType listType = objectMapper.getTypeFactory().constructParametricType(List.class, dataType);
56+
final Response<List<Data<TestDto>>> deserealizedResponse = objectMapper.readValue(json, objectMapper.getTypeFactory().constructParametricType(Response.class, listType));
57+
58+
assertThat(deserealizedResponse.getData().get(0).getAttributes().getId(), is(TEST_DTO_1_ID));
59+
assertThat(deserealizedResponse.getData().get(0).getAttributes().getName(), is(TEST_DTO_1_NAME));
60+
assertThat(deserealizedResponse.getData().get(0).getAttributes().getCreateDate(), is(TEST_DTO_1_DATE_CREATE));
61+
assertThat(deserealizedResponse.getData().get(0).getId(), is(TEST_DTO_1_ID.toString()));
62+
assertThat(deserealizedResponse.getData().get(0).getType(), Matchers.is(TestDto.API_TYPE));
63+
assertThat(deserealizedResponse.getData().get(0).getLinks().getSelf(), is(buildSelfLink(testDto1)));
64+
assertThat(deserealizedResponse.getData().get(0).getLinks().getRelated(), nullValue());
65+
66+
assertThat(deserealizedResponse.getData().get(1).getAttributes().getId(), is(TEST_DTO_2_ID));
67+
assertThat(deserealizedResponse.getData().get(1).getAttributes().getName(), is(TEST_DTO_2_NAME));
68+
assertThat(deserealizedResponse.getData().get(1).getAttributes().getCreateDate(), is(TEST_DTO_2_DATE_CREATE));
69+
assertThat(deserealizedResponse.getData().get(1).getId(), is(TEST_DTO_2_ID.toString()));
70+
assertThat(deserealizedResponse.getData().get(1).getType(), Matchers.is(TestDto.API_TYPE));
71+
assertThat(deserealizedResponse.getData().get(1).getLinks().getSelf(), is(buildSelfLink(testDto2)));
72+
assertThat(deserealizedResponse.getData().get(1).getLinks().getRelated(), nullValue());
73+
74+
assertThat(deserealizedResponse.getErrors(), nullValue());
75+
76+
assertThat(deserealizedResponse.getMeta().getApi().getVersion(), is("1"));
77+
assertThat(deserealizedResponse.getMeta().getPage().getMaxSize(), is(25));
78+
assertThat(deserealizedResponse.getMeta().getPage().getTotal(), is(2L));
79+
80+
assertThatAttributesIdFieldIsPresentInCollection(deserealizedResponse);
81+
}
82+
83+
@Test
84+
public void shouldDeserializeResponseWithErrorWithData() throws Exception {
85+
final Response<Data<TestDto>> response = Response.<Data<TestDto>, TestDto>builder()
86+
.data(buildTestDto1())
87+
.error(HttpStatus.BAD_REQUEST, ERROR_DESCRIPTION)
88+
.build();
89+
90+
final String json = objectMapper.writeValueAsString(response);
91+
final JavaType dataType = objectMapper.getTypeFactory().constructParametricType(Data.class, TestDto.class);
92+
final Response<Data<TestDto>> deserealizedResponse = objectMapper.readValue(json, objectMapper.getTypeFactory().constructParametricType(Response.class, dataType));
93+
94+
assertErrorResponse(deserealizedResponse);
95+
}
96+
}

src/test/java/com/slmdev/jsonapi/simple/response/ResponseTest.java

Lines changed: 3 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,22 @@
22

33
import com.fasterxml.jackson.core.type.TypeReference;
44
import com.fasterxml.jackson.databind.ObjectMapper;
5-
import com.fasterxml.jackson.databind.json.JsonMapper;
6-
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
7-
import lombok.NonNull;
85
import lombok.SneakyThrows;
96
import org.hamcrest.Matchers;
107
import org.junit.jupiter.api.Assertions;
118
import org.junit.jupiter.api.Test;
129
import org.springframework.http.HttpStatus;
1310

14-
import java.time.LocalDateTime;
15-
import java.time.ZoneOffset;
1611
import java.util.Arrays;
1712
import java.util.List;
1813
import java.util.Map;
1914
import java.util.UUID;
2015

2116
import static org.hamcrest.MatcherAssert.assertThat;
22-
import static org.hamcrest.Matchers.*;
23-
24-
public class ResponseTest {
25-
private static final String TEST_RESPONSE_URI = "/api/v1";
26-
private static final UUID TEST_DTO_1_ID = UUID.randomUUID();
27-
private static final String TEST_DTO_1_NAME = "TEST-1";
28-
private static final LocalDateTime TEST_DTO_1_DATE_CREATE = LocalDateTime.now(ZoneOffset.UTC);
29-
private static final UUID TEST_DTO_2_ID = UUID.randomUUID();
30-
private static final String TEST_DTO_2_NAME = "TEST-2";
31-
private static final LocalDateTime TEST_DTO_2_DATE_CREATE = LocalDateTime.now(ZoneOffset.UTC);
32-
private static final String ERROR_CODE = "TEST_ERROR_CODE";
33-
private static final String ERROR_DESCRIPTION = "TEST";
34-
35-
private final ObjectMapper objectMapper = JsonMapper.builder()
36-
.addModule(new JavaTimeModule())
37-
.build();
17+
import static org.hamcrest.Matchers.is;
18+
import static org.hamcrest.Matchers.nullValue;
3819

20+
public class ResponseTest extends BaseTest {
3921
@Test
4022
public void shouldReturnResponseWithDataAs1ObjectWithoutErrorsAndUriSpecified() {
4123
final TestDto testDto = buildTestDto1();
@@ -480,66 +462,4 @@ public void shouldParseJsonResponseWithMetaTrace() {
480462
assertThat(response.getMeta().getApi().getVersion(), is("1"));
481463
assertThat(response.getMeta().getTrace().getId(), is(traceId));
482464
}
483-
484-
private TestDto buildTestDto1() {
485-
return new TestDto()
486-
.setId(TEST_DTO_1_ID)
487-
.setName(TEST_DTO_1_NAME)
488-
.setCreateDate(TEST_DTO_1_DATE_CREATE);
489-
}
490-
491-
private TestDto buildTestDto2() {
492-
return new TestDto()
493-
.setId(TEST_DTO_2_ID)
494-
.setName(TEST_DTO_2_NAME)
495-
.setCreateDate(TEST_DTO_2_DATE_CREATE);
496-
}
497-
498-
private String buildSelfLink(final @NonNull TestDto testDto) {
499-
return buildSelfLink("", testDto);
500-
}
501-
502-
private String buildSelfLink(final @NonNull String uri, final @NonNull TestDto testDto) {
503-
return uri + "/" + TestDto.API_TYPE + "/" + testDto.getId();
504-
}
505-
506-
private void assertResponseErrorCode(final @NonNull Response<?> response) {
507-
assertThat(response.getErrors().get(0).getCode(), is(ERROR_CODE));
508-
}
509-
510-
private void assertErrorResponse(final @NonNull Response<?> response) {
511-
assertThat(response.getData(), nullValue());
512-
513-
assertThat(response.getErrors().get(0).getStatus(), is(HttpStatus.BAD_REQUEST.value()));
514-
assertThat(response.getErrors().get(0).getDetail(), is(ERROR_DESCRIPTION));
515-
516-
assertThat(response.getMeta().getApi().getVersion(), is("1"));
517-
assertThat(response.getMeta().getPage().getMaxSize(), is(25));
518-
assertThat(response.getMeta().getPage().getTotal(), is(0L));
519-
}
520-
521-
@SuppressWarnings("unchecked")
522-
private void assertThatAttributesIdFieldIsPresentInCollection(final @NonNull Object response) {
523-
final Map<String, Object> responseMap = objectMapper.convertValue(response, Map.class);
524-
525-
((List<Object>)responseMap.get("data")).forEach(dataItem -> {
526-
final Object idAttributeField = ((Map<String, Object>)((Map<String, Object>)dataItem)
527-
.get("attributes"))
528-
.get("id");
529-
530-
assertThat(idAttributeField, notNullValue());
531-
});
532-
}
533-
534-
@SuppressWarnings("unchecked")
535-
private void assertThatAttributesIdFieldIsPresentInObject(final @NonNull Object response) {
536-
final Map<String, Object> responseMap = objectMapper.convertValue(response, Map.class);
537-
538-
final Object idAttributeField = ((Map<String, Object>)((Map<String, Object>)responseMap
539-
.get("data"))
540-
.get("attributes"))
541-
.get("id");
542-
543-
assertThat(idAttributeField, notNullValue());
544-
}
545465
}

0 commit comments

Comments
 (0)