使用Microsoft Graph API发送带附件邮件时遇NoSuchMethodError求助
我在基于Microsoft官方文档开发使用Graph API发送带附件的邮件时遇到错误,该错误仅在为Message添加Attachment列表时触发。
错误详情
错误发生在com.microsoft.graph.serializer.CollectionPageSerializer类的序列化方法中,错误日志如下:
[2022-09-22T09:41:04.345Z] System.Private.CoreLib: Exception while executing function: Functions.QueueTriggerMails. System.Private.CoreLib: Result: Failure
Exception: NoSuchMethodError: com.google.gson.JsonParser.parseString(Ljava/lang/String;)Lcom/google/gson/JsonElement;
Stack: java.lang.reflect.InvocationTargetException
.
.
.
[2022-09-22T09:41:04.356Z] Caused by: java.lang.NoSuchMethodError: com.google.gson.JsonParser.parseString(Ljava/lang/String;)Lcom/google/gson/JsonElement;
[2022-09-22T09:41:04.356Z] at com.microsoft.graph.serializer.CollectionPageSerializer.serialize(CollectionPageSerializer.java:78)
.
.
.
触发错误的序列化方法代码:
/** * Serializes an CollectionPage * * @param src the CollectionPage variable for serialization * @param logger the logger * @param <T1> the entity type for the collection * @param <T2> the collection request builder interface type * @return JsonElement of CollectionPage */ @Nullable public static <T1, T2 extends BaseRequestBuilder<T1>> JsonElement serialize(@Nonnull final BaseCollectionPage<T1, T2> src, @Nonnull final ILogger logger) { if(src == null) { return null; } Objects.requireNonNull(logger, "parameter logger cannot be null"); JsonArray jsonArray = new JsonArray(); List<T1> items = src.getCurrentPage(); serializer = new DefaultSerializer(logger); for(T1 item : items) { final String json = serializer.serializeObject(item); final JsonElement element = JsonParser.parseString(json); if(element != null && element.isJsonObject()) { final JsonObject jsonObject = element.getAsJsonObject(); jsonArray.add(jsonObject); } } return jsonArray; }
相关业务代码
发送邮件核心方法
public void sendEmail(Mail mailProperties, ExecutionContext context) { final TokenCredentialAuthProvider tokenCredentialAuthProvider = new TokenCredentialAuthProvider(scopes, clientSecretCredential); GraphServiceClient<Request> graphClient = GraphServiceClient .builder() .authenticationProvider(tokenCredentialAuthProvider) .buildClient(); try { graphClient.users(noReplyUserId) .sendMail(UserSendMailParameterSet .newBuilder() .withMessage(createMessage(mailProperties, context)) .withSaveToSentItems(null) .build()) .buildRequest() .post(); } catch (ClientException | IllegalArgumentException e) { context.getLogger().warning("Couldn't send the email due to errors while reading the input message"); context.getLogger().warning(e.getMessage()); } }
创建带附件的邮件方法
private Message createMessage(Mail mailProperties, ExecutionContext context) throws IllegalArgumentException { Message message = new Message(); ItemBody body = new ItemBody(); body.contentType = BodyType.HTML; String bodyContent = new String(Base64.getDecoder().decode(mailProperties.getBody()), StandardCharsets.UTF_8); body.content = bodyContent; List<Recipient> recipientsList = new ArrayList<>(); for (String item : mailProperties.getDestinatario().split(",")) { EmailAddress emailAddress = new EmailAddress(); emailAddress.address = item.trim(); Recipient recipient = new Recipient(); recipient.emailAddress = emailAddress; recipientsList.add(recipient); } message.subject = mailProperties.getSubject(); message.body = body; message.toRecipients = recipientsList; FileAttachment attachment = new FileAttachment(); attachment.name = "attachment.txt"; attachment.contentType = "text/plain"; attachment.contentBytes = Base64.getDecoder().decode("SGVsbG8gV29ybGQh"); List<Attachment> attachmentsList = new ArrayList<Attachment>(); attachmentsList.add(attachment); AttachmentCollectionResponse attachmentCollectionResponse = new AttachmentCollectionResponse(); attachmentCollectionResponse.value = attachmentsList; AttachmentCollectionPage attachmentCollectionPage = new AttachmentCollectionPage(attachmentCollectionResponse, null); message.attachments = attachmentCollectionPage; return message; }
依赖配置
使用的Graph API版本为5.31.0,Maven依赖声明如下:
<dependency> <groupId>com.microsoft.graph</groupId> <artifactId>microsoft-graph</artifactId> <version>5.31.0</version> </dependency>
问题分析与解决步骤
核心原因
NoSuchMethodError表示运行时无法找到JsonParser.parseString()方法,该方法是Gson 2.8.0及以上版本才新增的API。问题根源是项目依赖的Gson版本低于要求,或存在多版本Gson依赖冲突,导致Graph SDK运行时加载了旧版本Gson。
解决措施
升级Gson依赖版本
在Maven中明确指定Gson版本为2.8.0或更高(建议使用与Graph SDK 5.31.0兼容的版本,可通过mvn dependency:tree命令查看当前依赖树):<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency>排除冲突的旧版本Gson
如果其他依赖引入了旧版本Gson,在Graph SDK依赖中排除该冲突依赖:<dependency> <groupId>com.microsoft.graph</groupId> <artifactId>microsoft-graph</artifactId> <version>5.31.0</version> <exclusions> <exclusion> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </exclusion> </exclusions> </dependency>简化附件赋值逻辑
无需手动创建AttachmentCollectionPage,Graph SDK支持直接将List<Attachment>赋值给message.attachments,可避免手动构建集合页带来的序列化问题:
修改createMessage方法中的附件部分代码:// 替换原AttachmentCollection相关代码 List<Attachment> attachmentsList = new ArrayList<Attachment>(); attachmentsList.add(attachment); message.attachments = attachmentsList; // 直接赋值List即可
内容的提问来源于stack exchange,提问作者Gor Sahakyan

