Skip to content

Commit 23607ee

Browse files
committed
Add nullSafeValue method that accepts a mapper Function
Update `JsonObjectDeserializer` with a `nullSafeValue` method that accepts a mapper `Function` Closes gh-42972
1 parent 2fa1180 commit 23607ee

File tree

4 files changed

+43
-32
lines changed

4 files changed

+43
-32
lines changed

spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestIntegrationTests.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.boot.test.autoconfigure.json;
1818

19+
import java.util.Date;
20+
import java.util.UUID;
21+
1922
import org.junit.jupiter.api.Test;
2023

2124
import org.springframework.beans.factory.annotation.Autowired;
@@ -75,7 +78,7 @@ void jacksonBasic() throws Exception {
7578

7679
@Test
7780
void jacksonCustom() throws Exception {
78-
ExampleCustomObject object = new ExampleCustomObject("spring");
81+
ExampleCustomObject object = new ExampleCustomObject("spring", new Date(), UUID.randomUUID());
7982
assertThat(this.jacksonCustomJson.write(object)).isEqualToJson("example.json");
8083
}
8184

Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,35 +16,17 @@
1616

1717
package org.springframework.boot.test.autoconfigure.json.app;
1818

19+
import java.util.Date;
20+
import java.util.UUID;
21+
1922
/**
2023
* Example object to read/write as JSON through {@link ExampleJsonComponent}.
2124
*
2225
* @author Phillip Webb
26+
* @param value the value
27+
* @param date a date
28+
* @param uuid a uuid
2329
*/
24-
public class ExampleCustomObject {
25-
26-
private final String value;
27-
28-
public ExampleCustomObject(String value) {
29-
this.value = value;
30-
}
31-
32-
@Override
33-
public boolean equals(Object obj) {
34-
if (obj != null && obj.getClass() == getClass()) {
35-
return this.value.equals(((ExampleCustomObject) obj).value);
36-
}
37-
return false;
38-
}
39-
40-
@Override
41-
public int hashCode() {
42-
return this.value.hashCode();
43-
}
44-
45-
@Override
46-
public String toString() {
47-
return this.value;
48-
}
30+
public record ExampleCustomObject(String value, Date date, UUID uuid) {
4931

5032
}

spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/app/ExampleJsonComponent.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,8 @@
1717
package org.springframework.boot.test.autoconfigure.json.app;
1818

1919
import java.io.IOException;
20+
import java.util.Date;
21+
import java.util.UUID;
2022

2123
import com.fasterxml.jackson.core.JsonGenerator;
2224
import com.fasterxml.jackson.core.JsonParser;
@@ -44,7 +46,9 @@ static class Serializer extends JsonObjectSerializer<ExampleCustomObject> {
4446
@Override
4547
protected void serializeObject(ExampleCustomObject value, JsonGenerator jgen, SerializerProvider provider)
4648
throws IOException {
47-
jgen.writeStringField("value", value.toString());
49+
jgen.writeStringField("value", value.value());
50+
jgen.writeNumberField("date", value.date().getTime());
51+
jgen.writeStringField("uuid", value.uuid().toString());
4852
}
4953

5054
}
@@ -54,7 +58,10 @@ static class Deserializer extends JsonObjectDeserializer<ExampleCustomObject> {
5458
@Override
5559
protected ExampleCustomObject deserializeObject(JsonParser jsonParser, DeserializationContext context,
5660
ObjectCodec codec, JsonNode tree) throws IOException {
57-
return new ExampleCustomObject(nullSafeValue(tree.get("value"), String.class));
61+
String value = nullSafeValue(tree.get("value"), String.class);
62+
Date date = nullSafeValue(tree.get("date"), Integer.class, Date::new);
63+
UUID uuid = nullSafeValue(tree.get("uuid"), String.class, UUID::fromString);
64+
return new ExampleCustomObject(value, date, uuid);
5865
}
5966

6067
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jackson/JsonObjectDeserializer.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2022 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.math.BigDecimal;
2121
import java.math.BigInteger;
22+
import java.util.function.Function;
2223

2324
import com.fasterxml.jackson.core.JsonParser;
2425
import com.fasterxml.jackson.core.ObjectCodec;
@@ -72,6 +73,24 @@ public final T deserialize(JsonParser jp, DeserializationContext ctxt) throws IO
7273
protected abstract T deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,
7374
JsonNode tree) throws IOException;
7475

76+
/**
77+
* Helper method to extract a value from the given {@code jsonNode} or return
78+
* {@code null} when the node itself is {@code null}.
79+
* @param jsonNode the source node (may be {@code null})
80+
* @param type the data type. May be {@link String}, {@link Boolean}, {@link Long},
81+
* {@link Integer}, {@link Short}, {@link Double}, {@link Float}, {@link BigDecimal}
82+
* or {@link BigInteger}.
83+
* @param <D> the data type requested
84+
* @param <R> the result type
85+
* @param mapper a mapper to convert the value when it is not {@code null}
86+
* @return the node value or {@code null}
87+
* @since 3.4.0
88+
*/
89+
protected final <D, R> R nullSafeValue(JsonNode jsonNode, Class<D> type, Function<D, R> mapper) {
90+
D value = nullSafeValue(jsonNode, type);
91+
return (value != null) ? mapper.apply(value) : null;
92+
}
93+
7594
/**
7695
* Helper method to extract a value from the given {@code jsonNode} or return
7796
* {@code null} when the node itself is {@code null}.

0 commit comments

Comments
 (0)