Java调用Microsoft exchange ews接口空指针问题分析

项目中需要通过java获取exchange的新邮件,使用官方接口包,测试时总是有空指针(java.lang.NullPointerException)异常:

java.lang.NullPointerException
	at microsoft.exchange.webservices.data.Strings.<clinit>(Strings.java:197)
	at microsoft.exchange.webservices.data.EwsXmlReader.internalReadElement(EwsXmlReader.java:57)
	at microsoft.exchange.webservices.data.EwsXmlReader.readStartElement(EwsXmlReader.java:345)
	at microsoft.exchange.webservices.data.ServiceRequestBase.readResponse(ServiceRequestBase.java:285)
	at microsoft.exchange.webservices.data.SimpleServiceRequestBase.readResponse(SimpleServiceRequestBase.java:126)
	at microsoft.exchange.webservices.data.SimpleServiceRequestBase.internalExecute(SimpleServiceRequestBase.java:33)
	at microsoft.exchange.webservices.data.MultiResponseServiceRequest.execute(MultiResponseServiceRequest.java:146)
	at microsoft.exchange.webservices.data.ExchangeService.bindToFolder(ExchangeService.java:355)
	at microsoft.exchange.webservices.data.ExchangeService.bindToFolder(ExchangeService.java:380)
	at microsoft.exchange.webservices.data.Folder.bind(Folder.java:53)
	at microsoft.exchange.webservices.data.Folder.bind(Folder.java:112)
	at com.aires.Test.main(Test.java:28)
Exception in thread "main" java.lang.NullPointerException
	at java.util.regex.Matcher.getTextLength(Unknown Source)
	at java.util.regex.Matcher.reset(Unknown Source)
	at java.util.regex.Matcher.<init>(Unknown Source)
	at java.util.regex.Pattern.matcher(Unknown Source)
	at java.util.Formatter.parse(Unknown Source)
	at java.util.Formatter.format(Unknown Source)
	at java.util.Formatter.format(Unknown Source)
	at java.lang.String.format(Unknown Source)
	at microsoft.exchange.webservices.data.EwsXmlReader.internalReadElement(EwsXmlReader.java:56)
	at microsoft.exchange.webservices.data.EwsXmlReader.readStartElement(EwsXmlReader.java:345)
	at microsoft.exchange.webservices.data.ServiceRequestBase.readResponse(ServiceRequestBase.java:285)
	at microsoft.exchange.webservices.data.SimpleServiceRequestBase.readResponse(SimpleServiceRequestBase.java:126)
	at microsoft.exchange.webservices.data.SimpleServiceRequestBase.internalExecute(SimpleServiceRequestBase.java:33)
	at microsoft.exchange.webservices.data.MultiResponseServiceRequest.execute(MultiResponseServiceRequest.java:146)
	at microsoft.exchange.webservices.data.ExchangeService.bindToFolder(ExchangeService.java:355)

刚开始时没多想,以为接口调用得有问题,后多方查找无果,反编译jar包,终于有所收获,特此记录:

1、第一个异常为缺少配置文件,不知道是不是我拿到的jar包有问题,问题出在microsoft.exchange.webservices.data.Strings,该类内容大概为错误信息常量,其中有一静态块

/*     */   static
/*     */   {
/*     */     try
/*     */     {//此处bundle为一Properties对象
/* 223 */       BUNDLE.load(Thread.currentThread().getContextClassLoader().getResource("microsoft/exchange/webservices/data/Strings.properties").openStream());
/*     */     }
/*     */     catch (Exception e) {
/* 226 */       e.printStackTrace();//此处为上文第一个NullPointerException出处
/*     */     }
/* 228 */     loadProperties();
/*     */   }

其中loadProperties做的是常量初始化:

