请问该序列化格式名称是什么?如何转换为POJO?
如何将非标准类JSON格式的SQS消息解析为POJO
嘿,我完全懂你的困扰——这种键名不带引号的类JSON格式确实够让人头疼的,既不是标准JSON也不是ION,直接用常规的JSON解析工具根本没法转成POJO,想提取Body里你真正关心的Message部分都无从下手。不过别担心,咱们有两种靠谱的解决方案可以试试:
先理清楚你的场景
你正在通过JMS异步接收SNS发布到SQS的消息,用onMessage方法拿到的消息文本是类似这样的非标准格式:
示例非标准格式
{ ExampleKey1: ExampleValue1, ExampleKey2: ExampleValue2, ExampleObjectKey: { "ObjectKey" : "ObjectValue" } }
你实际收到的消息格式
{MessageId: 123-123-123,ReceiptHandle: BigTextWithCharactersLike+and/andNumbers123,MD5OfBody: AlphaNumberic123,Body: { "Type" : "Notification", "MessageId" : "uuid-uuid-uuid-uuid", "TopicArn" : "arn:aws:sns:us-west-2:someARN", "Message" : "{\"this\":\"is\",\"the\":\"part\",\"i\":\"am\",\"interested\":\"in\"}", "Timestamp" : "timestamp", "SignatureVersion" : "1", "Signature" : "alphanumeric+charatersLike+and/and==", "SigningCertURL" : "https://an-sns-url", "UnsubscribeURL" : "https://an-sns-url" },Attributes: {},MessageAttributes: {}}
获取消息的代码
public void onMessage(Message message) { try { // Cast the received message as TextMessage and print the text to screen. System.out.println("Received: " + ((TextMessage) message).getText()); } catch (JMSException e) { e.printStackTrace(); } }
两种解决方案推荐
方案一:预处理字符串为标准JSON
这种格式的核心问题是键名没有被双引号包裹,我们可以用正则表达式把所有键名加上双引号,转换成标准JSON后再用常规解析工具处理:
- 编写正则替换逻辑,匹配所有符合
键名:格式的部分,替换为"键名":。注意要避免替换到值里的内容(比如Body中已经带引号的字段),可以用这个正则:(\w+)(?=:) - 用Jackson或Gson等JSON库解析处理后的字符串到自定义POJO。
示例代码(Java + Jackson):
import com.fasterxml.jackson.databind.ObjectMapper; import java.util.regex.Pattern; public class MessageParser { private static final Pattern KEY_PATTERN = Pattern.compile("(\\w+)(?=:)"); public void parseMessage(TextMessage textMessage) throws Exception { String rawMessage = textMessage.getText(); // 预处理:给所有键名加上双引号,转成标准JSON String standardJson = KEY_PATTERN.matcher(rawMessage).replaceAll("\"$1\""); // 解析到自定义的SQS消息POJO ObjectMapper objectMapper = new ObjectMapper(); SqsMessage sqsMessage = objectMapper.readValue(standardJson, SqsMessage.class); // 提取Body中的Notification内容,再解析里面的Message字段 Notification notification = objectMapper.readValue(sqsMessage.getBody(), Notification.class); String innerMessageJson = notification.getMessage(); // 解析你真正关心的内容到目标POJO YourTargetPojo targetData = objectMapper.readValue(innerMessageJson, YourTargetPojo.class); } } // 自定义SQS消息POJO class SqsMessage { private String MessageId; private String ReceiptHandle; private String MD5OfBody; private String Body; // 其他对应字段的getter/setter方法 } // SNS Notification对应的POJO class Notification { private String Type; private String MessageId; private String TopicArn; private String Message; // 其他对应字段的getter/setter方法 } // 你真正关心的内容对应的POJO class YourTargetPojo { private String this; private String is; private String the; // 对应字段的getter/setter方法 }
方案二:直接使用AWS SDK的封装类
你提到这个消息对应AWS SDK中封装的Message类,那其实完全可以跳过手动解析的麻烦,直接用AWS SDK的SQS客户端来接收消息——SDK会自动帮你把消息解析成现成的Message对象,不用自己处理非标准格式:
示例代码(AWS SDK v2):
import software.amazon.awssdk.services.sqs.SqsClient; import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest; import software.amazon.awssdk.services.sqs.model.Message; import com.fasterxml.jackson.databind.ObjectMapper; public class SqsAsyncReceiver { public void receiveMessages() { // 初始化SQS客户端 SqsClient sqsClient = SqsClient.create(); String yourQueueUrl = "你的队列URL"; // 构建接收消息的请求 ReceiveMessageRequest request = ReceiveMessageRequest.builder() .queueUrl(yourQueueUrl) .maxNumberOfMessages(1) .build(); // 接收并解析消息 for (Message sqsMessage : sqsClient.receiveMessage(request).messages()) { // 获取SNS推送的Notification内容(已经是标准JSON字符串) String notificationJson = sqsMessage.body(); // 解析Notification到对应POJO ObjectMapper objectMapper = new ObjectMapper(); Notification notification = objectMapper.readValue(notificationJson, Notification.class); // 解析你关心的Message部分到目标POJO YourTargetPojo targetData = objectMapper.readValue(notification.getMessage(), YourTargetPojo.class); } } }
这个方案更稳妥,因为SDK已经处理了所有格式细节,不用自己写正则处理非标准格式,不容易出错。
内容的提问来源于stack exchange,提问作者akshitBhatia
相关产品推荐
相关产品推荐

