JSONICとは
JSONICは、Java用のシンプルかつ高機能なJSONエンコーダー/デコーダーライブラリです。
Java用のJSONライブラリは他にも複数ありますが、JSONICはRFC 4627に従った正式なJSON形式でのデコード/エンコードを行いながらも、プログラミング言語に依存する情報をJSON内に含めることなくPOJO(Plain Old Java Object)と自然な変換を行える点に特徴があります。
使い方も非常に簡単です。
import net.arnx.jsonic.JSON; // POJOをJSONに変換します String text = JSON.encode(new Hoge()); // JSONをPOJOに変換します Hoge hoge = JSON.decode(text, Hoge.class);
ダウンロード
JSONICの現時点での最新バージョンは0.9.7です。
ダウンロードはこちらからできます。なお、JSONICのビルド/実行には、Javaバージョン5.0以上が必要です。
使い方
基本的な使い方
通常の用途では、二つの静的メソッドencode/decodeだけ利用すれば事足ります。
■ encodeメソッド - POJOからJSONへの変換
POJOからJSONに変換する場合は、encodeを使います。デフォルトでは、空白などを含まない可読性の低いJSONが出力されますが、二番目の引数をtrueにすることで可読性の高いJSONが出力されるようになります(Pretty Printモード)。
// 変換対象のPOJOを準備 Hoge hoge = new Hoge(); hoge.number = 10; // public field hoge.setString("aaa"); // publid property hoge.setArray(new int[] {1, 2, 3}); // POJOをJSONに変換します。戻り値は {"number":10,"string":"aaa","array":[1,2,3]}となります String text = JSON.encode(hoge); // POJOを可読性の高いJSONに変換します。戻り値は次のような文字列になります // { // "number": 10, // "string": "aaa", // "array": [1, 2, 3] // } String text = JSON.encode(hoge, true);
POJOからJSONへの変換ルールは次の通りです。
変換元(Java) | 変換先(JSON) |
---|---|
Map | object |
Object(※1) | |
boolean[], short[], int[], long[], float[], double[], Object[] | array |
Collection | |
char[], CharSequence | string |
char, Character | |
TimeZone, Pattern, Type, Member | |
byte[] | string (BASE64) |
Locale | string (言語コード-国コード) |
byte, short, int, long, float, double | number(※2) |
Number | |
Date, Calendar | number (1970年からのミリ秒) |
Enum | number (ordinalにより変換) |
boolean, Boolean | true/false |
null | null |
(※2) NaN, Infinity, -Infinityに限りそれぞれ文字列"NaN", "Infinity", "-Infinity"に変換されます。
また、org.w3c.dom.Document/ElementからJSONへの変換もサポートしています。詳しくは「高度な使い方 - XMLからJSONへの変換」の項をご覧ください。
なお、JSONはobjectかarrayで始まる必要があるため、直接、intやStringのインスタンスをencodeメソッドの引数に指定した場合エラーとなります。
■ decodeメソッド - JSONからPOJOへの変換
JSONからPOJOに変換する場合は、decodeを使います。デフォルトでは、object, array, string, number, true/false, nullをHashMap, ArrayList, String, BigDecimal, Boolean, nullに変換しますが、二番目の引数に変換先のクラスを指定することでそのクラスのインスタンスにデータをセットして返してくれます。また、この処理はパブリック・フィールドやパブリック・プロパティ、配列やコレクションのデータを再帰的に辿り実行されますので、一般的なJavaBeansであればencodeして作られたJSONからの逆変換も可能です(Generics型にも対応しています)。
なお、JSON文字列が不正な場合にはJSONParseExceptionを投げ、型の変換に失敗した場合はJSONConvertExceptionを投げます(変換に失敗した際の動作を変更したい場合には、handleConversionFailureをオーバーライドします)。
// JSONをPOJOに変換します。戻り値としてサイズが4のArrayListが返されます List list = (List)JSON.decode("[1, \"a\", {}, false]"); // JSONをHogeクラスのインスタンスに変換します(キャストは不要です) Hoge hoge = JSON.decode("{\"number\": 10, \"array\": [1, 2, 3]}", Hoge.class);
JSONからPOJOへの変換ルールは次の通りです。
変換元(JSON) | 指定された型 | 変換先(Java) |
---|---|---|
object | なし, Object, Map | LinkedHashMap |
SortedMap | TreeMap | |
その他のMap派生型 | 指定された型 | |
その他の型 | 指定された型(パブリック・フィールド/プロパティに値をセット)(※3) | |
array | なし, Object, Collection, List | ArrayList |
Set | LinkedHashSet | |
SortedSet | TreeSet | |
その他のCollection派生型 | 指定された型 | |
short[], byte[], int[], long[], float[], double[] Object[]派生型 | 指定された型 | |
Locale | Locale(「言語コード」「国コード」「バリアントコード」からなる配列とみなし変換) | |
Map | インデックスの値をキーとするLinkedHashMap | |
SortedMap | インデックスの値をキーとするTreeMap | |
その他のMap派生型 | インデックスの値をキーとする指定された型のMap | |
string | なし, Object, CharSequence, String | String |
char | char(幅0の時は'\u0000', 2文字以上の時は1文字目) | |
Character | Character(幅0の時はnull, 2文字以上の時は1文字目) | |
Appendable | StringBuilder | |
その他のAppendable派生型 | 指定された型(値をappend) | |
Enum派生型 | 指定された型(値をEnum.valueOfで変換) | |
Date派生型, Calendar派生型 | 指定された型(文字列をDateFormatで変換) | |
byte, short, int, long, float, double, Byte, Short, Integer, Long, Float, Double, BigInteger, BigDecimal | 指定された型(文字列を数値とみなし変換) | |
byte[] | byte[](文字列をBASE64とみなし変換) | |
Locale | Locale(文字列を「言語コード」「国コード」「バリアントコード」が何らかの句読文字で区切られているとみなし変換) | |
Pattern | Pattern(文字列をパターンとみなし変換) | |
Class | Class(文字列をClass.forNameを使い変換) | |
TimeZone | TimeZone(文字列をTimeZone.getTimeZoneを使い変換) | |
boolean, Boolean | 指定された型("", "false", "no", "off", "NaN"の時false、その他の時true) | |
number | なし, Object, Number, BigDecimal | BigDecimal |
byte, short, int, long, float, double, Byte, Short, Integer, Long, Float, Double, BigInteger | 指定された型 | |
Date派生型, Calendar派生型 | 指定された型(数値を1970年からのミリ秒とみなし変換) | |
boolean, Boolean | 指定された型(0以外の時true、0の時false) | |
Enum派生型 | 指定された型(int値をEnum.ordinal()に従い変換) | |
true/false | なし, Object, Boolean | Boolean |
char, Character | 指定された型(trueの時'1'、falseの時'0') | |
float, double, Float, Double | 指定された型(trueの時1.0、falseの時NaN) | |
byte, short, int, long, Byte, Short, Integer, Long, BigInteger | 指定された型(trueの時1、falseの時0) | |
boolean | boolean | |
null | なし, Object | null |
byte, short, int, long, float, double | 0 | |
boolean | false | |
char | '\u0000' |
高度な使い方
JSONICでは、フレームワークなどでの利用を想定していくつかの便利な機能を用意しています。
- 継承による機能拡張
- Reader/InputStreamによるparse
- 総称型を指定してのdecode/parse
- 柔軟な読み込み
- 内部クラスを利用したエンコード/デコード
- 最大深度の設定
- XMLからJSONへの変換
■ 継承による機能拡張
JSONICは、フレームワークでの利用を考慮しインスタンスを生成したり、継承して拡張することができるように設計してあります。 なお、インスタンスを生成して利用する場合は、encode/decodeメソッドの代わりにformat/parseメソッドを利用します。
// インスタンスを生成します JSON json = new JSON(); // POJOをJSONに変換します(encodeと同じ機能) String text = json.format(new Hoge()); // POJOを可読性の高いJSONに変換します(Pretty Printモード) json.setPrettyPrint(true); String text = json.format(new Hoge()); // JSONをPOJOに変換します(decodeと同じ機能) Map map = (Map)json.parse(text); // JSONをHogeクラスのインスタンスに変換します(decodeと同じ機能) Hoge hoge = json.parse(text, Hoge.class);
DIコンテナなどを使いインスタンスを生成したり、独自の変換を追加するために次のようなオーバーライド可能なメソッドが用意されています。
JSON json = new JSON() { // 引数で指定された内容に従い変換します。例外が投げられた場合、 // JSONConvertExceptionでラップされ呼び出し元に通知されます。 protected <T> T convert(Object key, Object value, Class<? extends T> c, Type type) throws Exception { // JSON arrrayをjava.awt.Pointに変換する例です。 // さらに下の階層を変換する場合はconvertChildメソッドを呼び出してください。 if (c == Point.class && value instanceof List) { return (T)new Point( convertChild(0, ((List)value).get(0), int.class, int.class), convertChild(1, ((List)value).get(1), int.class, int.class) ); } return super.convert(key, value, c, type); } // 型cに対するインスタンスを生成します protected Object create(Class c) { return super.create(c); } // Class cにおいて、Member mを無視します(parse/formatの両方で有効です) protected boolean ignore(Class c, Member m) { // デフォルトでは、static/transparentのメンバおよびObjectクラスで宣言された // メンバの場合、trueを返します。 return super.ignore(c, m); } };
■ Reader/InputStreamによるparse
staticメソッドのJSON.decodeでは文字列からPOJOへの変換しか対応できませんが、parseメソッドの場合にはjava.io.Readerやjava.io.InputStreamからJSONデータを読み込むことができます。
// ReaderからのJSONの読み込み Hoge hoge = (new JSON()).parse(new FileReader("sample.json"), Hoge.class); // InputStreamからのJSONの読み込み(ファイルはUnicodeである必要があります(※4)) Hoge hoge = (new JSON()).parse(new FileInputStream("sample.json"), Hoge.class);
■ 総称型を指定してのdecode/parse
Java 5.0で追加された総称型は動的な情報としては利用できないため、decode/parseメソッドのClass型引数として直接指定することができません。その代わり、FieldやMethodを利用することで間接的に指定することができます。
public class JSONConfigLoader { private Map<String, Hoge> config; public Map load(Reader reader) throws JSONParseException, IOException { JSON json = new JSON(); // これはコンパイルエラー config = json.parse(reader, Map<String, Hoge>.class); // これならOK config = (Map<String, Hoge>)json.parse(reader, getClass().getField("config").getGenericType()); return config; } }
■ 柔軟な読み込み - 妥当でないJSONのデコード
JSONICはポステルの法則(送信するものに関しては厳密に、受信するものに関しては寛容に)に従い、妥当でないJSONであっても読み込みが可能なように作成されています。RFC 4627に規定された内容との相違点は以下の通りです。
- Cスタイルの複数行コメント(/**/)、C++スタイルの行コメント(//)およびシェルスクリプトスタイルの行コメント(#)をコメントとして認識します。
- ルート要素がobjectの場合、一番外側の'{'と'}'を省略することができます(入力文字列が空白文字列やコメントのみの場合も空のobjectとみなされます)。
- シングルクォートで囲まれた文字列やJavaリテラルを文字列として認識します(ただし、シングルクォートで囲まれた場合はjavascriptと異なりエスケープを処理しません)。
- objectやarrayにおいて各要素が改行で区切られているとき','を省略することができます。
- objectにおいてキーに対する値がobjectの場合、':'を省略することができます。
- string中で改行やタブなどの制御文字を有効な文字として認識します。
- objectやarrayにおいて値が省略された場合、nullとして認識します。
例えば、次のテキストはRFC 4627では無効ですが、JSONICでは読み込むことが可能です。
# database settings database { description: 'ms sql server connecter settings' user: sa password: xxxx // you need to replace your password. } /* equals to {"database": { "description": "ms sql server\n\tconnecter settings", "user": "sa", "password": "xxxx"}} */
※version 0.9.3まであった拡張モードは0.9.4以降廃止されました。
■ 内部クラスを利用したエンコード/デコード
JSONの設定ファイルを解析したいような場合は、内部クラスやパッケージ・デフォルトのクラスを利用したいことがあります。
JSONICでは、encode/decode/parse/formatの引数に指定されたクラスと同一パッケージの内部クラスや無名クラスを自動的にアクセス可能に変更します。
ただし、この場合に生成された内部クラスのインスタンスには包含するクラスのインスタンスがセットされていない状態になります。内部クラスから包含するクラスのインスタンスにアクセスしたい場合や引数に指定したクラス以外のコンテキストで実行したい場合は、setContextを利用して明示的に指定してください。
public class EnclosingClass { public void decode() { JSON json = new JSON(); InnerClass ic = json.parse("{\"a\": 100}", InnerClass.class); // このクラスのコンテキストで動作 System.out.println("ic.a = " + ic.a); // ic.a = 100 ic.accessEnclosingClass(); // 実行時にNullPointerExceptionが発生 json.setContext(this); // コンテキストを設定 ic = json.parse("{\"a\": 100}", InnerClass.class); ic.accessEnclosingClass(); // 正常に動作 } class InnerClass { public int a = 0; public void accessEnclosingClass() { decode(); } } }
■ setMaxDepth - 最大深度の設定
JSONICは、encode/format時に自分自身を戻すようなフィールドやプロパティ、配列を無視することで再帰による無限ループが発生することを防ぎます。 しかし、そのインスタンスにとって孫に当たるクラスが自分のインスタンスを返す場合にも再帰が発生してしまいます。JSONICでは、このような場合へ対処するため 単純に入れ子の深さに制限を設けています。なお、最大深度の設定はdecode/parse時にも有効ですので深すぎるデータの取得も避けることが可能となります。
この最大深度は、デフォルトでは32に設定されていますが変更することも可能です。
// 5階層以下の情報は取得しない json.setMaxDepth(5);
■ XMLからJSONへの変換
JSONICでは、org.w3c.dom.Document/ElementからJSONへの変換もサポートしています。 方法は、通常と同じようにencode/formatの引数にorg.w3c.dom.Document/Elementのインスタンスを設定するだけです。
Document doc = builder.parse(new File("sample.xml")); String xmljson = JSON.encode(doc);
例えば、下記のXMLの場合
<feed xmlns="http://www.w3.org/2005/Atom"> <title>Feed Title</title> <entry> <title>Entry Title</title> </entry> </feed>
次のようなJSONが生成されます(実際にはタグ間の空白文字もTextNodeとして出力されます)。
{ "tagName": "feed", "attributes": { "xmlns": "http://www.w3.org/2005/Atom" }, "childNodes": [ { "tagName": "title", "childNodes": [ "Feed Title" ] }, { "tagName": "entry", "childNodes": [ { "tagName": "title", "childNodes": [ "Entry Title" ] } ]} ] }
JSON Web Service Servlet
JSONICには、JSON-RPC1.0によるRPCモードとRestfull APIによるRESTモードの2 Way Web Service機能が用意されています。
※JSONRPCServletは0.9.6以降net.arnx.jsonic.web.WebServiceServletに置き換えられました。
■ 設定方法
JSON Web Service Servletの設定は簡単です。web.xmlにWebServiceServletを指定し、パスとClassのマッピングなどの設定を行うだけです。
<servlet> <servlet-name>json-ws</servlet-name> <servlet-class>net.arnx.jsonic.web.WebServiceServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value> { "debug": true, "encoding": "UTF-8", "mappings": { "/[package]/[class].[ext]": "sample.web.${package}.service.${class}Service", "/[class].[ext]": "sample.${class}Service" } } </param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>json-ws</servlet-name> <url-pattern>*.json</url-pattern> </servlet-mapping>
configで設定できる値は次の通りです。
キー | 値型 | 説明 |
---|---|---|
container | net.arnx.jsonic.web.Container | クラスのインスタンスを取得するためのコンテナを設定します。デフォルトは、net.arnx.jsonic.web.Containerです。 |
debug | Boolean | デバッグモードの有効/無効を切り替えます。デフォルトはfalseです。 |
encoding | java.lang.String | Request/Responseの文字エンコーディングを設定します。デフォルトはUTF-8です。 |
mappings | java.util.Map<String, String> | URLパスとクラスのマッピングを行います。 パス中の[name]で囲まれた部分はクラス名の${name}に置換されます(※5)。 なお、RESTモードの場合、利用されなかった変数はメッセージボディとして送られてきたJSON objectの値として設定されメソッドに引き渡されます(RPCモードの場合は設定されません)。 |
definitions | java.util.Map<String, Pattern> | mappings中の変数の定義を正規表現で設定します。設定されない場合は[^/]+が設定されたものと扱われます。 |
■ RPCモード
JSON-RPCは、JSONを使ったシンプルなRemote Procedure Callプロトコルです。JSON Web Service Servletでは、class変数の値が"rpc"であった場合、RPCモードとなります。
RPCモードでは、対象のパスに対し次のようなJSONをPOSTすることで、対象クラスのメソッドを呼び出すことができます(GET/PUT/DELETEは無効です)。paramsに指定された配列の値はメソッドの引数に指定された型に従い自動的に変換されます。なお、クラス名はUpperCamel、メソッド名はLowerCamelに自動的に変換されます。そして、実行後、戻り値がJSONに変換されクライアントに返されます。
{ "method": "[class].[method]", "params": [ arg1, arg2, ... ], "id": request_id }
例えば、mappingsに "/[package]/[class].[ext]": "boo.${package}.${class}Service" という指定があった場合、 /foo/woo/rpc.jsonというパスに次のJSONがPOSTすると、boo.foo.woo.CalcServiceクラスのint plus(int a, int b)のようなメソッドが呼び出されます。
{ "method": "calc.plus", "params": [1,2], "id": 1 }
この時、レスポンスボディとしては次のような結果が返されます。
{ "result": 3, "error": null, "id": 1 }
RPCモードでエラーが発生した場合にはHTTP Status Codeとレスポンスボディの両方でクライアントに通知されます。
エラー内容 | HTTP Status Code | JSON error |
---|---|---|
JSONリクエストがJSON-RPCのリクエストとして不正 | 400 Bad request | { "code": -32600, "message": "Invalid Request." } |
methodで指定したクラス/メソッドが見つからない(※6) | 404 Not found | { "code": -32601, "message": "Method not found." } |
paramsが不適切(※7) | 400 Bad request | { "code": -32602, "message": "Invalid params." } |
JSONの解析に失敗した | 400 Bad request | { "code": -32700, "message": "Parse error." } |
その他のエラー | 500 Internal Server Error | { "code": -32603, "message": "Internal error." or Exception.getMessage() } |
■ RESTモード
class変数の値が"rpc"以外の場合はRESTモードになります。RESTモードでは、GET/POST/PUT/DELETEの四つのHTTP Methodに従い対象となったクラスの次の名前のメソッドが呼び出されます(※6)。そして、実行後、戻り値がJSONに変換されクライアントに返されます(※7)。
HTTP Method | Java メソッド名 | 引数 |
---|---|---|
GET | find | URLのQueryを「.」で区切られた階層構造とみなし引数の型に従い変換し設定 |
POST | create | メッセージボディのJSONを引数の型に従い変換し設定 |
PUT | update | メッセージボディのJSONを引数の型に従い変換し設定 |
DELETE | delete | メッセージボディのJSONを引数の型に従い変換し設定 |
なお、メッセージボディがJSON objectの場合、その値はリクエストパラメータ、パス変数の順で上書きされます。JSON arrayの場合は上書きされずに最後尾に追加されます。
(※7) JSONはobjectかarrayより始まる必要があるため、それ以外の要素に変換される型の戻り値(例えば、boolean/int/Dateなど)の場合にはSC_NO_CONTENTが返されます。
RESTモードでエラーが発生した場合にはHTTP Status Codeにてクライアントに通知されます。
エラー内容 | HTTP Status Code |
---|---|
クラス/メソッドが見つからない(※8) | 404 Not found |
送信されたJSONの解析/変換に失敗した(※9) | 400 Bad request |
その他のエラー | 500 Internal Server Error |
■ JSONP
RESTモードでかつHTTP MethodがGETの場合、リクエストパラメータとしてcallback=Function名を指定することでJSONPによる返答を返すことができるようになります。
<script type="text/javascript" > function call(value) { alert(value); } </script> ... <script type="text/javascript" src="http://host/hoge.json?callback=call"></script>
■ DI Container対応
JSONRPCServletは、内部のコンテナを切り替えることで呼び出し対象のインスタンスを任意のDI Containerにて管理することが可能です。
<servlet> <servlet-name>JSON-WebService</servlet-name> <servlet-class>net.arnx.jsonic.web.WebServiceServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value> // "container": (net.arnx.jsonic.web.Containerを実装したクラス) // Seasar2対応Container "container": "net.arnx.jsonic.web.S2Container" ... </param-value> </init-param> </servlet>
JSONICでは、Seasar2に対応したContainerを標準添付しています。このContainerを利用すると、Seasar2上で管理されているコンポーネントをWebServiceとして利用することができるようになります。
ライセンス
JSONICは、Apache License, Version 2.0下で配布します。
なお、書くまでもないことですが自分のライブラリへの組み込みやその際にパッケージ名や処理の変更など行っていただいて一向に構いません。保障はありませんが、ライセンスの範囲内でご自由にお使いください。
バグ・要望の報告先
バグや要望などはJSONICプロジェクトサイトのトラッキング情報あるいはフォーラムまでご連絡ください。
リリースノート
2008/03/02 version 0.9.7
下記の機能追加・変更とバグ修正が行われています。
- decode/parseメソッドでClassとTypeの両方を指定する必要がなくなりました。
- setContextを指定しなくても引数に指定したObject/Classのコンテキストで動作するように変更しました。内部クラスの中で外側のメソッドなどを使う場合のみsetContextを利用ください。
- 将来的に別の用途に利用するため、コンストラクタでのコンテキストの指定は廃止しました。
- JSONConvertExceptionがJSONParseExceptionを継承するようにしました。
- MapのFormat時にkeyがStringでない場合ClassCastExceptionが発生し変換に失敗する問題を修正しました。
- Parse時にJSON arrayからMapへの変換に対応しました。
- Parse時にMapのキー値に対する変換が行われず常にStringに変換されていた問題を修正しました。
- Parse時にJSON arrayやJSON objectから文字列への変換を行わないように変更しました。
- Parse時にもsetMaxDepthで指定された階層以下のデータを無視するようになりました。
- 変換機能の拡張をconvertメソッドでも可能なように戻しました。
- handleConvertFailuerによる継続処理のカスタマイズはニーズが低そうなので廃止しました。変換機能の拡張にはconvertメソッドを使用してください。
- Parse時のJSON string, JSON numberから列挙型(Enum)への変換およびFormat時のEnumの変換に対応しました。
- 仕様変更の影響を緩和するためnet.arnx.jsonic.web.Containerをinterfaceからclassに変更し、S2ContainerがContainerを継承するようにしました。
2008/02/18 version 0.9.6
下記の機能追加・変更とバグ修正が行われています。
- Formatにてorg.w3c.dom.Document/ElementオブジェクトからJSONへの変換に対応しました。
- Parse/Format時にJavaBeansのプロパティの扱いを制御できるよう、ignoreメソッドを追加しました。
- 今まで変換機能を拡張する場合にはconvertを継承するようにしていましたが、handleConversionFailureの継承により行うよう変更しました。
- 変換に失敗した際には、デフォルトでJSONConvertExceptionを投げるよう変更しました。この動作は、handleConversionFailureをoverrideすることで変更できます。
- JSONParseExceptionをRuntimeExceptionを継承するように変更しました。
- JSONRPCServletを機能強化しnet.arnx.jsonic.web.WebServiceServletとして再リリースしました(Seasar2のサポートも追加されています)。
2008/01/28 version 0.9.5
下記の機能追加・変更とバグ修正が行われています。
- maxDepthのデフォルト値を32階層に変更しました。
- InputStreamによるParseを実装しました。文字コードは、UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LEから自動判別されます。
- Parse時にBOMが見つかった場合、無視するようにしました。
- Parse時の日付変換ロジックを見直し、一般的にコンピュータが取り扱う日付フォーマットに対応しました。
- Parse時にjava.sql.Date/java.sql.Time/java.sql.Timestamp/java.util.TimeZoneへの変換に対応しました。
- Parse時に値が指定されない場合、nullが指定されたものとして取り扱うよう変更しました(ただし、カンマの省略はできません)。
- Parse時に「'」で囲まれた文字列はエスケープ処理しないよう変更しました。
- ParseのJSON objectからJavaBeanへの変換時、名称が常にJavaBean規約に合うように変換していましたが、マッチに失敗した場合のみ変換するように変更しました。
- ParseのJSON objectからJavaBeanへの変換時、Javaの予約語にも対応できるよう末尾に「_」の付いたプロパティでもマッチできるよう変更しました。
- convertメソッドの引数にkey値を追加しました。
- 余り役に立たないためinvokeメソッドは廃止しました。
- 各種JavaScriptライブラリのJSON対応が整ってきたため、JavaScript版のJSON.encode/JSON.decodeを削除しました。
2008/01/25 version 0.9.4.1
パッケージミスと記載ミスの修正のみおこなわれています。
- net/arnx/jsonic/JSON.propertiesおよびnet/arnx/jsonic/JSON_ja.propertiesが配布用のjarファイルに含まれていない問題を修正しました。
- net.arnx.jsonic.JSONクラスのコメントがParseExceptionを出力すると書かれていましたが、正しくはJSONParseExceptionですので記載を修正しました。
2007/09/09 version 0.9.4
下記の機能追加とバグ修正が行われています。
- パーサは1クラスのみにするという自己規制を取り払いました。
- 拡張モードを廃止しparse時は常に柔軟な読み込みを可能とし、逆にformat時は厳格なJSONを出力するように変更しました。
- JSON objectのname項目が空白、ハイフン、アンダースコアで区切られている場合や先頭の文字が大文字になっている場合でも、Java Classのプロパティ名に変換できるように変更しました。
- JavaScript版のJSON.encode/JSON.decode機能を追加し、JSONRPCServlet経由で呼び出せるようにしました。
- JSONParseExceptionを独立したクラスとするとともに、decode/parseメソッドをJSONParseExceptionをthrowするようにメソッド定義を変更しました。
- Parseエラーを拾ったところで意味がないことに気づいたので、handleParseErrorを廃止しました。
- formatの引数にWriterを指定した場合flushがされずOutOfMemoryErrorが発生していたのを修正しました。
- メッセージをプロパティファイル化したことにより、英語と日本語にてエラーメッセージが出力できるようになりました。
- 順序を保存させるため、Map/Setのデフォルト変換先をHashMap/HashSetからLinkedHashMap/LinkedHashSetに変更しました。
2007/06/10 version 0.9.3
主に機能追加、メソッドの整理が変更点です。
- Readerを使ったparseに対応しました。
- java.lang.reflect.Type/Memberをのencodeに対応しました。
- java.lang.Classのencode/decodeに対応しました。
- java.util.regex.Patternのencode/decodeに対応しました。
- 真の内部クラス対応を行いました。setContextでEnclosingしているインスタンスを指定できます。
- JSONRPCServletの文字化け対応を行いました。
- JSONRPCServletでGETによるメソッド起動を可能にしました。なお、GETの場合にはJSONP機能が使えます。
- setMaxDepthによる階層の制限を越えた場合、エラーにするのではなくnullを設定するように変更しました。
- parseで利用するStringBuilderを再利用するように変更しました。
- handleParseExceptionの仕様を見直しました。
2007/06/03 version 0.9.2
下記のバグ修正と機能追加を行いました。
- 継承の比較順序が逆になっており、convert時に変換元が変換先のClassを継承している場合にnullに変換されていたバグを修正
- JSON-RPCの簡易実装を追加しました(JSONRPCServlet)
2007/06/02 version 0.9.1
下記のバグ修正と機能追加を行いました。
- charとCharacterでboolean値の変換規則に一貫性を持たせるように変更
innerpublic以外のclassであっても、引数に指定されたクラスと同一のパッケージ内であれば、encode/decodeするように対応
2007/05/27 version 0.9.0
今まで日記上でほそぼそと公開していたSimple JSON Class for Javaを仕様などを整理し名前も新たに0.9にリバージョンして公開(機能面での変更はありませんが、微妙に変換ルールや仕様を調整してあります)。