Gson
gsonと呼ばれるライブラリを使用します.調べた限り一番一般的です.以下Maven.
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.7</version> </dependency>
公式のgithubはこちら.
使い方
恐ろしく簡単です.Collection以外のクラスは以下のようにして変換できます.
T obj; //Collection以外のObject Gson gson = new Gson(); String json = gson.toJson(obj); //object -> json T obj2 = gson.fromJson(json, obj); //json -> object
Collection<T>を扱う場合
また,Collectionを扱いたい場合は以下のように実施します.これはCollectionがGenericsであり,jsonでは型情報を保存する手法がないので,deserializeするときに明示的に型指定する必要があるためです.(試しにList.classを渡してもdeserializeしてくれません)
//Tは適当なObject Type collectionType = new TypeToken<Collection<T>>(){}.getType(); List<T> lists = gson.fromJson(json, collectionType);
Collectionを持ったWrapperクラスを定義して,それを渡したほうが可読性的にもいいと思いますね.
Genericsクラスを扱う
上記で想像がつくかもしれませんが,他のGenericsクラスをdeserializeするときも上記と同様の手法を用います.
Type type = new TypeToken<GenericClass<String>>(){}.getType(); GenericClass<String> obj = gson.fromJson(json, type);
jsonにnull値を含める
jsonで {“id” : null}と表示してほしい場合には,以下からGsonを作製します.jsonの可読性を高める目的だけで,json -> Objectへのdeserializeは問題なくこのオプションに関係なく可能です.(null値のObjectはnullになる)
GsonBuilder builder = new GsonBuilder(); builder.serializeNulls(); Gson gson = builder.create();
jsonでprivate フィールドを除く
Interface部だけ取り出したい場合は以下のようにしてPrivateなどのフィールドは除くことができるようです.
GsonBuilder builder = new GsonBuilder(); builder.excludeFieldsWithModifiers(Modifier.PRIVATE);
特定のクラスにだけ特別なSerialize/Deserializeを行う
確かにこれ使いたいときありますよね.備忘録としてリンクだけ貼っておきます.
HttpURLConnectionによる通信
Client
JsonTransferというInnerClassをJsonで送信します.Android用のHttpURLConnectionになります.
private void sendJson(){ List<JsonTransfer> items = new ArrayList<>(); items.add(new JsonTransfer("json1", 343)); items.add(new JsonTransfer("json2", 34777)); items.add(new JsonTransfer(null, 6464)); GsonBuilder builder = new GsonBuilder(); builder.serializeNulls(); Gson gson = builder.create(); String json = gson.toJson(items); Log.e("test", json); HttpURLConnection con = null; //post try{ URL url = new URL("https://localhost:8080/application/anywhere"); con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("POST"); //POSTを使用 con.setDoOutput(true); //Requestにボディを持たせます. con.setDoInput(true); //Defaultでtrueなのでなくてもよい con.setRequestProperty("Content-Type", "application/json; charset=utf-8"); //jsonを指定する try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(con.getOutputStream(), StandardCharsets.UTF_8))){ writer.write(json); } if(con.getResponseCode() == HttpURLConnection.HTTP_OK){ try(BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))){ StringBuilder builder1 = new StringBuilder(); String line = null; while((line = reader.readLine()) != null){ builder1.append(line); } Log.e("test", "recv:" + builder1.toString()); } } }catch(Exception e){ e.printStackTrace(); }finally { if(con != null){ con.disconnect(); } } } private static class JsonTransfer{ private String name; private int id; public JsonTransfer(String name, int id) { this.name = name; this.id = id; } }
Server
HttpServletで受け取る場合を記載します.なお,InnerClassにJsonTransferを定義していますが,本来はServerかClientがどちらかに依存してそれを参照するようにすべきで,両方に記載すべきではありません.逆に言えば,Gsonはフィールド名が一致していたらそのクラスで読み込んでくれるということですね.
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); BufferedReader reader = new BufferedReader(req.getReader()); String json = reader.readLine(); System.out.println("recv json:" + json); Gson gson = new Gson(); Type collectionType = new TypeToken<Collection<JsonTransfer>>(){}.getType(); List<JsonTransfer> recordItems = gson.fromJson(json, collectionType); for(JsonTransfer item : recordItems){ System.out.println(item.name + "," + item.id); } } private static class JsonTransfer{ private String name; private int id; public JsonTransfer(String name, int id) { this.name = name; this.id = id; } }