人生、気合いと具合 - blog

カテゴリ:Java

この記事は Java Puzzlers Advent Calendar の8日目です。

・問題
最近は問題なくマルチバイト文字を含んだファイルを読み込めるようになった java.util.Properties ですが、昔はnative2ascii使ったりで面倒でした。
以下は、仕事で実際に遭遇したコードを元にしたものです。仕様的にはダメなわけですが、さて、実際に実行したら結果はどうなるでしょうか。

●プロパティファイル(Shift_JIS)

programmer=十把一絡げ

●プログラム

package com.bugworm.advent2016.puzzlers;

import java.io.InputStream;
import java.util.Properties;

public class MultiByteCharacterProperties{

    public static void main(String... args)throws Exception{
        Properties properties = new Properties();
        try(InputStream in = 
                ClassLoader.getSystemResourceAsStream("test.properties")){
            properties.load(in);
        }

        String value = properties.getProperty("programmer");
        String shift_jis = new String(value.getBytes("ISO8859-1"), "Shift_JIS");
        System.out.println("programmer は " + shift_jis);
    }
}

(1) 「programmer は 十把一絡げ」と出力される
(2) 実行時例外
(3) 「十把一絡げ」の部分が文字化けする






解答

(3) 「十把一絡げ」の部分が文字化けする

解説

この場合は文字化けするのですが、実は、たいていのケースではちゃんとマルチバイト文字を読み込めてしまいます。
しかし、上記の「十把一絡げ」はダメなのです。

「十把一絡げ」は、Shift_JISだと 「8F 5C 94 63 88 EA 97 8D 82 B0」となります。 
2バイト目の「5C」がくせものです。
単独で見るとこれは「\」になります。最初にPropertiesクラスが読み込む際にはShift_JISとして意識していませんので、これは実際に「\」として読みこまれます。
プロパティファイルでは「\」はエスケープ文字なので、「5C 94」部分がエスケープとみなされます。ただし「94」はエスケープとして特に意味がないのでそのまま「94」として解釈されます。
したがって読み込んだ結果を getBytes("ISO8859-1") すると「8F 94 63 88 EA 97 8D 82 B0」です。(5Cがなくなる)
なので、これをShift_JISとして文字列にすると、「8F 5C」が「諸」、3バイト目(元は4バイト目)の「63」は半角「c」なので、実行結果は「programmer は 諸c一絡げ」と表示されます。

ちなみに、 「十\把一絡げ」として、5Cを重ねてやれば、「8F 5C 5C 94 63 88 EA 97 8D 82 B0」となり、読み込み時に5Cが残る(5C 5Cをエスケープとみなして、5Cとして読み込まれる)ので、 結果的に「十把一絡げ」になります。
 

2015/11/28(土)、JJUG CCC 2015 Fallが開催されました。
今回初めてCfP通ったので、登壇してきました。

ネタがかなりマイナーなこと、タイムテーブル的にきしださん(@kis)の裏番組だったことから、まあせいぜい30人くらいだろ、と高を括っていたら満席近い感じで盛況でした。
来場いただいたみなさま、ありがとうございます。

スライドはScalaFX製なので、上記はスクショを並べてあるだけです。
元のスライドアプリを動かしてみたい方はこちらからどうぞ。
全部一個のjarにまとめてあるので、ダウンロードしてダブルクリックで動くはずです。Java8の新しめの環境用。(1.8.0_65で確認)
メイリオ前提で作っているので、Windows環境以外ではフォント関係イマイチかもしれません。

発表時はWebSocketのタイムアウトに悩まされて急いでしまったため、40~45分くらいの予定が35分程度で終わってしまいました。
やはり本番に近い環境でちゃんとリハーサルしないとダメですね。
とはいえ、関心を持ってくれた方が思ってた以上に多くてよかったです。
 

2015/11/28(土)に開催される、JJUG CCC 2015 Fallで登壇することになりました。
JDI (Java Debug Inteface)について話します。

参加登録はこちらから。 
https://jjug.doorkeeper.jp/events/33514 
本編は参加無料、懇親会はたぶん有料で、募集は上記とは別に行うようです。

タイムテーブル
http://www.java-users.jp/?page_id=2060
Room C+D の17:00からの枠です。

裏番組が強力なので過疎りそうですね...(苦笑)
 

IntelliJ IDEA の「New Project」で「Java Enterprise」> 「CDI:Contexts and Dependency Injection」を選んでプロジェクトを作成する。
このときライブラリとしてGlassFish4.1を選ぶと、javax.enterprise.context.SessionScoped とかが使えない。

原因を調べてみると、どうもGlassFishのjar構成が、4.0から4.1になる際に変更されているのが原因っぽい。
GlassFish4.0の場合
gf40cdi_e



























GlassFish4.1の場合
gf41cdi_e
 
















上記のスクショの通り、4.0ではjavax.enterprise.contextパッケージはweld-osgi-bundle.jarに含まれてたけど、4.1ではきれいさっぱりなくなっている。
で、4.1ではこのパッケージ、新しく入ったcdi-api.jar に含まれている。確かにjarの構成としてはこの方が正解な感じだけど、いきなり変えたから追従できてないのかな...。

JSFのManagedBeanとCDIのNamedを調べていて、どうにも腑に落ちない現象に出会った。
ほとんど同じ構成のearなのに、ManagedBeanがちゃんと認識されるケースとされないケースがある。

動かないearは以下のような最低限の構成。なお、タイトルにもある通り、サーバはGlassFish4.1。

META-INF/MANIFEST.MF
lib/myapp.jar
myapp.war

@ManagedBean と @javax.faces.bean.ViewScopedを指定したクラスがjarに入っていて、warにそれを使うxhtmlが入っている。
で、これをデプロイすると動かない。
Beanのクラス名が"JsfHello"で、
javax.el.PropertyNotFoundException: Target Unreachable, identifier 'jsfHello' resolved to null
なので、認識されてないっぽい。

でも、本格的に調べ始める前に暫定で作ってたやつは、ほとんど同じ構成で動いた。構成はこう。

META-INF/MANIFEST.MF
lib/sssss.jar
myweb.war

名前が雑だけど、同じようにjarとwarにBeanとxhtmlが入っている。
こっちは最初、faces-config.xml とか beans.xml とか入れていたり、application.xml を入れたりしていたので、その辺の違いかなーと思って上記の状態まで削除したんだけどやっぱり動く。
さて、何が影響してるのか、と考えてもさっぱりわからない。

で、昨日から今日にかけてダメ元でいろいろ試した結果、得られた結論は「jarとwarの名前が一緒だとManagedBeanが認識されない」
そんな馬鹿な、とも思ったんだけど、最初の構成で、jarの名前だけ変えてデプロイするとちゃんと動く。
個人的には「え!?そんなんありか?」って感じなんだけど、これって仕様なの?バグ?

★2015/5/1追記
さらに試したところ、
myapp.jar + app.war -> NG
app.jar + myapp.war -> OK
myapp.jar + my.war -> NG
my.jar + myapp.war -> OK
となったので、どうも、「jar名がwar名を含むとダメ」に見える。ほんとか?

このページのトップヘ