如何用Jackson将对象字段序列化为JSON字符串适配Amazon SNS?
解决Amazon SNS推送中APNS字段需JSON字符串的Java序列化问题
针对你用Java Record定义SNS Payload时,APNS字段被序列化为嵌套对象而非JSON字符串的问题,这里有几种无需预序列化字段的简便实现方式:
方案1:自定义通用序列化器(最通用)
先写一个能把任意对象转为JSON字符串的序列化器:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; public class JsonStringSerializer extends JsonSerializer<Object> { @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { // 复用当前上下文的ObjectMapper,避免重复创建 gen.writeString(serializers.getMapper().writeValueAsString(value)); } }
然后在Record的APNS字段上添加@JsonSerialize注解指定序列化器:
import com.fasterxml.jackson.databind.annotation.JsonSerialize; public record ApnsPayload(String apsAlert, Integer badge) {} public record SnsNotificationPayload( @JsonSerialize(using = JsonStringSerializer.class) ApnsPayload apns, String defaultMessage ) {}
这样序列化时,APNS字段会自动被转为JSON字符串格式,符合SNS的要求。
方案2:内嵌序列化器(无需单独类文件)
如果不想额外创建序列化器类,可以把序列化器内嵌在Record中,尤其适合Jackson 2.12+版本:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.io.IOException; public record ApnsPayload(String apsAlert, Integer badge) {} public record SnsNotificationPayload( @JsonSerialize(using = JsonStringSerializer.class) ApnsPayload apns, String defaultMessage ) { private static class JsonStringSerializer extends JsonSerializer<Object> { @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(serializers.getMapper().writeValueAsString(value)); } } }
方案3:利用Record的重写访问方法+@JsonRawValue
直接重写Record中APNS字段的访问方法,结合@JsonRawValue注解实现序列化:
import com.fasterxml.jackson.annotation.JsonRawValue; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public record ApnsPayload(String apsAlert, Integer badge) {} public record SnsNotificationPayload(ApnsPayload apns, String defaultMessage) { // 建议复用全局ObjectMapper,比如Spring环境中注入 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @JsonRawValue public String apns() { try { return OBJECT_MAPPER.writeValueAsString(apns); } catch (JsonProcessingException e) { throw new RuntimeException("Failed to serialize APNS payload", e); } } }
注意事项
- 尽量复用
ObjectMapper实例,避免每次序列化时创建新对象,提升性能; - 如果是Spring Boot环境,可以直接注入容器中的
ObjectMapper,无需手动实例化; - 若APNS字段可能为null,记得在序列化器中做null值处理,避免抛出异常。
内容的提问来源于stack exchange,提问作者Brendan Long
相关产品推荐
相关产品推荐

