|
15 | 15 | */
|
16 | 16 | package io.micronaut.jackson.parser
|
17 | 17 |
|
| 18 | +import com.fasterxml.jackson.annotation.JsonTypeInfo |
18 | 19 | import com.fasterxml.jackson.core.JsonParseException
|
19 | 20 | import com.fasterxml.jackson.core.io.JsonEOFException
|
20 | 21 | import com.fasterxml.jackson.databind.JsonNode
|
21 | 22 | import com.fasterxml.jackson.databind.ObjectMapper
|
22 | 23 | import com.fasterxml.jackson.databind.node.ArrayNode
|
| 24 | +import groovy.transform.ToString |
23 | 25 | import io.micronaut.context.ApplicationContext
|
24 | 26 | import io.micronaut.context.DefaultApplicationContext
|
| 27 | +import io.micronaut.context.env.PropertySource |
25 | 28 | import org.reactivestreams.Subscriber
|
26 | 29 | import org.reactivestreams.Subscription
|
27 | 30 | import spock.lang.AutoCleanup
|
@@ -103,6 +106,219 @@ class JacksonProcessorSpec extends Specification {
|
103 | 106 | foo.age == 10
|
104 | 107 | }
|
105 | 108 |
|
| 109 | + void "test Jackson polymorphic deserialization"() { |
| 110 | + given: |
| 111 | + ObjectMapper objectMapper = applicationContext.getBean(ObjectMapper) |
| 112 | + JacksonProcessor processor = new JacksonProcessor() |
| 113 | + Bicycle bicycle = new MountainBike(3, 30, 10) |
| 114 | + Garage instance = new Garage(bicycle: bicycle) |
| 115 | + |
| 116 | + when: |
| 117 | + def string = objectMapper.writeValueAsString(instance) |
| 118 | + byte[] bytes = objectMapper.writeValueAsBytes(instance) |
| 119 | + boolean complete = false |
| 120 | + JsonNode node = null |
| 121 | + Throwable error = null |
| 122 | + int nodeCount = 0 |
| 123 | + processor.subscribe(new Subscriber<JsonNode>() { |
| 124 | + @Override |
| 125 | + void onSubscribe(Subscription s) { |
| 126 | + s.request(Long.MAX_VALUE) |
| 127 | + } |
| 128 | + |
| 129 | + @Override |
| 130 | + void onNext(JsonNode jsonNode) { |
| 131 | + nodeCount++ |
| 132 | + node = jsonNode |
| 133 | + } |
| 134 | + |
| 135 | + @Override |
| 136 | + void onError(Throwable t) { |
| 137 | + error = t |
| 138 | + } |
| 139 | + |
| 140 | + @Override |
| 141 | + void onComplete() { |
| 142 | + complete = true |
| 143 | + } |
| 144 | + }) |
| 145 | + processor.onSubscribe(new Subscription() { |
| 146 | + @Override |
| 147 | + void request(long n) { |
| 148 | + |
| 149 | + } |
| 150 | + |
| 151 | + @Override |
| 152 | + void cancel() { |
| 153 | + |
| 154 | + } |
| 155 | + }) |
| 156 | + processor.onNext(bytes) |
| 157 | + processor.onComplete() |
| 158 | + |
| 159 | + then: |
| 160 | + complete |
| 161 | + node != null |
| 162 | + error == null |
| 163 | + nodeCount == 1 |
| 164 | + string == '{"bicycle":{"gear":3,"speed":30,"seatHeight":10}}' |
| 165 | + |
| 166 | + when: |
| 167 | + Garage garage = objectMapper.treeToValue(node, Garage) |
| 168 | + |
| 169 | + then: |
| 170 | + !(garage.bicycle instanceof MountainBike) |
| 171 | + } |
| 172 | + |
| 173 | + void "test Jackson polymorphic deserialization, per class"() { |
| 174 | + given: |
| 175 | + ObjectMapper objectMapper = applicationContext.getBean(ObjectMapper) |
| 176 | + JacksonProcessor processor = new JacksonProcessor() |
| 177 | + Dog dog = new Dog(name: "Daisy", barkVolume: 1111.1D) |
| 178 | + Zoo instance = new Zoo(animal: dog) |
| 179 | + |
| 180 | + when: |
| 181 | + def string = objectMapper.writeValueAsString(instance) |
| 182 | + byte[] bytes = objectMapper.writeValueAsBytes(instance) |
| 183 | + boolean complete = false |
| 184 | + JsonNode node = null |
| 185 | + Throwable error = null |
| 186 | + int nodeCount = 0 |
| 187 | + processor.subscribe(new Subscriber<JsonNode>() { |
| 188 | + @Override |
| 189 | + void onSubscribe(Subscription s) { |
| 190 | + s.request(Long.MAX_VALUE) |
| 191 | + } |
| 192 | + |
| 193 | + @Override |
| 194 | + void onNext(JsonNode jsonNode) { |
| 195 | + nodeCount++ |
| 196 | + node = jsonNode |
| 197 | + } |
| 198 | + |
| 199 | + @Override |
| 200 | + void onError(Throwable t) { |
| 201 | + error = t |
| 202 | + } |
| 203 | + |
| 204 | + @Override |
| 205 | + void onComplete() { |
| 206 | + complete = true |
| 207 | + } |
| 208 | + }) |
| 209 | + processor.onSubscribe(new Subscription() { |
| 210 | + @Override |
| 211 | + void request(long n) { |
| 212 | + |
| 213 | + } |
| 214 | + |
| 215 | + @Override |
| 216 | + void cancel() { |
| 217 | + |
| 218 | + } |
| 219 | + }) |
| 220 | + processor.onNext(bytes) |
| 221 | + processor.onComplete() |
| 222 | + |
| 223 | + then: |
| 224 | + complete |
| 225 | + node != null |
| 226 | + error == null |
| 227 | + nodeCount == 1 |
| 228 | + string == '{"animal":{"@class":"io.micronaut.jackson.parser.Dog","name":"Daisy","barkVolume":1111.1}}' |
| 229 | + |
| 230 | + when: |
| 231 | + Zoo zoo = objectMapper.treeToValue(node, Zoo) |
| 232 | + |
| 233 | + then: |
| 234 | + zoo.animal instanceof Dog |
| 235 | + |
| 236 | + when: |
| 237 | + Dog animal = (Dog) zoo.animal |
| 238 | + |
| 239 | + then: |
| 240 | + animal != null |
| 241 | + animal.name == "Daisy" |
| 242 | + animal.barkVolume == 1111.1D |
| 243 | + } |
| 244 | + |
| 245 | + void "test Jackson polymorphic deserialization, global default typing"() { |
| 246 | + given: |
| 247 | + ApplicationContext applicationContext1 = new DefaultApplicationContext("test") |
| 248 | + applicationContext1.environment.addPropertySource(PropertySource.of( |
| 249 | + 'test', ['jackson.defaultTyping':'NON_FINAL'] |
| 250 | + )) |
| 251 | + applicationContext1 = applicationContext1.start() |
| 252 | + ObjectMapper objectMapper = applicationContext1.getBean(ObjectMapper) |
| 253 | + JacksonProcessor processor = new JacksonProcessor() |
| 254 | + Bicycle bicycle = new MountainBike(3, 30, 10) |
| 255 | + Garage instance = new Garage(bicycle: bicycle) |
| 256 | + |
| 257 | + when: |
| 258 | + def string = objectMapper.writeValueAsString(instance) |
| 259 | + byte[] bytes = objectMapper.writeValueAsBytes(instance) |
| 260 | + boolean complete = false |
| 261 | + JsonNode node = null |
| 262 | + Throwable error = null |
| 263 | + int nodeCount = 0 |
| 264 | + processor.subscribe(new Subscriber<JsonNode>() { |
| 265 | + @Override |
| 266 | + void onSubscribe(Subscription s) { |
| 267 | + s.request(Long.MAX_VALUE) |
| 268 | + } |
| 269 | + |
| 270 | + @Override |
| 271 | + void onNext(JsonNode jsonNode) { |
| 272 | + nodeCount++ |
| 273 | + node = jsonNode |
| 274 | + } |
| 275 | + |
| 276 | + @Override |
| 277 | + void onError(Throwable t) { |
| 278 | + error = t |
| 279 | + } |
| 280 | + |
| 281 | + @Override |
| 282 | + void onComplete() { |
| 283 | + complete = true |
| 284 | + } |
| 285 | + }) |
| 286 | + processor.onSubscribe(new Subscription() { |
| 287 | + @Override |
| 288 | + void request(long n) { |
| 289 | + |
| 290 | + } |
| 291 | + |
| 292 | + @Override |
| 293 | + void cancel() { |
| 294 | + |
| 295 | + } |
| 296 | + }) |
| 297 | + processor.onNext(bytes) |
| 298 | + processor.onComplete() |
| 299 | + |
| 300 | + then: |
| 301 | + complete |
| 302 | + node != null |
| 303 | + error == null |
| 304 | + nodeCount == 1 |
| 305 | + string == '["io.micronaut.jackson.parser.Garage",{"bicycle":["io.micronaut.jackson.parser.MountainBike",{"gear":3,"speed":30,"seatHeight":10}]}]' |
| 306 | + |
| 307 | + when: |
| 308 | + Garage garage = objectMapper.treeToValue(node, Garage) |
| 309 | + |
| 310 | + then: |
| 311 | + garage.bicycle instanceof MountainBike |
| 312 | + |
| 313 | + when: |
| 314 | + MountainBike mountainBike = (MountainBike) garage.bicycle |
| 315 | + |
| 316 | + then: |
| 317 | + mountainBike != null |
| 318 | + mountainBike.gear == 3 |
| 319 | + mountainBike.speed == 30 |
| 320 | + mountainBike.seatHeight == 10 |
| 321 | + } |
106 | 322 |
|
107 | 323 | void "test publish JSON array async"() {
|
108 | 324 |
|
@@ -289,3 +505,59 @@ class Foo {
|
289 | 505 | String name
|
290 | 506 | Integer age
|
291 | 507 | }
|
| 508 | + |
| 509 | +@ToString |
| 510 | +class Garage { |
| 511 | + String name |
| 512 | + Bicycle bicycle |
| 513 | +} |
| 514 | + |
| 515 | +@ToString |
| 516 | +class Bicycle { |
| 517 | + int gear |
| 518 | + int speed |
| 519 | + |
| 520 | + Bicycle() {} |
| 521 | + |
| 522 | + Bicycle(int gear, int speed) { |
| 523 | + this.gear = gear |
| 524 | + this.speed = speed |
| 525 | + } |
| 526 | + |
| 527 | + void applyBrake(int decrement) { |
| 528 | + speed -= decrement |
| 529 | + } |
| 530 | + |
| 531 | + void speedUp(int increment) { |
| 532 | + speed += increment |
| 533 | + } |
| 534 | +} |
| 535 | + |
| 536 | +@ToString |
| 537 | +class MountainBike extends Bicycle { |
| 538 | + int seatHeight |
| 539 | + |
| 540 | + MountainBike() {} |
| 541 | + |
| 542 | + MountainBike(int gear,int speed, int seatHeight) { |
| 543 | + super(gear, speed) |
| 544 | + this.seatHeight = seatHeight |
| 545 | + } |
| 546 | +} |
| 547 | + |
| 548 | +@ToString |
| 549 | +class Zoo { |
| 550 | + Animal animal |
| 551 | +} |
| 552 | + |
| 553 | +@ToString |
| 554 | +@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class") |
| 555 | +class Animal { |
| 556 | + String name |
| 557 | +} |
| 558 | + |
| 559 | +@ToString |
| 560 | +class Dog extends Animal { |
| 561 | + double barkVolume |
| 562 | + |
| 563 | +} |
0 commit comments