最近、JSONとの間の列挙型の逆/シリアル化中に奇妙な動作に遭遇しました。
私は関連する部分を簡単な例に落とし込みました(以下のコードを参照)。基本的に、列挙型エントリを含むリストがあります。リストをシリアル化してから、逆シリアル化します。新しい(逆シリアル化された)リストに特定の列挙型エントリが含まれている場合にチェックすると、リストに実際にエントリが含まれていても、回答として常に「false」が返されます。
少し自分で分析したところ、リストを逆シリアル化した後、コンテンツは列挙型ではなく、文字列が含まれていることがわかりました。
なぜこれが起こるのか、どうすれば回避できるのかを理解したいと思います。私の目標は、文字列のリストではなく、逆シリアル化後に列挙型エントリのリストを再度作成することです。
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class Test {
enum TYPE {
SMALL, MEDIUM, LARGE
}
public static void main(String[] args) {
List<TYPE> myList = new ArrayList<>();
myList.add( TYPE.MEDIUM );
// serialize
String serializedJsonString = JsonbBuilder.create(new JsonbConfig().withLocale(Locale.GERMAN).withFormatting(true)).toJson(myList);
// deserialize
@SuppressWarnings("unchecked")
List<TYPE> mySecondList = JsonbBuilder.create(new JsonbConfig().withLocale(Locale.GERMAN).withFormatting(true)).fromJson(serializedJsonString, List.class);
System.out.println( myList.contains( TYPE.MEDIUM ) ); // will be true (as expected)
System.out.println( mySecondList.contains( TYPE.MEDIUM ) ); // will be false (surprising!)
System.out.println( mySecondList.contains( "MEDIUM" ) ); // will be true (surprising!)
}
}
Java列挙型は、デフォルトで文字列にシリアル化されます。これは、Java列挙型に適したデフォルトのJSONタイプがないためです。(必要に応じて、intにシリアル化されるように構成できます。)
デシリアライズするときは、JSON文字列を列挙型に変換するようにJsonbパーサーに指示する必要があります。そうしないと、デフォルトでJavaストリングにデシリアライズされます。
上記の例では、列挙型のリストList.class
(List<?>
)ではなく(つまり)を要求したため、これを行っていません。これは、型消去のためにJavaで行うのは難しいです。(コンパイラはバージョンが機能しないことを認識しているため、コードを「チェックなし」としてマークする必要があることに注意してください。)JsonBドキュメントでは、このケースについて明示的に説明しています:http://json-b.net/docs/user-guide .html#mapping-a-generic-collectionTYPE
List<TYPE>
次のようなものを試してください:
List<TYPE> mySecondList = jsonb.fromJson(result, new ArrayList<TYPE>(){}.getClass().getGenericSuperclass());
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加