Solve Long Precision Loss in Spring Boot 3 with Jackson and Custom Annotations
This article demonstrates how to handle Java Long precision loss in Spring Boot 3 front‑end displays, configures Jackson to serialize Long as String, uses @JsonValue for single‑property serialization, and creates custom annotations with a SensitiveSerializer for data masking, complete with code examples and screenshots.
In previous articles we introduced extensive Jackson usage in Spring Boot. This article focuses on two main topics: Long precision loss in the front‑end and @JsonValue serialization of single property values, plus the creation of custom annotations for sensitive data masking.
1. Introduction
The following topics are covered:
Long type precision loss in the front‑end
@JsonValue serialization of single property values
Custom annotation application
2. Practical Cases
2.1 Long Precision Loss
When JavaScript handles large numbers such as Java Long , precision can be lost because JavaScript uses IEEE‑754 64‑bit floating‑point numbers, which cannot accurately represent integers larger than 2^53‑1 . The following controller returns a 17‑digit Long value:
<code>@RestController
@RequestMapping("/longs")
public class LongController {
@GetMapping("")
public Map<String, Object> getData() {
return Map.of("code", 0, "data", 123456789012345678L);
}
}
</code>Directly accessing the endpoint in a browser shows the correct value, but the network response contains the truncated number. An Ajax request also returns the incorrect value:
<code>function getData() {
axios.get('http://localhost:8080/longs')
.then(resp => {
console.log(resp.data);
}).catch(error => {
console.log(error);
});
}
</code>To prevent this issue, configure Jackson to serialize all Long values as String globally:
<code>@Component
public class PackMapperCustomizer implements Jackson2ObjectMapperBuilderCustomizer {
@Override
public void customize(Jackson2ObjectMapperBuilder builder) {
builder.serializerByType(Long.class, ToStringSerializer.instance);
}
}
</code>If only specific fields need conversion, annotate them with @JsonSerialize(using = ToStringSerializer.class) :
<code>public class User {
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
private String name;
// getters, setters
}
</code>2.2 @JsonValue Serialization of Single Property Values
The @JsonValue annotation marks a method or field whose value will be used as the JSON representation of the entire object. For example, an enum:
<code>public enum PaymentStatus {
NO_PAY(0, "未支付"), PAID(1, "已支付");
private Integer code;
private String desc;
// constructor, getters, setters
}
</code>When the enum is returned from a controller, the default JSON output is the enum name. Adding @JsonValue to a field makes that field the JSON value:
<code>@JsonValue
private String desc;
</code>Applying @JsonValue to a regular bean field yields the same effect:
<code>public class User {
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@JsonValue
private String name;
}
</code>2.3 Custom Annotation for Sensitive Data Masking
To mask sensitive fields such as ID cards or phone numbers, define a custom annotation using @JacksonAnnotationsInside and a serializer:
<code>@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveSerializer.class)
public @interface Sensitive {
int start() default 0;
int end() default 0;
String mask() default "*";
}
</code>The corresponding serializer implements the masking logic:
<code>public class SensitiveSerializer extends JsonSerializer<String> implements ContextualSerializer {
private Sensitive sensitive;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
String val = value;
if (sensitive != null && StringUtils.hasLength(val)) {
String m = sensitive.mask();
int start = sensitive.start();
int end = sensitive.end();
int totalLength = value.length();
// masking algorithm omitted for brevity
}
gen.writeString(val);
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
sensitive = property.getAnnotation(Sensitive.class);
return this;
}
}
</code>Use the annotation on fields that require masking:
<code>public class User {
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
private String name;
@Sensitive(start = 6, end = 4)
private String idCard;
@Sensitive(start = 4, end = 3)
private String phone;
// getters, setters
}
</code>The front‑end now displays masked values for the annotated fields.
Overall, the article provides practical solutions for Long precision handling, single‑property JSON serialization, and custom data masking in Spring Boot 3 applications.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.