public abstract class hiJSON extends Object
JSON文字列のパーズには個別の型に割り当てる方式と汎用的な辞書・配列などに割り当てる方式が用意されています
型を定めてパーズする hiJSON.parseText(text).asClass(X.class);
文字列をパーズし既存の型にデータを得るにはparseText()で文字列を与えasClass()で対象となる型を指定します。
メソッドは連結式になっており、条件設定メソッドを連結し、最後にasClass()メソッドを置きます。
対象の型 data = hiJSON.parseText(文字列)
.asClass(対象の型.class)
パーズの基本
例えば次のデータ構造があり
// Sample.java
import java.util.*;
public class Sample {
public String firstName;
public String lastName;
public int age;
public static class Address {
public String streetAddress;
public String city;
public String state;
public int postalCode;
};
public Address address;
public static class PhoneNumber{
public String type;
public String number;
};
public LinkedHashSet<PhoneNumber> phoneNumbers;
};
これに対する次のJSONデータ表現がファイル"Sample_data.json"上にあるとき
{
"firstName":"John",
"lastName":"Smith",
"age":25,
"address":{
"streetAddress":"21 2nd Street",
"city":"New York",
"state":"NY",
"postalCode":10021
},
"phoneNumbers":[
{
"type":"home",
"number":"212 555-1234212 555-1234"
},
{
"type":"fax",
"number":"646 555-4567646 555-4567"
}
]
}
// http://www.oracle.com/technetwork/jp/articles/java/ja-topics/json-1973242-ja.htmlより
次の様にして解析しデータを取得することができます。
// Test01.java import otsu.hiNote.*; public class Test01{ public static void main(String[] args_){ try{ String _json_text= hiFile.readTextAll("Sample_data.json"); Sample _sample = hiJSON.parseText(_json_text) .asClass(Sample.class); System.out.println("Sample_data="+hiU.str(_sample,hiU.WITH_INDENT)); } catch(Exception _ex){ _ex.printStackTrace(System.err); System.exit(1); } System.exit(0); } }
次の結果が得られます。
Sample_data={
firstName="John",
lastName="Smith",
age=25,
address={
streetAddress="21 2nd Street",
city="New York",
state="NY",
postalCode=10021},
phoneNumbers=[
{
type="home",
number="212 555-1234212 555-1234"},
{
type="fax",
number="646 555-4567646 555-4567"}]}
階層化したクラス参照や、ジェネリック型LinkedHashSet<PhoneNumber>のデータも取得されていることが分かります。
メソッド名は何を引数にするかを明示した説明的な形式を採っていますが、より簡素な名前も用意してあります。
Sample _sample = hiJSON.parse(_json_text).as(Sample.class);
なお、上の出力結果は 拡張JSON記法 の範囲内なのでhiJSONで読み込むことができます。
補足:
hiFile.readTextAll("Sample_data.json")
はtextファイルをオープンし全内容を読み込みます。
hiU.str(_sample,hiU.WITH_INDENT)
はオブジェクトをクラス定義に従って内容表示するものです。
hiU.WITH_INDENTはインデント付きで表示する指定です。
Objectメンバ (envelope形式)
Objectメンバはパーズ結果はJSONノード(Dict,Array,String,Doble,Boolean)のツリー構造となります。
envelope型のクラスなどで型の定まらないデータをハンドリングする場合などに使用します。
public class Envelope {
long id; // 識別子
long date; // 送信日時
String from; // 送り主
String to; // 宛先
String type_info; // 内容型情報
Object content; // 内容
}
汎用オブジェクトは改めてクラスにパーズしなおすことができます。
テキストの代わりにObjectをパーズするにはparseText()の代わりにparseNode()を用います。
ジェネリック型 java標準のジェネリック型コンテナ
クラス内にMapやListなどのジェネリック型のメンバが置けます。
利用できるジェネリック型は次のものです。
| 要件 | 補足 | |
| 配列形式 | add(T1)メソッド | ArrayList,HashSet,TreeSetなど |
| 辞書形式 | put(T1,T2)メソッド | HashMap,LinkedHashMapなど |
先の例でもLinkedHashSetを用いています。
このメソッドを持てば利用者定義のジェネリック型コンテナも利用できます。
最外層が配列のデータ
最外層が配列
[ {"i":10,"s":"tokyo"},{"i":5,"s":"osaka"},{"i":10,"s":"kochi"} ]
のようなデータの場合次の方法でパーズ可能です。
後述の「クラスのメンバにパーズする」のようにクラスのメンバに取り込むことも可能です。
byte[]要素 Base64
JSONにはbyteというデータは有りません。
byteの配列はimageデータなどのバイナリデータ保持用に用いられます。
これをJSONにマッピングするにあたって数値の配列とすると煩雑で無用に長いデータとなってしまいます。
hiJSONでは3種のマッピングデータをパーズできます。
配列なら数値配列としてパーズし、文字列ならbase64または16進数として内容をデコードします。
hiJSON.str()またはhiU.str(xx,JSON_STYLE)によるエンコード時はhiU.str()
またはhiJSON.str()でbyte[]フィールドが@hiU.Base64アノーテーションで修飾されている場合base64エンコードします。
class MyClass {
String name;
@hiU.Base64 // 出力時は配列でなくbase64文字列にマッピングする
byte[] image_data;
}
利用者定義のジェネリック型
利用者定義のジェネリック型、例えば次のような形のクラスもパーズ可能です。
class Vals<T1,T2,T3>{
int i;
T1 val1;
T2 val2;
Map<T3,T1> map;
}
ただし、型パラメタが一個でadd<T>メソッドを持つ、あるいは型パラメタが2個でput<T1,T2>のメソッドを持つ場合、List,Mapに準ずるコンテナ型と見做されることに注意してください。
class MyList<T>{ // List型と見做し、addにより値設定
public void add(T){...}
}
class MyMap<T1,T2>{ // Map型と見做し、putにより値設定。
public void put(T1,T2){...}
}
派生型:baseクラスメンバを同レベルに展開
baseクラスのメンバを派生クラスと同レベルに展開したJSON文字列をパーズできます。
class Base {
int baseInfo;
}
class Derived extends Base {
String derivedInfo;
}
--- JSONデータ Base,Derivedのメンバを同一レベルに配置
{ "baseInfo":100 , "derivedInfo":"ABC" }
多型-1:base型フック
baseクラスを指定して、実型に応じ、オブジェクトを部分パーズする手続きを
hiJSON.with_class_from_node(baseクラス.class,(c,f,o)->{ return myFunc(c,f,o); })
で設定できます。
cにはbaseクラスの情報,fには上位のクラス内でのフィールド情報、oには構造解析されたJOSBオブジェクトが入っています。fはnullの場合もあります。
多型-2:@type仮メンバ
JSON文字列上にタイプを示すヒント情報フィールド"@type"を付加し、パーズ時は@typeに基づきObject生成する手法をとります。
{"id":1,"infoA":"abc"} // 本来のデータ
{"@type":"A","id":1,"infoA":"abc"} // @typeを追加したデータ."A"は型を表すヒント情報
@typeに関する指定はデータ定義上にアノーテーションの形で置きます。動作プログラム上では特に指定することなく自動で取り扱われます。
クラスのメンバにパーズする
クラスのメンバにパーズすることができます。
.asClass(Class)の代わりに.toMember(object,name)}を用います。
設定先となるオブジェクトとメンバ名を指定します。
staticメンバにパーズすることができます。
.asClass(Class)の代わりに.toStaticMember(Class,name)}を用います。
指定するのはクラスとメンバ名です。
パーズオプション
パーズの仕様はフラグとアノーテーションにより変更できます。
フラグ
パーズはwith_option(long),without_option(long)メソッドにより幾つかのオプション指定ができます。
| hiU.ONLY_PUBLIC hiU.PUBLIC_ONLY |
publicメンバのみパーズする |
| hiU.CHECK_UNKNOWN_FIELD | 存在しないフィールドをエラーとする。 |
| hiU.CHECK_UNSET_FIELD |
値が設定されなかったフィールドがあればエラーとする。 staticでないフィールドに値が設定されない場合エラーとします。 ただし、hiU.PUBLIC_ONLYが指定されている場合はprivateフィールドはチェックしません。 @hiU.Optionalアノーテーションで修飾されているフィールドもチェックされません。 |
| hiU.SINGLE_LINE_STRING | ダブルクオート、シングルクオートで囲む文字列が複数行に渡ることを禁止する。 |
次の補助設定メソッドがあります。
hiJSON.accept_fields(Class,String...) |
このフィールドは受け付ける(PUBLIC_ONLY無視) |
アノーテーション
対象クラス・フィールドで次のアノーテーションが有効です。
| @hiU.AcceptTypes(class...) | baseクラスで受け付ける多型派生のリスト 多型-2:@type仮メンバ参照 |
| @hiU.TypeHintField(名前) |
@type情報に載る名前 多型-2:@type仮メンバ参照 |
| @hiU.AltName(名前) |
フィールドの代替名 JSONの要素名が記号を含むなどで利用者クラスにマッピング不能な場合、その要素名を「代替名」と解釈することで、利用者クラスのフィールドにマッピングさせることが出来ます。 @hiU.AltNameは読み込み時の指定で出力時に別名を用いる場合な別途@hiU.PrintNameを指定します。
-- JSON
{
"name":"abc",
"value":15,
"$record-id":327
}
-- 利用者クラス
class MyClass {
String name;
int value;
@hiU.AltName("$record-id")
int record_id;
}
この指定があっても本来のフィールド名でのマッピングは有効です。 |
| @hiU.PrintName(名前) |
フィールドの別名出力 @hiU.PrintNameでフィールド出力時に用いる名前を指定します。@hiU.AltNameと一緒に指定することも可能です。
-- JSON
{
"name":"abc",
"value":15,
"$record-id":327
}
-- 利用者クラス
class MyClass {
String name;
int value;
@hiU.PrintName("$record-id")
@hiU.AltName("$record-id")
int record_id;
}
|
汎用型でパーズする
.asClass(Class)の代わりに.asNode()メソッドで、特定の型を指定せず辞書や配列などによる構造としてパーズしアクセスすることができます。
Object data = hiJSON.parseText(文字列)
.asNode()
要素アクセスの基本
asNodeで得られるノードツリーの各要素は次の形のObjectとなります。
| 辞書型 | : | LinkedHashMap<String,Object> |
| 配列型 | : | ArrayList<Object> |
| 文字列 | : | String |
| 数値 | : | Double,LongまたはBigDecimal |
| 真偽値 | : | Boolean |
数値はパーズ時に次のクラスが選択されます。これは内部表現であり、どのクラスであろうとも、利用者の型に最終的にはマップ可能です。
| 17桁までの10進数 | : Long |
| 15桁までの浮動小数でかつ指数が±15以内 | : Double |
| 上記以外 | : BigDecimal |
Doubleに指数範囲限定を加えたのはdoubleでは"123.45e19"が必要精度を持って解析できないからです。
hiJSON.ProbeでObject内容を探索する
asNodeで得られたObject内容にアクセスするためにhiJSON.Probeクラスが用意されています。
型を定めてパーズする/パーズの基本と同じデータを汎用型でパーズし要素へアクセスする例を示します。
データは次のものとします。
{
"firstName":"John",
"lastName":"Smith",
"age":25,
"address":{
"streetAddress":"21 2nd Street",
"city":"New York",
"state":"NY",
"postalCode":10021
},
"phoneNumbers":[
{
"type":"home",
"number":"212 555-1234212 555-1234"
},
{
"type":"fax",
"number":"646 555-4567646 555-4567"
}
]
}
データは
階層化したデータはprobe.to(名前)で位置を変えることが出来ます。
probe.to(名前)で新しい位置の新しいProbeが得られます。
probe.get()でカレント位置の要素、
probe.get(名前)で指定位置の要素を得ることができます。
// Test06.java
import otsu.hiNote.*;
public class Test06{
public static void main(String[] args_){
try{
String _json_text= hiFile.readTextAll("Sample_data.json");
Object _sample = hiJSON.parseText(_json_text)
.asNode();
System.out.println("Sample_data="+hiU.str(_sample,hiU.WITH_INDENT
|hiU.WITH_TYPE));
System.out.println("---");
//
String _lastName = hiJSON.probe(_node).getString("lastName");
ps.println("lastName="+_lastName);
int _age = hiJSON.probe(_node).getInt("age");
ps.println("age="+_age);
long _postalCode = hiJSON.probe(_node).to("address")
.to("postalCode")
.getLong();
ps.println("postalCode="+_postalCode);
// Probe内アクセス
hiJSON.Probe _address= hiJSON.probe(_node).at("address");
ps.println("in address");
ps.println(" streetAddress="+_address.get("streetAddress"));
ps.println(" city=" +_address.get("city"));
ps.println(" state=" +_address.get("state"));
ps.println(" postalCode=" +_address.get("postalCode"));
// ここではget()で型を特定しないObjectを得て表示している。stateはString,postalCodeはDouble
}
catch(Exception _ex){
_ex.printStackTrace(System.err);
System.exit(1);
}
System.exit(0);
}
}
probe.to(名前)は当該Probeの位置が変更になりますが、
probe.at(名前)では新たなProbeが生成され元のProbeに影響を与えません。
繰り返しや検索を行いラムダ式で処理を行うことができます。
例を載せます。
解析補助メソッド
hiJSON.ProbeにはObjectの値を取得するstaticメソッドも用意されています。
Object _node_obj = hiJSON.parse(_json_text).asNode(); hiJSON.Probe _probe= hiJSON.probe(); // Map<String,Object> _map = hiJSON.Probe.asMap(_node_obj); // Mapとして解釈 List<Object> _list = hiJSON.Probe.asList(_node_obj); // Listとして解釈 // 数値系はObjectはDoubleまたはLongですがintやlong,byteなどと解釈する機能があります。 int _i = hiJSON.Probe.asInt(_node_obj); // intと解釈 long _lng = hiJSON.Probe.asLong(_node_obj); // longと解釈 byte _b = hiJSON.Probe.asByte(_node_obj); // byteと解釈 //... // byte配列にデータを得る Doubleの配列、16進文字列、base64文字列からbyteの配列を得る byte[] _bytes= hiJSON.Probe.asByteArray(_node_obj);
汎用型のノードを利用者型に割り当て直す
汎用型のデータはparseNode(xx).asClass(xx)により利用者型に割り当て直すことが出来ます。
hiJSON以外のツールで作られた汎用型データにはhiJSONで取り扱えないものがある可能性があります。
これらに関しては.with_class_from_node()を用いて変換メソッドを設定する必要があります。
数値型の場合はBicDecimalへの変換法を設定します。
拡張JSON記法 コメントなど
コメントなどのJSON記法の拡張を行ってあります。
JSON表記にはjavascript表記との関連により大きな揺れが有ります。
プログラム同士でのやり取りには問題では有りませんが、人が記述する場合、大きな問題となります。
hiJSONは表記の揺れに対処しています。
コメントが書けるので設定記述などにも利用できます。
コメント
コメントは//から行末までと/*から*/までです。互いに相手をコメントアウトします。
コメントが置けますので設定ファイルの表記としても用いることが可能です。
// minim.service.json 行端までコメントアウト
{
"Unit":{
"Description":"minim DLNA server"
},
"Service":{
/* ブロックコメント
"StartLimitBurst":0,
"WorkingDirectory":"/usr/src/minimServer/minimserver/bin/"
*/
"ExecStart":"/usr/src/minimServer/minimserver/bin/startc",
"Restart" : "always",
"Type" : "simple"
},
"Install":{
"WantedBy":"multi-user.target"
}
}
引用符
引用符としてダブルクオート("),シングルクオート('),逆クオート(`)が許されます。
数字、特殊記号以外で始まり特殊記号や空白を含まない文字列は引用符を省略できます。
特殊記号とは ;:,[]{}()/= です。
// minim.service.json
{
Unit:{ // 名前の引用符省略
"Description":'minim DLNA server' // 値シングルクオート
},
'Service':{ // 名前シングルクオート
StartLimitBurst:0,
WorkingDirectory:'/usr/src/minimServer/minimserver/bin/',
ExecStart:"/usr/src/minimServer/minimserver/bin/startc",
Restart : always, // 値の引用符省略
Type : `simple` // 値逆クオート
code : UTF-8 // ハイフンも引用符無の文字列に含めることができる
$date : 1970-01-01T09 // $などのも可
},
`Install`:{ // 名前逆クオート
"WantedBy":"multi-user.target"
}
}
各引用符ブロックの中では異なる引用符はエスケープ無で使用できます。例えばシングルクオートで囲まれた文字列の中ではダブルクオートはエスケープ不要です。
カンマ、セミコロン
カンマは省略できます。
リストの最後にカンマがあってもエラーとはなりません。
カンマの代わりにセミコロンを置くことも可能です
{
work_dir:'/var/www/test01' // カンマなし
exec :test_service,
log :'/var/log/test01.log'
lang :JP; // セミコロン
char :utf-8, // 最後に不要なカンマあり
}
コロン(:)の代わりにイクオール(=)を使う
コロン(:)の代わりにイクオール(=)を用いることが出来ます。
// minim.service.json
{
Unit={
Description='minim DLNA server'
},
Service={
StartLimitBurst=0,
WorkingDirectory='/usr/src/minimServer/minimserver/bin/',
ExecStart='/usr/src/minimServer/minimserver/bin/startc',
Restart = always,
Type = simple
},
Install={
WantedBy='multi-user.target'
}
}
文字列の改行、文字列の連結
長い文字列は行分割できます。
{
site1:"http://k-hiura.cocolog-nifty.com/blog/\
2007/11/post_5f3a.html", // 連結されます
text:`象は
鼻が
長い`, // 3行になります
site2:"https://www.youtube.com/"
+"watch?v=4ll_6RimCuM" // 連結されます
}
なおダブルクオートでもシングルクオートでも標準では逆クオートと同じ扱いになります。
with_option(hiU.SINGLE_LINE_STRING)指定をすると逆スラッシュ無での行分割をエラーにすることが出来ます。
逆クオートの場合with_option(hiU.SINGLE_LINE_STRING)指定は無効です。
行端の逆スラッシュは後ろに空白文字が入っても行端と見做されます。
文字列を囲む引用符と異なる引用符はエスケープ不要ですので次のよう記述を分断し+で結合することが出来ます。
表したい文字列 HAL said, "It's puzzling." JSON表記 'HAL said, "' + "It's puzzling." + '"'
[]を用いないjsonシーケンス(asClassList,asNodeList)
asClassList(Class),asNodeList()では[]を持たない構造の並びもパーズ可能です。
// 例えば
{id:'001',name:'田中',age:51}
{id:'002',name:'鈴木',age:32}
{id:'003',name:'山田',age:63}
{id:'004',name:'佐藤',age:40}
を読み取ることが出来ます。
{}を用いないid付きオブジェクト(asClassValues)
javascriptの変数定義の様に名前付きで値を記述できます。
セミコロンがあっても構いません。
名前の前にあるキーワード'var'は無視されます。
val ={ a:1,b:2 }
取得にはasClassValues()を用います。 値はLinkedHashMap<String,T>の形となります。
関数形式の記述/正規表現記述/新しい型の導入
JSONから逸脱した関数型の記述や正規表現記述が要求されるシステムがあります。
// 関数型
{ "_id" : ObjectId("5eeaf008e2f99f1abfc48b16"),
"timeStamp" : ISODate("2020-06-18T01:54:21.000Z") }
// 正規表現
{famiryName:/sky$/}
この2つの書式に対応しました。
このシステムではノード要素として標準の辞書、配列、文字列、数値などの他
を持ちます。
hiJSONではラムダ式を用いて、新たなnode型を導入することができます。
| 目的 | メソッド |
| 関数型記述からnodeオブジェクトを得る | with_functionStyle_parse |
| 正規表現型記述からnodeオブジェクトを得る | with_regex_node_parse .str_class_disp |
| 辞書型記述からnodeオブジェクトを得る | with_dict_parse |
| 利用者クラスを追加型nodeなどから得る | with_class_from_node |
| 追加型nodeから文字列を得る | str_format() .str_class_disp |
プログラム例を示します。
JSON表記を得る
利用者データからJSON表記を得るには
hiJSON.str(Object)
を用います。
データ構造からJSON表記を得る
基本は次の形です。
SampleX _sampleX=...;
String _json_text= hiJSON.str(_sampleX);
または
String _json_text= hiU.str(_sampleX,hiU.JSON_STYLE);
次のオプションを付加することができます。
| hiU.ONLY_PUBLIC | PUBLIC要素のみ表示する |
| hiU.WITH_INDENT | インデント付きで表示する この指定は人間が見るために行うもので、通信用などの場合は付ける必要はありません。 本クラスのサンプル出力では見やすさのため多くの場合WITH_INDENTを使用しています。 |
| hiU.EVEN_PRIVATE_STATIC | private staticフィールドも表示する |
| hiU.EVEN_FINAL_STATIC | final staticフィールドも表示する ただしhiJSONによるパーズ時はfinal staticフィールドは無視されます |
次の様な形です。
String _json_text= hiJSON.str(_sampleX,hiU.ONLY_PUBLIC|hiU.WITH_INDENT)
hiFieldFormatの機能による細かな設定
表示機能はhiFieldFormatクラスが請け負っています。
str_format()メソッドを用いればhiFieldFormatが得られ、hiFieldFormatの機能で細かな設定が出来ます。
次のオプションを無効にすることができます。
| hiU.USE_AT_FIELD | @type,@classフィールドを付加しない。 hiU@TypeHintFieldアノーテーションを無視します。 特定クラスに関して無視する場合はstr_ignore_annotations()を用いてください。 |
フィールドを次のアノーテーションで修飾することができます。
| hiU.@AsBase64 | byte[]をBase64で表示する |
| hiU.@AsHex | byte[]を先頭に'#'のついた16進数で表示する |
| hiU.@UnPrintable | このフィールドは表示しない |
| hiU.@Printable | このフィールドを表示する |
表示用のアノーテーションの無効化はstc_xxxを使い次のように行います。
hiJSON.str_format()
.str_ignore_annotations(hiU.AsBase64.class,hiU.UnPrintable.class)//複数可
.for_classes(X.class,Y.class) //複数可
.str(_y);
hiJSON.str()の表示用のオプションもstr_format()で得るhiFieldFormatの機能で設定可能です。
hiJSON.str_format()
.str_option(hiU.ONLY_PUBLIC|hiU.WITH_INDENT)
.str(_sampleX);
は
hiJSON.str(_sampleX,hiU.ONLY_PUBLIC|hiU.WITH_INDENT)
と同じ
JSON文字列を直接書く
hiJSONでパーズする場合以外で、標準のJSON文字列をJavaのStringとして与える場合、引用符の表記が煩わしいものとなります。
(hiJSONでパーズする場合はシングルクオートが使えますので引用符に関わる煩わしさは余り有りません)
そこでシングルクオートをダブルクオートに変換する単純なメソッドを用意しました。
もちろん万能ではありませんが、とても見やすくなります。
String _json_text=hiJSON.literal("[{'i':1,'s':'abc'},{'i':2,'s':'xyz'}]"); 次の記述と同等です⇒ String _json_txet="[{\"i\":1,\"s\":\"abc\"},{\"i\":2,\"s\":\"xyz\"}]";
複数行をまとめる機能も持ちますので次のような記述ができます。
_json_text=hiJSON.literal(
"{",
" 'firstName':'John',",
" 'lastName':'Smith',",
" 'age':25,",
" 'address':{",
" 'streetAddress':'21 2nd Street',",
" 'city':'New York',",
" 'state':'NY',",
" 'postalCode':10021",
" },",
" 'phoneNumbers':[",
" {",
" 'type':'home',",
" 'number':'212 555-1234212 555-1234'",
" },",
" {",
" 'type':'fax',",
" 'number':'646 555-4567646 555-4567'",
" }",
" ]",
" }"
);
hiJSON.literal_lines()を使えば各行の間に"\n"が置かれます。
API
| 修飾子とタイプ | クラスと説明 |
|---|---|
static class |
hiJSON.Engine
型割り当てエンジン.
|
static class |
hiJSON.Numeric |
static class |
hiJSON.Probe
オブジェクトツリー探査機.
|
static class |
hiJSON.TX<TT>
型情報を保持するベースクラス
このクラスに型情報を与えたものの無名クラスのインスタンスを用います。
|
| 修飾子とタイプ | フィールドと説明 |
|---|---|
static int |
ANNOT_AcceptTypes |
static int |
ANNOT_TypeHintField |
static int |
NEW_ID_MAX
parseでidの衝突を許す個数
|
static char |
null_char
null文字
|
| 修飾子とタイプ | メソッドと説明 |
|---|---|
static hiJSON.Engine |
accept_fields(Class<?> class_,
String... fieldNames_)
特定フィールドのパーズを可能とする.
hiU.PUBLIC_ONLY指定時にpublic以外のメンバを許します。
|
static byte[] |
asByteArray(Object obj_)
オブジェクトをbyte配列として解釈する.
|
static hiJSON.Engine |
default_engine()
デフォルトの解析エンジンを得る.
|
static hiJSON.Engine |
engine()
解析エンジンを生成する.
|
static String |
literal_lines(String... texts_)
JSON文字列リテラルを簡易表記する(行保持).
|
static String |
literal(String... texts_)
JSON文字列リテラルを簡易表記する.
|
static hiJSON.Engine |
parse(ArrayList<String> json_text_)
パーズ対象の文字列リストを指定する.
|
static hiJSON.Engine |
parse(File file_)
パーズ対象の読み込み元ファイルを指定する.
|
static hiJSON.Engine |
parse(Reader reader_)
パーズ対象の読み込み元を指定する.
|
static hiJSON.Engine |
parse(String json_text_)
パーズ対象の文字列を指定する.
|
static hiJSON.Engine |
parse(String[] json_text_)
パーズ対象の文字列配列を指定する.
|
static hiJSON.Engine |
parseFile(File file_)
パーズ対象の読み込み元ファイルを指定する.
|
static hiJSON.Engine |
parseFile(String fileName_)
パーズ対象の読み込み元ファイルを指定する.
|
static hiJSON.Engine |
parseNode(Object json_obj_)
パーズ対象の構造解析済みJSONノードを指定する.
|
static hiJSON.Engine |
parseReader(Reader reader_)
パーズ対象の読み込み元を指定する.
|
static hiJSON.Engine |
parseText(ArrayList<String> json_text_)
パーズ対象の文字列リストを指定する.
|
static hiJSON.Engine |
parseText(String json_text_)
パーズ対象の文字列を指定する.
|
static hiJSON.Engine |
parseText(String[] json_text_)
パーズ対象の文字列配列を指定する.
|
static hiJSON.Probe |
probe(Object node_)
指定オブジェクトの探査用Probeを作る
|
ArrayList<String> |
reshape(ArrayList<String> json_text_,
long option_)
標準JSON形に整形する.
|
String |
reshape(String json_text_)
標準JSON形に整形する.
|
String[] |
reshape(String[] json_text_)
標準JSON形に整形する.
|
static hiFieldFormat |
str_default()
フォーマットのデフォルトを得る.
|
static hiFieldFormat |
str_format()
デフォルトのフォーマットを得る
影響を残しません
|
static String |
str(Object obj_)
JSON表示を得る
|
static String |
str(Object obj_,
long additional_option)
JSON文字列を得る.
|
static hiJSON.Engine |
with_atType_parse(hiU.QuadrFunctionEx<Class<?>,hiField,String,Object,Object,Exception> check_func_)
@typeパーズ手続き設定.
|
static hiJSON.Engine |
with_class_from_node(Class<?> class_,
hiU.TriFunctionEx<Class<?>,hiField,Object,Object,Exception> check_func_)
部分パーズ手続きの登録.
|
static hiJSON.Engine |
with_dict_parse(String key_,
hiU.TriFunctionEx<String,Object,Map<String,Object>,Object,Exception> check_func_)
辞書型データをノードに置き換える手続きを設定.
|
static hiJSON.Engine |
with_functionStyle_parse(String funcName_,
hiU.BiFunctionEx<String,ArrayList<Object>,Object,Exception> check_func_)
関数形式配列解析手続き設定.
|
static hiJSON.Engine |
with_option(long option_)
パーズオプションを指定する.
|
static hiJSON.Engine |
without_option(long option_)
パーズオプションを無効にする.
|
public static int ANNOT_TypeHintField
public static int ANNOT_AcceptTypes
public static int NEW_ID_MAX
public static final char null_char
public static hiFieldFormat str_default()
public static String str(Object obj_, long additional_option)
JSON文字列を得ます。
次のオプションを付加することができます。
hiU.WITH_INDENT |
: | インデント付きで出力する |
hiU.ONLY_PUBLIC |
: | パブリックメンバのみ出力する |
obj_ - JSON形式にしたいオブジェクトadditional_option - 追加オプションhiU.WITH_INDENT hiU.WITH_INDENT),
(hiU.WITH_INDENT hiU.WITH_INDENT)public static String literal(String... texts_)
シングルクオートをダブルクオートに置き換えます。
Javaの文字列リテラルにJSON記述を行う場合ダブルクオートのエスケープが煩雑になります。
String _json_txet="[{\"i\":1,\"s\":\"abc\"},{\"i\":2,\"s\":\"xyz\"}]";
が次のように書ける
String _json_text=hiJSON.literal("[{'i':1,'s':'abc'},{'i':2,'s':'xyz'}]");
複数行を連結する機能がありますので次のような記述も可能です。 行と行の間には区切り文字の追加はされません。
_json_text=hiJSON.literal(
"{",
" 'firstName':'John',",
" 'lastName':'Smith',",
" 'age':25,",
" 'address':{",
" 'streetAddress':'21 2nd Street',",
" 'city':'New York',",
" 'state':'NY',",
" 'postalCode':10021",
" },",
" 'phoneNumbers':[",
" {",
" 'type':'home',",
" 'number':'212 555-1234212 555-1234'",
" },",
" {",
" 'type':'fax',",
" 'number':'646 555-4567646 555-4567'",
" }",
" ]",
" }"
);
texts_ - 文字列public static String literal_lines(String... texts_)
JSON文字列を得ます。
複数からなる場合、改行を挟んで連結されます。
texts_ - 文字列public static hiJSON.Probe probe(Object node_)
node_ - エントリーとなるnoオブジェクトpublic static byte[] asByteArray(Object obj_)
オブジェクトが配列の場合数値の配列として解釈し、byteの配列にします。
オブジェクトが文字列の場合先頭文字が'#'なら16進数として解釈し、それ以外ならBase64として解釈しbyteの配列とします。
obj_ - jsonオブジェクトpublic static final hiFieldFormat str_format()
影響を残しません
public static hiJSON.Engine parseText(String json_text_)
パーズ対象を指定します。パーズは.asClass(型)で行います。
// class X{...}
String _json_text="....";
X = hiJSON.parseText(_json_text)
.asClass(X.class);
json_text_ - パーズする文字列public static hiJSON.Engine parseText(ArrayList<String> json_text_)
パーズ対象を指定します。パーズは.asClass(型)で行います。
// class X{...}
String _json_text="....";
X = hiJSON.parseText(_json_text)
.asClass(X.class);
json_text_ - パーズする文字列public static hiJSON.Engine parseText(String[] json_text_)
パーズ対象を指定します。パーズは.asClass(型)で行います。
// class X{...}
String _json_text="....";
X = hiJSON.parseText(_json_text)
.asClass(X.class);
json_text_ - パーズする文字列public static final hiJSON.Engine parse(String json_text_)
json_text_ - パーズする文字列public static final hiJSON.Engine parse(ArrayList<String> json_text_)
json_text_ - パーズする文字列public static final hiJSON.Engine parse(String[] json_text_)
json_text_ - パーズする文字列public String reshape(String json_text_)
例えば次の様な変換がなされます。
hiJSON.reshape("{$or:[{name:'X'},{name:'Z'}]}");
⇒
"{ \"$or\":[{\"name\":\"X\"},{\"name\":\"Z\"}]}"
json_text_ - 拡張JSON形式public ArrayList<String> reshape(ArrayList<String> json_text_, long option_)
例えば次の様な変換がなされます。
ArrayList<String> _json=new ArrayList<>();
_json.add("{$or:[ // comment");
_json.add(" {name:'X'},");
_json.add(" /{@litera;l *} コメント {@litera;l *}/ {name:'Z'},");
_json.add(" ]}");
hiJSON.reshape(_json,hiU.WITH_INDENT);
⇒
"{ \"$or\":["
"{\"name\":\"X\"},"
"{\"name\":\"Z\"}]}"
json_text_ - 拡張JSON形式public String[] reshape(String[] json_text_)
例えば次の様な変換がなされます。
String _json[]={
"{$or:[ // comment",
" {name:'X'},",
" /{@litera;l *} コメント {@litera;l *}/ {name:'Z'},",
" ]}";
hiJSON.reshape(_json,hiU.WITH_INDENT);
⇒
{"{ \"$or\":[",
"{\"name\":\"X\"},",
"{\"name\":\"Z\"}]}"}
json_text_ - 拡張JSON形式public static hiJSON.Engine parseNode(Object json_obj_)
.asNode()で得たJSONノードObjectを解析し直します。
JSONノードは次のいずれかの型であり、Map,ArraListyでツリーを構成します。
次の例では一旦Object objとして解析されたメンバを改めてX,Yとして解析し直しています。
結果は読み込んだ直後とメンバの解析をしなおした後を表示しています。
// Test10.java
import otsu.hiNote.*;
import java.util.*;
public class Test10{
static class X{
int i;
String s;
}
static class Y{
double d1;
double d2;
}
static class Z{
String type;
Object obj;
void check(){
if( "X".equals(type) ){
obj= hiJSON.parseNode(obj)
.asClass(X.class); // 構造ObjectをXとしてパーズ
}
else if( "Y".equals(type) ){
obj= hiJSON.parseNode(obj)
.asClass(Y.class); // 構造ObjectをYとしてパーズしなおす
}
type= "-"+type; // 解析済み
}
}
public static void main(String[] args_){
try{
String _json_text= hiJSON.literal("["
," {'type':'X','obj':{'i':1,'s':'ABC'}}"
," ,{'type':'Y','obj':{'d1':1.3,'d2':1.7}}"
," ,{'type':'X','obj':{'i':13,'s':'XYZ'}}"
,"]");
ArrayList<Z> _zs= hiJSON.parseText(_json_text)
.asClassList(Z.class);
System.out.println("read"+hiU.str(_zs,hiU.WITH_INDENT|hiU.WITH_TYPE));
for(Z _z:_zs) _z.check();// 内部で型を割り当て直す
System.out.println("assigned="+hiU.str(_zs,hiU.WITH_INDENT|hiU.WITH_TYPE));
}
catch(Exception _ex){
_ex.printStackTrace(System.err);
System.exit(1);
}
System.exit(0);
}
}
--- 出力
read(ArrayList)[
(Test10$Z){
type=(String)"X",
obj=(hiJSON$Dict){
(String)"i"=(Double)1.0,
(String)"s"=(String)"ABC"}},
(Test10$Z){
type=(String)"Y",
obj=(hiJSON$Dict){
(String)"d1"=(Double)1.3,
(String)"d2"=(Double)1.7}},
(Test10$Z){
type=(String)"X",
obj=(hiJSON$Dict){
(String)"i"=(Double)13.0,
(String)"s"=(String)"XYZ"}}]
assigned=(ArrayList)[
(Test10$Z){
type=(String)"-X",
obj=(Test10$X){
i=(int)1,
s=(String)"ABC"}},
(Test10$Z){
type=(String)"-Y",
obj=(Test10$Y){
d1=(double)1.3,
d2=(double)1.7}},
(Test10$Z){
type=(String)"-X",
obj=(Test10$X){
i=(int)13,
s=(String)"XYZ"}}]
json_obj_ - JSON構造オブジェクトpublic static hiJSON.Engine parseReader(Reader reader_)
reader_ - Readerpublic static hiJSON.Engine parse(Reader reader_)
reader_ - Readerpublic static hiJSON.Engine parseFile(String fileName_)
fileName_ - ファイル名public static hiJSON.Engine parseFile(File file_)
file_ - ファイルpublic static final hiJSON.Engine parse(File file_)
file_ - パーズするFilepublic static hiJSON.Engine with_option(long option_)
パーズに関するオプションを指定します。
パーズオプション参照option_ - オプションpublic static hiJSON.Engine accept_fields(Class<?> class_, String... fieldNames_)
class_ - クラスfieldNames_ - フィールド名public static hiJSON.Engine without_option(long option_)
パーズオプションを無効にします。
option_ - オプションpublic static hiJSON.Engine with_class_from_node(Class<?> class_, hiU.TriFunctionEx<Class<?>,hiField,Object,Object,Exception> check_func_)
パーズ時に特定の型のjson汎用オブジェクトを部分パーズする手続きを登録します。
ラムダ式になっており次のような形での使い方となります。
式の戻り値が解析された型のインスタンスとして使われます。nullを返すと標準の手続きで型インスタンスを得ます。
hiJSON.with_class_from_node(チェックしたいクラス.class
(c,f,o)->{ 手続き c:クラス,f:フィールド,o:オブジェクト })
parseText(),asClass()と連結して使います。実例を示します。
// Test13.java
import otsu.hiNote.*;
import java.util.*;
public class Test13{
static abstract class Base { // Abstact
int id;
}
static class A extends Base { // 派生
String infoA;
}
static class B extends Base { // 派生
Double infoB;
}
static class Infos {
A a; // 単純派生
ArrayList<Base> list; // 多型 ここにAまたはBが入る
}
static Object check(Class<?> c_,hiField f_,Object o_){
if( hiJSON.hasMember(o_,"infoA") ){// infoAが有ればAと解釈
return hiJSON.parseNode(o_).asClass(A.class);
}
if( hiJSON.hasMember(o_,"infoB")){// infoBが有ればBと解釈
return hiJSON.parseNode(o_).asClass(B.class);
}
return null;
}
public static void main(String[] args_){
try{
String _json_text= hiJSON.literal_lines("{"
,"'a' :{'id':1,'infoA':'abc'},"
,"'list':["
," {'id':2,'infoA':'aaa'},"
," {'id':3,'infoB':10.5},"
," {'id':4,'infoA':'xyz'}"
," ]"
,"}"
);
System.out.println("json-in="+_json_text);
Infos _read= hiJSON
.parseText(_json_text)
.with_class_from_node(Base.class,(c,f,o)->{return check(c,f,o);})
.asClass(Infos.class);
System.out.println("read-done="
+hiU.str(_read,hiU.WITH_INDENT|hiU.WITH_TYPE));
}
catch(Exception _ex){
_ex.printStackTrace(System.err);
System.exit(1);
}
System.exit(0);
}
}
class_ - チェックするクラスcheck_func_ - ラムダ式public static hiJSON.Engine with_atType_parse(hiU.QuadrFunctionEx<Class<?>,hiField,String,Object,Object,Exception> check_func_)
@typeフィールドを持つクラスで@type情報による自動割り当てができなかったものに対して呼ばれる
例えば次のようなデータクラスがありBaseの多型管理をしている状態でA,BはAcceptTypesで受け入れ可能宣言があるため
自動割り当てされますが"C"のデータが来ると、自動では割り当てられず、ここで登録した手続きが呼ばれます。
登録されていない場合、Baseとして割り当てをトライしエラーとなります。
@hiU.AcceptTypes({A.class,B.class})
static abstract class Base { // base(Abstact)
int id;
}
@hiU.TypeHintField("A")
static class A extends Base { // 派生
String infoA;
}
@hiU.TypeHintField("B")
static class B extends Base { // 派生
Double infoB;
}
@hiU.TypeHintField("C")
static class C extends Base { // 派生
Integer infoC
}
static class Info {
List<Base> infos; // 多型管理
}
手続きの登録は次のように行います。
hiJSON.with_atType_parse(baseクラス.class
(c,f,t,o)->{ 手続き c:Baseクラス,f:フィールド,t:@type情報,o:オブジェクト })
cにはbaseクラスの情報,fには上位のクラス内でのフィールド情報、tにはタイプヒント(この例では"A","B,"C")、oには構造解析されたJOSBオブジェクトが入っています。fはnullの場合もあります。
parseText(),asClass()と連結して使います。実例を示します。
Infos _info= hiJSON
.parseText(_json_textAB)
.with_atType_parse((c,f,t,o)->{return check(c,f,t,o);})
.asClass(Infos.class);
check_func_ - ラムダ式public static hiJSON.Engine with_functionStyle_parse(String funcName_, hiU.BiFunctionEx<String,ArrayList<Object>,Object,Exception> check_func_)
関数形式の配列を解析手続きを設定します。
関数の戻したオブジェクトがフィールドにセットされます。
nullを返すと標準の手続きでフィールド値がセットされます。
funcName_ - 関数名check_func_ - ラムダ式public static hiJSON.Engine with_dict_parse(String key_, hiU.TriFunctionEx<String,Object,Map<String,Object>,Object,Exception> check_func_)
辞書型データをノードに置き換える手続きを設定します。
要素が一個の辞書型データを解析しノードオブジェクトを生成するて
key_ - 辞書キーcheck_func_ - ラムダ式public static hiJSON.Engine engine()
設定項目を毎回設定すると煩雑になる場合、解析エンジンの生成だけを行って、そのエンジンを使いまわすことができます。
ソース指定(parseText,parseFile,parseReader,parseNode)以外の設定は引き継がれます。
hiJSON.Engine _engine= hiJSON.engine(); _engine.substitute(Map.class).with(HashMap.class) .with_option(hiU.PUBLIC_ONLY); while(...){ // 型1 データ=_engine.parseText(入力文字列1) .asClass(型1.class); 型2 データ=_engine.parseText(入力文字列2) .asClass(型2.class); // }
なお、解析エンジンから表示メソッドstr()は呼べません。表示にはhiJSON.str()またはhiU.str()が必要です。
public static hiJSON.Engine default_engine()
このメソッドにより得られるエンジンに対する変更はスレッドセーフではありません。
変更はその後の解析に影響を与えます。