Android集成MS Graph SDK报XMLInputFactory.newFactory方法不存在错误
问题描述
com.fasterxml.jackson.dataformat包下的XmlFactory类是Java版微软MS Graph SDK的传递依赖,调用SDK实现邮件发送功能时抛出运行时错误:
Caused by: java.lang.NoSuchMethodError: No static method newFactory(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljavax/xml/stream/XMLInputFactory; in class Ljavax/xml/stream/XMLInputFactory; or its super classes
经Gradle依赖树排查,项目加载的XMLInputFactory、XMLOutputFactory来自旧版stax:stax-api:1.0.1,该版本发布时newFactory方法尚未替代newInstance方法,不存在被调用的newFactory方法,判定为问题根因。
错误触发点为构建InteractiveBrowserCredential实例的逻辑:
this.interactiveBrowserCredential = new InteractiveBrowserCredentialBuilder() .clientId(clientId) .redirectUrl(myRedirectURL) .build();
现有配置与已尝试操作
当前项目build.gradle配置如下:
plugins { id 'com.android.application' } android { compileSdk 32 defaultConfig { applicationId "com.organisation.appname" minSdk 26 targetSdk 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } buildFeatures { viewBinding true } packagingOptions { exclude 'project.properties' exclude 'META-INF/INDEX.LIST' exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/LICENSE' exclude 'META-INF/LICENSE.txt' exclude 'META-INF/license.txt' exclude 'META-INF/NOTICE' exclude 'META-INF/NOTICE.txt' exclude 'META-INF/notice.txt' exclude 'META-INF/ASL2.0' exclude 'META-INF/AL2.0' exclude 'META-INF/LGPL2.1' exclude 'META-INF/io.netty.versions.properties' //pickFirst 'META-INF/services/javax.xml.stream.XMLInputFactory' } } dependencies { //implementation 'javax.xml.stream:stax-api:1.0' //implementation 'stax:stax:1.2.0' implementation fileTree(include: ['*.aar'], dir: 'libs') implementation 'androidx.appcompat:appcompat:1.4.2' implementation 'com.google.android.material:material:1.6.1' implementation('com.microsoft.graph:microsoft-graph:5.29.0') { //exclude group: "stax", module: "stax" //exclude group: "stax", module: "stax-api" } implementation 'com.google.guava:guava:30.1.1-android' implementation('com.azure:azure-identity:1.2.5') { //exclude group: "stax", module: "stax" //exclude group: "stax", module: "stax-api" } implementation "org.jetbrains.kotlin:kotlin-stdlib:1.5.31" testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' }
业务逻辑代码片段:
public Emailing() { this.interactiveBrowserCredential = new InteractiveBrowserCredentialBuilder() .clientId(clientId) .redirectUrl(myRedirectURL) .build(); this.tokenCredentialAuthProvider = new TokenCredentialAuthProvider(scopes, interactiveBrowserCredential); this.graphClient = GraphServiceClient .builder() .authenticationProvider(tokenCredentialAuthProvider) .buildClient(); } public void emailForVisitorArrival(String name, String purpose, List<String> recipients) { Date timestamp = Calendar.getInstance().getTime(); String timestampText = (String) DateFormat.format("dd MMM yyyy | hh:mm a", timestamp); Message message = new Message(); message.subject = name + " has arrived."; ItemBody body = new ItemBody(); body.contentType = BodyType.TEXT; body.content = myEmailContent; message.body = body; LinkedList<Recipient> toRecipientsList = new LinkedList<Recipient>(); Recipient toRecipients = new Recipient(); for (String recipient: recipients) { EmailAddress emailAddress = new EmailAddress(); emailAddress.address = recipient; toRecipients.emailAddress = emailAddress; toRecipientsList.add(toRecipients); message.toRecipients = toRecipientsList; } graphClient.me() .sendMail(UserSendMailParameterSet .newBuilder() .withMessage(message) .withSaveToSentItems(false) .build()) .buildRequest() .post(); }
已尝试以下操作但未解决问题:
- 手动引入不同版本的stax依赖
- 排除依赖树中的旧版stax依赖
修复步骤
- 在
build.gradle中添加全局依赖强制规则,指定加载包含newFactory方法的stax-api版本,将以下配置放在android节点同级位置:
该版本已实现configurations.all { resolutionStrategy.force 'javax.xml.stream:stax-api:1.0-2' }XMLInputFactory.newFactory静态方法,完全匹配Jackson XML组件的调用逻辑,避免使用存在缺陷的1.0.1版本。 - 修改packagingOptions规则,处理StAX服务配置文件冲突,取消原有注释并补充对应规则:
packagingOptions { // 保留原有所有exclude规则 pickFirst 'META-INF/services/javax.xml.stream.XMLInputFactory' pickFirst 'META-INF/services/javax.xml.stream.XMLOutputFactory' } - 检查
libs目录下的本地aar包,如果有aar内置了旧版stax-api的class文件,手动解包移除内置的stax相关类后重新打包,避免本地aar类加载优先级高于远程依赖导致版本规则失效。 - 执行Gradle同步,清理构建缓存后重新编译运行即可。
内容的提问来源于stack exchange,提问作者Joshua Lewis
相关产品推荐
相关产品推荐

