Javaオブジェクトをjsonに変換する必要があるという要件があります。
私はそのためにGsonを使用していますが、null以外の値または空でない値のみをシリアル化するコンバーターが必要です。
例えば:
//my Java object looks like
class TestObject{
String test1;
String test2;
OtherObject otherObject = new OtherObject();
}
今、このオブジェクトをjsonに変換する私のGsonインスタンスは次のようになります
Gson gson = new Gson();
TestObject obj = new TestObject();
obj.test1 = "test1";
obj.test2 = "";
String jsonStr = gson.toJson(obj);
println jsonStr;
上記の印刷では、結果は
{"test1":"test1", "test2":"", "otherObject":{}}
ここでは、結果が欲しいだけです
{"test1":"test1"}
Test2は空で、otherObjectは空なので、jsonデータにシリアル化されたくありません。
ところで、私はGroovy/Grailsを使用しているので、これに適したプラグインがあれば、gsonシリアル化クラスをカスタマイズするための提案がなければ良いでしょう。
独自のTypeAdapter
を作成します
public class MyTypeAdapter extends TypeAdapter<TestObject>() {
@Override
public void write(JsonWriter out, TestObject value) throws IOException {
out.beginObject();
if (!Strings.isNullOrEmpty(value.test1)) {
out.name("test1");
out.value(value.test1);
}
if (!Strings.isNullOrEmpty(value.test2)) {
out.name("test2");
out.value(value.test1);
}
/* similar check for otherObject */
out.endObject();
}
@Override
public TestObject read(JsonReader in) throws IOException {
// do something similar, but the other way around
}
}
その後、Gson
で登録できます。
Gson gson = new GsonBuilder().registerTypeAdapter(TestObject.class, new MyTypeAdapter()).create();
TestObject obj = new TestObject();
obj.test1 = "test1";
obj.test2 = "";
System.out.println(gson.toJson(obj));
生産する
{"test1":"test1"}
GsonBuilder
クラスには、独自のシリアライゼーション/デシリアライゼーション戦略を作成し、タイプアダプタを登録し、他のパラメータを設定するための多数のメソッドがあります。
Strings
はGuavaクラスです。その依存関係が必要ない場合は、独自のチェックを行うことができます。
私がanswerを使用してTypeAdapter
で個人的に嫌いなのは、クラス全体のすべてのフィールドを記述する必要があるという事実です。これは、50個のフィールド(if
の50個のTypeAdapter
ブロックを意味します).
私のソリューションはReflection
に基づいており、デフォルトではGson
はnull値フィールドをシリアル化しません。
DocumentModelというドキュメントを作成するAPIのデータを保持する特別なクラスがあります。これには約50のフィールドがあり、String
フィールドに ""(空ではないが空ではない)値または空の配列を送信しませんサーバ。そこで、すべての空のフィールドを無効にしてオブジェクトのコピーを返す特別なメソッドを作成しました。注-デフォルトでは、DocumentModelインスタンスのすべての配列は空の(長さゼロの)配列として初期化されているため、nullになることはありません。
public DocumentModel getSerializableCopy() {
Field fields[] = new Field[]{};
try {
// returns the array of Field objects representing the public fields
fields = DocumentModel.class.getDeclaredFields();
} catch (Exception e) {
e.printStackTrace();
}
DocumentModel copy = new DocumentModel();
Object value;
for (Field field : fields) {
try {
value = field.get(this);
if (value instanceof String && TextUtils.isEmpty((String) value)) {
field.set(copy, null);
// note: here array is not being checked for null!
else if (value instanceof Object[] && ((Object[]) value).length == 0) {
field.set(copy, null);
} else
field.set(copy, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return copy;
}
このメソッドを使用して、このメソッドの作成後にフィールドが追加または削除されたかどうかは気にしません。残っている唯一の問題は、String
または配列ではないカスタム型フィールドをチェックすることですが、これは特定のクラスに依存し、if/elseブロックで追加コード化する必要があります。
私には問題はgsonにはないようです。 Gsonは、nullと空の文字列の違いを正しく追跡します。その区別を消去してもよろしいですか? TestObjectを使用するすべてのクラスは気にしませんか?
違いを気にしない場合にできることは、シリアル化する前にTestObject内で空の文字列をnullに変更することです。または、空の文字列がnullに設定されるようにTestObjectでセッターを作成してください。そのようにして、クラス内で空の文字列がnullと同じであると厳密に定義します。セッターの外部で値を設定できないようにする必要があります。