tomcat 7 servlet annotation StackOverflowError

今天部署代码的时候, 遇到如下的出错:

SEVERE: Error waiting for multi-thread deployment of WAR files to complete
java.util.concurrent.ExecutionException: java.lang.StackOverflowError
    at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:252)
    at java.util.concurrent.FutureTask.get(FutureTask.java:111)
    at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:751)
    at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:471)
    at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1412)
    at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:312)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:401)
    at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:346)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1145)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:782)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1566)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1556)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
Caused by: java.lang.StackOverflowError
    at java.util.Random.nextInt(Random.java:239)
    at sun.misc.Hashing.randomHashSeed(Hashing.java:254)
    at java.util.HashMap.<init>(HashMap.java:255)
    at java.util.HashMap.<init>(HashMap.java:305)
    at java.util.HashSet.<init>(HashSet.java:103)
    at org.apache.catalina.startup.ContextConfig.populateSCIsForCacheEntry(ContextConfig.java:2169)
    at org.apache.catalina.startup.ContextConfig.populateSCIsForCacheEntry(ContextConfig.java:2188)
    at org.apache.catalina.startup.ContextConfig.populateSCIsForCacheEntry(ContextConfig.java:2188)
    at org.apache.catalina.startup.ContextConfig.populateSCIsForCacheEntry(ContextConfig.java:2188)
    at org.apache.catalina.startup.ContextConfig.populateSCIsForCacheEntry(ContextConfig.java:2188)
    at org.apache.catalina.startup.ContextConfig.populateSCIsForCacheEntry(ContextConfig.java:2188)
    at org.apache.catalina.startup.ContextConfig.populateSCIsForCacheEntry(ContextConfig.java:2188)
    at org.apache.catalina.startup.ContextConfig.populateSCIsForCacheEntry(ContextConfig.java:2188)
    at org.apache.catalina.startup.ContextConfig.populateSCIsForCacheEntry(ContextConfig.java:2188)
    at org.apache.catalina.startup.ContextConfig.populateSCIsForCacheEntry(ContextConfig.java:2188)
    ......

上面出错stack递归, 导致溢出. 这段代码应该发生在Servlet 容器启动的时候自动扫描 servlet 的 annotation时.
google 一下, 发现上述的情况在下面这个bug 中有描述:
https://issues.apache.org/bugzilla/show_bug.cgi?id=53871, RESOLVED FIXED Version: 7.0.35
上面出错的代码所用的tomcat 版本为: Version 7.0.27

那么换做 tomcat 7.0.40实验一下, 报出如下的出错内容 (出错的error message 被优化, 明确指出出错的原因):

Caused by: java.lang.IllegalStateException: Unable to complete the scan for annotations for web application [] due to a StackOverflowError. Possible root causes
 include a too low setting for -Xss and illegal cyclic inheritance dependencies. The class hierarchy being processed was 
 [org.jaxen.util.AncestorOrSelfAxisIterator->org.jaxen.util.AncestorAxisIterator->org.jaxen.util.AncestorOrSelfAxisIterator]
        at org.apache.catalina.startup.ContextConfig.checkHandlesTypes(ContextConfig.java:2179)

问题出在2个Class的依赖关系, 在一个包中, A 是B的之类, 另外一个包中, B 却是A的之类:
jaxen-1.1.6.jar 包中的依赖关系

public class org.jaxen.util.AncestorOrSelfAxisIterator implements java.util.Iterator
public class org.jaxen.util.AncestorAxisIterator extends org.jaxen.util.AncestorOrSelfAxisIterator

jaxen-core-1.0-FCS.jar 包中的依赖关系:

public class org.jaxen.util.AncestorOrSelfAxisIterator extends org.jaxen.util.AncestorAxisIterator
public class org.jaxen.util.AncestorAxisIterator extends org.jaxen.util.StackedIterator

解决方案: 在pom.xml 中找到2个jar, 把其中一个 exclude 掉, 去试试, 是不是好了

有人也遇到同样的问题:
http://hongjiang.info/2014/06/

windows 系统无法 粘贴 复制 copy/paste not working

最近在 chrome, eclipse, outlook 中有时候没法粘贴, 复制, 不论是 Ctrl+C, Ctrl+V 还是先选中在右键复制/粘贴, 都不管用.
在最后忍无可忍的时候, 突然想起来, 以前发生过, 只要关掉 windows 远程桌面就好了.

这应该是windows 远程桌面的 rdpclip.exe 的一个 Bug, 一开始还没问题, 如果远程桌面开的时间长了, 就会出现这个问题.

小米手机充电器 拆解

不知道从那天开始, 小米手机的充电器无法充电了, 仔细检查一下, 应该是充电器接触不良, 刚插入的时候, 能冲一瞬间, 有时候, 用手使劲掰住, 也能冲一会, 一旦放开, 就又无法充电了. 于是就想打开充电器看看到底怎么回事.

首先百度搜到官方论坛的这么一个帖子: 小米充电器辛苦拆卸全程, 真是惨不忍睹, 竟然锯开, 不过还是从回帖中发现, 需要从插头那头拆开. 开始动手了, 首先说下工具:
1) 美工刀, 用来划开粘住的接缝;
2) 钳子, 用力夹住插头, 拔出里面元器件;
3) 电笔, 测试里面某些东西上有没有电;
4) 胶水, 最后把他们在粘到一块.

直接上图吧:
全套工具, 注意看充电器插头那端的接缝, 那是用美工刀的尖一点点划的结果.
IMG_20150124_173947.jpg
当用美工刀把四边都弄出缝来之后, 可以用钳子夹住插头, 活动几下, 然后拔出:
IMG_20150124_173521.jpg
IMG_20150124_173512.jpg
最后使用不带壳的充电器, 小心有电...
D8007DB4FEFE1C6D83B6E422B72CBD27.png

我这个拆开再装上, 竟然就能充电了, 装的时候, 用胶水把划开的地方全部粘一下.

路由器网站 解决端口 80 问题

在中国这个和谐和言论自由的国度, 要在路由器上建网站, 有一个很大的阻碍就是80端口不能用. 幸而443 能用, 所以可以使用https.

可是大部分的网站默认是80端口的, 所以客户直接是访问80端口的. 针对所有通过二级域名访问的, 都可以通过显示/隐身的DNS设置, 转到https 上去. 比如 你的网站是 home.tianxiaohui.com. 那么你可以在路由器设置所有的 *.tianxiaohui.com 都转到 https://home.tianxiaohui.com, 那么所有的二级域名都正常可以访问了.

那么剩下 tianxiaohui.com 这个一级域名了, 因为有非常多的人可能直接访问这个, 并且是默认80端口, 那么就需要一个中转网站, 只要tianxiaohui.com 的 IP 指向这个中转站, 这个中转站在通过301 永久重定向到 https://home.tianxiaohui.com 那么就解决了.

于是今天就找到了一个免费的空间, 只是用它来做重定向, 它就是 http://cpanel.hostinger.com.hk/order/accounts-order.

其实最后只剩下唯一一个了 http://home.tanxiaohui.com, 这个永远连接不上80端口 :(