3

デバイスからのデータを保存する小さなアプリケーションを開発しました。JSON 形式でデータを保存することを選択しました。データのシリアル化/逆シリアル化は、私が作成したカスタム型が含まれていても問題なく機能します...しかし、私だけがIDEで作業します(Eclipse、さらに言えば)。

ただし、実行可能な JAR ファイルをエクスポートすると、ソフトウェアが常に次の例外をスローするため、データの逆シリアル化で何らかの問題が発生します。

Caused by: java.lang.UnsupportedOperationException: Cannot allocate class LocalDateTime
    at com.google.gson.internal.UnsafeAllocator$4.newInstance(UnsafeAllocator.java:104)
    at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:225)
    ... 88 common frames omitted

組み込み型ではなく、カスタム型で問題が発生すると思いました。この時点で、次の 2 つのことがわかりました。

  • 完全な JRE 9 を使用して JAR ファイルを実行すると、例外はスローされません。Jlink.exe で作成したカスタム JRE に含まれるモジュールを再確認したところ、すべてが正しく含まれていました。私はまだ小さい JRE を使用したいので、これ以上調査しませんでした (IDE で完全に動作する理由はこれで説明できると思います)。
  • カスタム デシリアライザーを Gson オブジェクトに追加し (以下を参照)、JSON 文字列を有効なデータに手動で変換するだけで、LocalDateTime クラスでの例外を回避できましたが、例外は別のクラスで単純に再表示されました。カスタムメイドの時間。

この時点で、問題を引き起こすデータ型ごとにデシリアライザーを追加するだけでよいと思いますが、完全な JRE で問題が発生しない理由と、すべてのモジュールが必要なものが含まれています。データを保存する Gson オブジェクトにカスタム シリアライザーを追加していないことにも言及する価値があるかもしれません。すべて Gson の既定値に従ってシリアル化されます。

LocalDateTimeデシリアライザー:

    @Override
    public LocalDateTime deserialize(JsonElement json, java.lang.reflect.Type type,
                JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {

        JsonObject joDate = json.getAsJsonObject().get("date").getAsJsonObject();
        JsonObject joTime = json.getAsJsonObject().get("time").getAsJsonObject();
        //JSON example: {"date":{"year":2019,"month":1,"day":9},"time":{"hour":6,"minute":14,"second":1,"nano":0}
        return LocalDateTime.of(joDate.get("year").getAsInt(),
                joDate.get("month").getAsInt(),
                joDate.get("day").getAsInt(),
                joTime.get("hour").getAsInt(),
                joTime.get("minute").getAsInt(),
                joTime.get("second").getAsInt(),
                joTime.get("nano").getAsInt());
    }
}

Jdeps.deps モジュール リスト:

com.google.gson
java.base
javafx.base
javafx.controls
javafx.fxml
javafx.graphics
org.slf4j

受け取った回答の後、ここで問題を開きました。

4

1 に答える 1