|
1 | 1 | package com.sap.cloud.sdk.datamodel.openapi.sample.api; |
2 | 2 |
|
| 3 | +import static org.assertj.core.api.Assertions.assertThatThrownBy; |
3 | 4 | import static org.assertj.core.api.AssertionsForClassTypes.assertThat; |
4 | | -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; |
5 | 5 |
|
6 | 6 | import javax.annotation.Nonnull; |
7 | 7 |
|
|
11 | 11 | import com.fasterxml.jackson.annotation.JsonAutoDetect; |
12 | 12 | import com.fasterxml.jackson.annotation.PropertyAccessor; |
13 | 13 | import com.fasterxml.jackson.core.JsonProcessingException; |
| 14 | +import com.fasterxml.jackson.databind.JsonNode; |
14 | 15 | import com.fasterxml.jackson.databind.ObjectMapper; |
15 | | -import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; |
16 | 16 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; |
17 | 17 | import com.sap.cloud.sdk.datamodel.openapi.sample.model.AllOf; |
18 | 18 | import com.sap.cloud.sdk.datamodel.openapi.sample.model.AnyOf; |
|
22 | 22 | import com.sap.cloud.sdk.datamodel.openapi.sample.model.OneOfWithDiscriminator; |
23 | 23 | import com.sap.cloud.sdk.datamodel.openapi.sample.model.OneOfWithDiscriminatorAndMapping; |
24 | 24 |
|
25 | | -public class OneOfDeserializationTest |
| 25 | +class OneOfDeserializationTest |
26 | 26 | { |
27 | | - String cola = """ |
| 27 | + private static final ObjectMapper objectMapper = newDefaultObjectMapper(); |
| 28 | + |
| 29 | + private static final Cola COLA_OBJECT = Cola.create().caffeine(true).sodaType("Cola"); |
| 30 | + private static final Fanta FANTA_OBJECT = Fanta.create().color("orange").sodaType("Fanta"); |
| 31 | + private static final String COLA_JSON = """ |
28 | 32 | { |
29 | 33 | "sodaType": "Cola", |
30 | 34 | "caffeine": true |
31 | 35 | }"""; |
32 | | - String fanta = """ |
| 36 | + private static final String FANTA_JSON = """ |
33 | 37 | { |
34 | 38 | "sodaType": "Fanta", |
35 | 39 | "color": "orange" |
36 | 40 | }"""; |
| 41 | + private static final String UNKNOWN_JSON = """ |
| 42 | + { |
| 43 | + "sodaType": "Sprite", |
| 44 | + "someProperty": "someValue" |
| 45 | + }"""; |
37 | 46 |
|
38 | 47 | @Test |
39 | 48 | void oneOf() |
| 49 | + throws JsonProcessingException |
40 | 50 | { |
41 | | - // useOneOfInterfaces is enabled and no discriminator is present, the deserialization will fail |
42 | | - // The fix is to use set a mixIn in the ObjectMapper |
43 | | - assertThatThrownBy(() -> newDefaultObjectMapper().readValue(cola, OneOf.class)) |
44 | | - .isInstanceOf(InvalidTypeIdException.class) |
45 | | - .hasMessageContaining("Could not resolve subtype"); |
46 | | - assertThatThrownBy(() -> newDefaultObjectMapper().readValue(fanta, OneOf.class)) |
47 | | - .isInstanceOf(InvalidTypeIdException.class) |
48 | | - .hasMessageContaining("Could not resolve subtype"); |
| 51 | + var actual = objectMapper.readValue(COLA_JSON, OneOf.class); |
| 52 | + assertThat(actual) |
| 53 | + .describedAs("Object should automatically be deserialized as Cola with JSON subtype deduction") |
| 54 | + .isInstanceOf(Cola.class) |
| 55 | + .isEqualTo(COLA_OBJECT); |
| 56 | + |
| 57 | + actual = objectMapper.readValue(FANTA_JSON, OneOf.class); |
| 58 | + assertThat(actual) |
| 59 | + .describedAs("Object should automatically be deserialized as Fanta with JSON subtype deduction") |
| 60 | + .isInstanceOf(Fanta.class) |
| 61 | + .isEqualTo(FANTA_OBJECT); |
| 62 | + |
| 63 | + assertThatThrownBy(() -> objectMapper.readValue(UNKNOWN_JSON, OneOf.class)) |
| 64 | + .isInstanceOf(JsonProcessingException.class); |
49 | 65 | } |
50 | 66 |
|
51 | 67 | @Test |
52 | 68 | void oneOfWithDiscriminator() |
53 | 69 | throws JsonProcessingException |
54 | 70 | { |
55 | | - Cola oneOfCola = (Cola) newDefaultObjectMapper().readValue(cola, OneOfWithDiscriminator.class); |
56 | | - assertThat(oneOfCola.getSodaType()).isEqualTo("Cola"); |
57 | | - assertThat(oneOfCola.isCaffeine()).isTrue(); |
| 71 | + var actual = objectMapper.readValue(COLA_JSON, OneOfWithDiscriminator.class); |
| 72 | + assertThat(actual) |
| 73 | + .describedAs( |
| 74 | + "Object should automatically be deserialized as Cola using the class names as discriminator mapping values") |
| 75 | + .isInstanceOf(Cola.class) |
| 76 | + .isEqualTo(COLA_OBJECT); |
58 | 77 |
|
59 | | - Fanta oneOfFanta = (Fanta) newDefaultObjectMapper().readValue(fanta, OneOfWithDiscriminator.class); |
60 | | - assertThat(oneOfFanta.getSodaType()).isEqualTo("Fanta"); |
61 | | - assertThat(oneOfFanta.getColor()).isEqualTo("orange"); |
| 78 | + actual = objectMapper.readValue(FANTA_JSON, OneOfWithDiscriminator.class); |
| 79 | + assertThat(actual) |
| 80 | + .describedAs( |
| 81 | + "Object should automatically be deserialized as Fanta using the class names as discriminator mapping values") |
| 82 | + .isInstanceOf(Fanta.class) |
| 83 | + .isEqualTo(FANTA_OBJECT); |
| 84 | + |
| 85 | + assertThatThrownBy(() -> objectMapper.readValue(UNKNOWN_JSON, OneOfWithDiscriminator.class)); |
62 | 86 | } |
63 | 87 |
|
64 | 88 | @Test |
65 | 89 | void oneOfWithDiscriminatorAndMapping() |
66 | 90 | throws JsonProcessingException |
67 | 91 | { |
68 | | - Cola oneOfCola = (Cola) newDefaultObjectMapper().readValue(cola, OneOfWithDiscriminatorAndMapping.class); |
69 | | - assertThat(oneOfCola.getSodaType()).isEqualTo("Cola"); |
70 | | - assertThat(oneOfCola.isCaffeine()).isTrue(); |
| 92 | + var jsonWithCustomMapping = """ |
| 93 | + { |
| 94 | + "sodaType": "cool_cola", |
| 95 | + "caffeine": true |
| 96 | + }"""; |
| 97 | + var actual = objectMapper.readValue(jsonWithCustomMapping, OneOfWithDiscriminatorAndMapping.class); |
| 98 | + assertThat(actual) |
| 99 | + .describedAs( |
| 100 | + "Object should automatically be deserialized as Cola using the explicit discriminator mapping values") |
| 101 | + .isInstanceOf(Cola.class) |
| 102 | + .isEqualTo(Cola.create().caffeine(true).sodaType("cool_cola")); |
| 103 | + |
| 104 | + jsonWithCustomMapping = """ |
| 105 | + { |
| 106 | + "sodaType": "fancy_fanta", |
| 107 | + "color": "orange" |
| 108 | + }"""; |
| 109 | + actual = objectMapper.readValue(jsonWithCustomMapping, OneOfWithDiscriminatorAndMapping.class); |
| 110 | + assertThat(actual) |
| 111 | + .describedAs( |
| 112 | + "Object should automatically be deserialized as Fanta using the explicit discriminator mapping values") |
| 113 | + .isInstanceOf(Fanta.class) |
| 114 | + .isEqualTo(Fanta.create().color("orange").sodaType("fancy_fanta")); |
| 115 | + |
| 116 | + assertThatThrownBy(() -> objectMapper.readValue(UNKNOWN_JSON, OneOfWithDiscriminatorAndMapping.class)) |
| 117 | + .isInstanceOf(JsonProcessingException.class); |
71 | 118 |
|
72 | | - Fanta oneOfFanta = (Fanta) newDefaultObjectMapper().readValue(fanta, OneOfWithDiscriminatorAndMapping.class); |
73 | | - assertThat(oneOfFanta.getSodaType()).isEqualTo("Fanta"); |
74 | | - assertThat(oneOfFanta.getColor()).isEqualTo("orange"); |
75 | 119 | } |
76 | 120 |
|
77 | 121 | @Test |
78 | 122 | void anyOf() |
79 | 123 | throws JsonProcessingException |
80 | 124 | { |
81 | | - AnyOf anyOfCola = newDefaultObjectMapper().readValue(cola, AnyOf.class); |
| 125 | + AnyOf anyOfCola = objectMapper.readValue(COLA_JSON, AnyOf.class); |
82 | 126 | assertThat(anyOfCola.getSodaType()).isEqualTo("Cola"); |
83 | 127 | assertThat(anyOfCola.isCaffeine()).isTrue(); |
| 128 | + assertThat(anyOfCola.getColor()).isNull(); |
84 | 129 |
|
85 | | - AnyOf anyOfFanta = newDefaultObjectMapper().readValue(fanta, AnyOf.class); |
| 130 | + AnyOf anyOfFanta = objectMapper.readValue(FANTA_JSON, AnyOf.class); |
86 | 131 | assertThat(anyOfFanta.getSodaType()).isEqualTo("Fanta"); |
87 | 132 | assertThat(anyOfFanta.getColor()).isEqualTo("orange"); |
| 133 | + assertThat(anyOfFanta.isCaffeine()).isNull(); |
88 | 134 | } |
89 | 135 |
|
90 | 136 | @Test |
91 | 137 | void allOf() |
92 | 138 | throws JsonProcessingException |
93 | 139 | { |
94 | | - AllOf allOfCola = newDefaultObjectMapper().readValue(cola, AllOf.class); |
| 140 | + AllOf allOfCola = objectMapper.readValue(COLA_JSON, AllOf.class); |
95 | 141 | assertThat(allOfCola.getSodaType()).isEqualTo("Cola"); |
96 | 142 | assertThat(allOfCola.isCaffeine()).isTrue(); |
97 | 143 | assertThat(allOfCola.getColor()).isNull(); |
98 | 144 |
|
99 | | - AllOf allOfFanta = newDefaultObjectMapper().readValue(fanta, AllOf.class); |
| 145 | + AllOf allOfFanta = objectMapper.readValue(FANTA_JSON, AllOf.class); |
100 | 146 | assertThat(allOfFanta.getSodaType()).isEqualTo("Fanta"); |
101 | 147 | assertThat(allOfFanta.getColor()).isEqualTo("orange"); |
102 | 148 | assertThat(allOfFanta.isCaffeine()).isNull(); |
103 | 149 | } |
104 | 150 |
|
| 151 | + @Test |
| 152 | + void testColaSerialization() |
| 153 | + throws JsonProcessingException |
| 154 | + { |
| 155 | + var expected = objectMapper.readValue(COLA_JSON, JsonNode.class); |
| 156 | + var actual = objectMapper.valueToTree(expected); |
| 157 | + |
| 158 | + assertThat(actual).isEqualTo(expected); |
| 159 | + } |
| 160 | + |
| 161 | + @Test |
| 162 | + void testFantaSerialization() |
| 163 | + throws JsonProcessingException |
| 164 | + { |
| 165 | + var expected = objectMapper.readValue(FANTA_JSON, JsonNode.class); |
| 166 | + var actual = objectMapper.valueToTree(expected); |
| 167 | + |
| 168 | + assertThat(actual).isEqualTo(expected); |
| 169 | + } |
| 170 | + |
105 | 171 | /** |
106 | 172 | * Taken from {@link com.sap.cloud.sdk.services.openapi.apiclient.ApiClient} |
107 | 173 | */ |
|
0 commit comments