Properties 和 Jsp Compile Nullpointer

之前在碰到一个bug,email service的smtp服务由于没有设置timeout,当和服务器连接失败时,会永远hang在那里。然后就在代码里加上了下面的红色字体(在smtp服务首次被调用时,下面的代码会被调用到)。


<span style="color:#ff0000;">private static final int MAIL_SMTP_TIMEOUT = 300000;</span>
Properties props = System.getProperties();
           props.put( "mail.smtp.host", smtpHost);
           <span style="color:#ff0000;">props.put("mail.smtp.timeout", MAIL_SMTP_TIMEOUT);</span>
            m_session = Session. getDefaultInstance(props, null);

      但是却发现,这样修改后jsp会随机的出现无法compile的情况,报错如下:

HTTP Status 500 
The server encountered an internal error () that prevented it from fulfilling this request.
        org.apache.jasper.JasperException: Unable to compile class for JSP
        org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:520)
        org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:295)
        org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
        org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
root cause: java.lang.NullPointerException
        java.util.Hashtable.put(Hashtable.java:396)
        org.apache.tools.ant.PropertyHelper.setProperty(PropertyHelper.java:335)
        org.apache.tools.ant.Project.setPropertyInternal(Project.java:460)
        org.apache.tools.ant.Project.setSystemProperties(Project.java:800)
        org.apache.tools.ant.Project.init(Project.java:261)
        org.apache.jasper.compiler.Compiler.getProject(Compiler.java:116)
        org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:320)
        org.apache.jasper.compiler.Compiler.compile(Compiler.java:472)
        org.apache.jasper.compiler.Compiler.compile(Compiler.java:439)
        org.apache.jasper.compiler.Compiler.compile(Compiler.java:451)
        org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:511)
        org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:295)
        org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
        org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

         具体就是由于ant在set properties的时候出现了null pointer, 导致jsp的编译失败。
          起初并没有怀疑是代码的问题(真莫有一点怀疑啊...),因为这次修改只是加了这个属性以及升级了mail的jar包,而没有可能引入任何null值。
         于是有了两种猜测,一种是新的jar包造成的,一种是有人动了server的环境。
          对环境进行了仔细的检查,甚至对prod环境进行了jdb调试,折腾一天无果。
          后来经过不断的重启service,发现一个规律:
          如果在服务起来后,如果首先访问jsp页面,那jsp就可以编译出来;如果在反问jsp前先访问了某些其他服务,则会nullpointer。然后自然就想到,这个某些其他服务应该就是这个smtp服务。
         由于email service是很多年前写的,所以用的tomcat版本比较老(5.0的), ant jar包的版本是1.6.4
        于是去看了源码,发现如下:


1.6.4

public  void  setSystemProperties () {
        Properties systemP = System. getProperties();
        Enumeration e = systemP.propertyNames();
         while  (e.hasMoreElements()) {
            String propertyName = (String) e.nextElement();
            String value = systemP.getProperty(propertyName);
             this .setPropertyInternal(propertyName, value);
        }
}

1.7.1

public  void  setSystemProperties() {
           Properties systemP = System.getProperties();
               Enumeration e = systemP.propertyNames();
                  while  (e.hasMoreElements()) {
                    String propertyName = (String) e.nextElement();
                      String value = systemP.getProperty(propertyName);
                        if (value != null) {
                           this.setPropertyInternal(propertyName, value);
                      }
                  }
         }

         原来在ant的1.7.1之前,一直没有做nullpointer的检测,就直接赋值到一个hashtable里面,之后的版本已经改了这个bug。
但是Properties本身就是个hashtable,放进去的指不可能有null值,为什么拿出来的时候怎么可能有null值,我第一反应是,添加进去的时候是好的,后来由于调用了某些服务,使其中的某个或某些值变为null。后来看了下Properties的源码,也是醉了.............

public  String getProperty(String key) {
     Object oval =  super .get(key);
     String sval = (oval  instanceof  String) ? (String) oval :  null ;
       return  ((sval ==  null ) && (  defaults  !=  null )) ?  defaults . getProperty(key) : sval;
    }

   尼玛,只要不是String的拿出来都妹的是null啊,晕啊,你说你个Properties,只要是Object的都能放的进去( Properties extends Hashtable<Object,Object>),偏偏getProperty的时候你只能拿String的值,toStirng都不尝试下!!!你如果只能放String那你就改为Properties extendsHashtable<String,String>啊,真的不是很理解。后来在stackoverflow上看到一个大牛的话:from a design perspective, the Properties class is considered to be one of the "mistakes" of java.
 
      但是还有问题,我在一个测试环境测试(也是tomcat5.0)过这个改动,并没有出现nullpointer的情况,后来检查了下,tomcat版本虽然相同,但是测试环境的ant却是1.6.1的,更奇怪了,旧版本是好的,1.6.4反而坏了,看看源码:

1.6.1
public  void  setSystemProperties() {
        Properties systemP = System. getProperties();
        Enumeration e = systemP.keys();
         while  (e.hasMoreElements()) {
            Object name = e.nextElement();
            String value = systemP.get(name).toString();
             this . setPropertyInternal(name.toString(), value);
        }
}

         这里虽然也没有做null 检查,但是用的是get方法,然后做的toString操作。其实这里没做null检查应该也很容易报nullpointer ,估计1.6.4是为了做优化改为了String value = systemP.getProperty(propertyName); 

终于,都清楚了!

prod环境用的是1.6.4版本的ant,没有做null检测,但是getProperty的时候又会把非String的值作为null返回,所以报了nullpointer;而1.6.1的版本虽然没有做nullpointer检测,但是用的是hastable的 get方法 和 Object toString方法,所以即使put进去了非Stirng的值,也不会报nullpointer。
其实我改的这段代码感觉有个很不好的地方,是用到了Properties props = System.getProperties();这样一来,我改错的地方不仅会影响我自己的服务,甚至会影响整个jvm的环境。但是这个是原来前辈写的,而且他估计考虑到是配置已经写到系统变量之类的情况吧,总之就不方便改了。

教训:
     以后报bug首先还是检查代码,不行就直接看源码,不要自己觉得不会错就一定不会错,尤其是自己没看过源码的东西;
     能用HashTable的东西就别用Properties了,用Properties就只放String或者load吧,安心。。。
     
     
     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值