これは何? †
- REST-APIを作っているときに、引数のBeanをいちいち作るのめんどいので、Map<String, Object> で済ませようという話
JSONで表すことができるデータ型 †
型 | 型名 | 表記法 |
Integer | 整数 | 123 |
Float | 実数 | 123.0 |
String | 文字列 | "string" / 'string' |
Object | オブジェクト | {key:val} |
Array | 配列 | [a,b,c] |
Boolean | 真偽値 | true, false |
Null | | Null |
こいつらが、REST-API 側でどうマッピングされるか調べてみた
REST-API †
@Path("map")
public class MapResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Object doSomething(LinkedHashMap<String, Object> inJson) {
System.out.println(dumpMap(inJson));
return inJson;
}
private String dumpMap(Map<String, Object> map) {
return dumpMap(map," ");
}
private String dumpMap(Map<String, Object> map, String indent) {
StringBuilder sb = new StringBuilder();
sb.append(indent).append(map.getClass().getName()).append("{\n");
map.forEach((key, val) -> {
sb.append(indent);
switch(val.getClass().getName()){
case "java.util.ArrayList" :
sb.append(String.format("%s(%s<%s>)=%s\n"
, key
, val.getClass().getName()
, ((List)val).get(0).getClass().getName()
, val.toString()));
break;
case "java.util.LinkedHashMap" :
sb.append(String.format("%s(%s)={\n"
, key
, val.getClass().getName()));
sb.append(dumpMap((Map<String, Object>)val, indent + " "));
break;
default:
sb.append(String.format("%s(%s)=%s\n"
, key
, val.getClass().getName()
, val.toString()));
break;
}
});
sb.append(indent).append("}\n");
return sb.toString();
}
}
実行結果 †
- test.json
{
"key1" : "val1",
"key2" : "val2",
"key3" : 123,
"key4" : 123.0,
"key5" : true,
"key6" : ["banana","grape","apple"],
"key7" : [123,456,789],
"key8" : {
"sub1" : "sval1",
"sub2" : "sval2",
"sub3" " ["abc","def","ghi"]
}
}
- curl で呼び出し
$ curl -H 'Content-Type:application/json' -d @test.json http://localhost:8080/RESTExam/webresources/map
ちなみに、標準入力で JSON を打ち込むときは -d @- とする。JSONを即値で与える場合は -d "{\"key\":\"value\"}"
- マッピング結果 (Glassfishのコンソール出力)
java.util.LinkedHashMap{
key1(java.lang.String)=val1
key2(java.lang.String)=val2
key3(java.lang.Integer)=123
key4(java.lang.Double)=123.0
key5(java.lang.Boolean)=true
key6(java.util.ArrayList<java.lang.String>)=[banana, grape, apple]
key7(java.util.ArrayList<java.lang.Integer>)=[123, 456, 789]
key8(java.util.LinkedHashMap)={
java.util.LinkedHashMap{
sub1(java.lang.String)=sval1
sub2(java.lang.String)=sval2
sub3(java.util.ArrayList<java.lang.String>)=[abc, def, ghi]
}
}
}
- マッピング結果
JSON型 | Java型 |
Integer | java.lang.Integer |
Float | java.lang.Double |
String "" | java.lang.String |
Object {} | LinkedHashMap?<String, Object> (格納されているオブジェクトの型は、この表に従ってマッピングされる) |
Array [] | ArrayList?<Object> (格納されているオブジェクトの型は、この表に従ってマッピングされる) |
Boolean | java.lang.Boolean |
Null | なし |
- そりゃそうですねという素直な結果。まぁ、ガチガチに Bean を作らなくても REST-API の引数(JSONのマッピング先)は、 Map<String, Object> でいいかな
- Map のインスタンスは LinkedHashMap? (入れた順を保存するMap) になるようです
Java#Glassfish