private static void loadProperties()
/*     */   {
/* 233 */     BothSearchFilterAndQueryStringCannotBeSpecified = BUNDLE.getProperty("BothSearchFilterAndQueryStringCannotBeSpecified");
/*     */ 
/* 236 */     IndexIsOutOfRange = BUNDLE.getProperty("IndexIsOutOfRange");
/*     */ 
/* 239 */     CannotCallConnectDuringLiveConnection = BUNDLE.getProperty("CannotCallConnectDuringLiveConnection");
/* 240 */     InvalidAutodiscoverSmtpAddressesCount = BUNDLE.getProperty("InvalidAutodiscoverSmtpAddressesCount");
/* 241 */     NoSoapOrWsSecurityEndpointAvailable = BUNDLE.getProperty("NoSoapOrWsSecurityEndpointAvailable");
/* 242 */     ObjectDoesNotHaveId = BUNDLE.getProperty("ObjectDoesNotHaveId");
。。。。。

当配置Strings.properties不存在时,抛出第一处异常并继续执行loadProperties(),执行完成后所有字符串“常量”被设置为null(因为此时BUNDLE内容为空)。


2、API包中,大量异常抛出使用了String.foramt方法,并将Strings中的“常量”(此时应为null)作为第一个参数传入,如:

microsoft.exchange.webservices.data.SimpleServiceRequestBase.java

/*     */     catch (HTTPException e)
/*     */     {
/*     */       Object serviceResponse;
/* 175 */       if (e.getMessage() != null) {
/* 176 */         getService().processHttpResponseHeaders(
/* 177 */           TraceFlags.EwsResponseHttpHeaders, response);
/*     */       }
/*     */ 
/* 180 */       throw new ServiceRequestException(String.format(
/* 181 */         Strings.ServiceRequestFailed, new Object[] { e.getMessage() }), e);
/*     */     }
/*     */     catch (IOException e) {
/* 184 */       throw new ServiceRequestException(String.format(
/* 185 */         Strings.ServiceRequestFailed, new Object[] { e.getMessage() }), e);
/*     */     }

此处有坑:第一个参数为null时,String.format将抛出NullPointerException,并且该异常将替代实际异常抛出,实际异常被“吃掉”;调用者在使用接口时捕获的是一个无用的空指针异常,然后被各种误导。。。。


3、解决方式:
1)增加对应配置文件;
2)修改Jar包中的异常抛出方式,抛出原异常;
我们项目中未考虑修改原jar包,配置文件内容又多,偷了个懒,简单将反编译的源码放入工程中覆盖jar包中的对应内容并做简单调整,输出实际的异常信息,根据实际异常修改调用方式至成功后,删除了添加到工程中的源码。我们的调整方式比较暴力,直接抛出原异常:

/* 167 */         InputStream responseStream = 
/* 168 */           ServiceRequestBase.getResponseStream(response);
System.out.println("-----------响应内容开始-----------------");//此处用于查看接口返回数据
System.out.println("响应内容长度:" + responseStream.available());
BufferedReader br = new BufferedReader(new InputStreamReader(responseStream));
StringBuilder sb = new StringBuilder();
String tmp;
while((tmp = br.readLine()) != null){
	sb.append(tmp);
	System.out.println(tmp);
}
System.out.println("-----------响应内容结束-----------------");
ByteArrayInputStream bis = new ByteArrayInputStream(sb.toString().getBytes());
/* 169 */         EwsServiceXmlReader ewsXmlReader = new EwsServiceXmlReader(
/* 170 */           bis, getService());
/* 171 */         serviceResponse = readResponse(ewsXmlReader);
/*     */       }
/*     */     }
/*     */     catch (HTTPException e)
/*     */     {
/* 175 */       if (e.getMessage() != null) {
/* 176 */         getService().processHttpResponseHeaders(
/* 177 */           TraceFlags.EwsResponseHttpHeaders, response);
/*     */       }
/*     */ 
/* 180 */       throw e;//此处修改
/*     */     }
/*     */     catch (IOException e) {
/* 184 */       throw e;//此处修改
/*     */     }
文首的第二个异常为此处:
EwsXmlReader.java

/*      */   private void internalReadElement(XmlNamespace xmlNamespace, String localName, XMLNodeType nodeType)
/*      */     throws Exception
/*      */   {
/*  109 */     if (xmlNamespace == XmlNamespace.NotSpecified) {
/*  110 */       internalReadElement("", localName, nodeType);
/*      */     } else {
/*  112 */       read(nodeType);
/*      */ 
/*  114 */       if ((!getLocalName().equals(localName)) || 
/*  115 */         (getNamespaceUri() != 
/*  116 */         EwsUtilities.getNamespaceUri(xmlNamespace)))
/*  117 */         throw new ServiceXmlDeserializationException(
/*  119 */           String.format(
/*  120 */           Strings.UnexpectedElement, new Object[] { 
/*  122 */           EwsUtilities.getNamespacePrefix(
/*  123 */           xmlNamespace), 
/*  124 */           localName, nodeType.toString(), 
/*  125 */           getName(), getNodeType()
/*  126 */           .toString() }));
/*      */     }
/*      */   }




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值