OGNL-3.1がひっそりとリリースされているのですが、かなり困った仕様変更が入ってます。
foo || bar
が動かない
例えば、bar
が文字列型の値だとして、
foo.aMethod(bar || "default string")
のようにして、bar
がnull
なら"default string"
を渡すようなコードが動かなくなります。
これはJavascript等では頻出するイディオムです。
どう変わったのか
ここに詳細があります。 http://github.com/jkuhnert/ognl/issues/8
要するに、文字列型なら"true"
の時のみtrue
、それ以外は常にfalse
です。
だからfooが"1"
とかそういう値であってもfalse
になります。
流石にメンテナー*1もこの非互換性は気になっているようで、この仕様変更を含まない3.0.12も同時リリースされています。
Javassistで無かったことにする
件のPullRequestの作者*2は、どうもJavassistでこの動作を無理矢理ねじ込んでいたようなのですが、とうとう我慢できなくなってPullRequestを送ったようです。
For me, it would allow me to remove this hugely ugly, javassist-based hack from thymeleaf: https://github.com/thymeleaf/thymeleaf/blob/159f963907e9d5e3943843031845df28934adafc/src/main/java/org/thymeleaf/standard/expression/OgnlVariableExpressionEvaluator.java#L201-L261
一方の僕はこの仕様変更を受け入れられないので、こちらもJavassistで無理やり打ち消そうと思います。
3.0.12を使えばいいのでは?という意見もありますが、以後の主流になる3.1系を使いたいのです。
final ClassPool classPool = ClassPool.getDefault(); classPool.appendClassPath(new ClassClassPath(this.getClass())); final CtClass ctClass = classPool.get(OgnlOps.class.getName()); final CtClass objectType = ctClass.getClassPool().get(Object.class.getName()); final String code = "if ($1 instanceof CharSequence)" + "{ return ((CharSequence) $1).length() > 0; }"; ctClass.getDeclaredMethod("booleanValue", new CtClass[] { objectType }) .insertBefore(code);
この処理をJava Agent経由でねじ込むと元通りになります。