web-dev-qa-db-ja.com

MongoDB 3のDocumentオブジェクトをPOJOSに変換する

Java.util.Dateフィールドを持つオブジェクトをMongoDB 3.2インスタンスに保存しています。

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(myObject);
collection.insertOne(Document.parse(json));

文字列には以下が含まれます:

"captured": 1454549266735

次に、MongoDBインスタンスから読み取りました。

    final Document document = collection.find(eq("key", value)).first();
    final String json = document.toJson();
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    xx = mapper.readValue(json, MyClass.class);

逆シリアル化は失敗します:

Java.lang.RuntimeException:com.fasterxml.jackson.databind.JsonMappingException:START_OBJECTトークンからJava.util.Dateのインスタンスをデシリアライズできません

「document.toJson()」によって作成されたjson文字列には、次のものが含まれていることがわかります。

"captured": {
    "$numberLong": "1454550216318"
}

もともとあったもの(「キャプチャ」:1454549266735)の代わりに、MongoDBのドキュメントは、「MongoDB Extended Json」の使用を開始したと述べています。ジャクソン1と2の両方を解析してみましたが、うまくいきませんでした。

mongoDB 3が提供するこれらのDocumentオブジェクトをJava POJOに変換する最も簡単な方法は何ですか?多分私はtoJson()ステップを完全にスキップできますか?

私はmongojackを試しました-これはMongoDB3をサポートしていません。

MongoDBのドキュメントページに記載されている他のいくつかのPOJOマッパーを確認しました。すべてのカスタムアノテーションをJavaクラスに配置する必要があります。

13
Alex

JSON生成を微調整するには、カスタムJsonWriterSettingsを定義して使用する必要があります。

 JsonWriterSettings settings = JsonWriterSettings.builder()
         .int64Converter((value, writer) -> writer.writeNumber(value.toString()))
         .build();

 String json = new Document("a", 12).append("b", 14L).toJson(settings);

生成されます:

 { "a" : 12, "b" : 14 }

カスタム設定を使用しない場合、ドキュメントは拡張jsonを生成します。

 { "a" : 12, "b" : { "$numberLong" : "14" } }
13
caiiiycuk

これは、Mongo Javaドライバーのバグです。Document.toJsonは、JsonMode.STRICTが使用されている場合でも、非標準のJSONを出力します。この問題は、次のバグ https://で説明されています。 jira.mongodb.org/browse/Java-217 投票をお勧めします。

回避策は、com.mongodb.util.JSON.serialize(document)を使用することです。

4
Aleksey Korolev

保管されているオブジェクトの元のタイプを指定するタグをmongo文書とともに保存します。次に、Gsonを使用して、その型の名前で解析します。まず、保存されたドキュメントを作成するには

private static Gson gson = new Gson();

public static Document ConvertToDocument(Object rd) {
    if (rd instanceof Document)
        return (Document)rd;
    String json = gson.toJson(rd);
    Document doc = Document.parse(json); 
    doc.append(TYPE_FIELD, rd.getClass().getName());
    return doc;
}

次に、ドキュメントをJavaに読み込むには、

public static Object ConvertFromDocument(Document doc) throws CAAException {
    String clazzName = doc.getString(TYPE_FIELD);
    if (clazzName == null)
        throw new RuntimeException("Document was not stored in the DB or got stored without becing created by itemToStoredDocument()");
    Class<?> clazz;
    try {
        clazz = (Class<?>) Class.forName(clazzName);
    } catch (ClassNotFoundException e) {
        throw new CAAException("Could not load class " + clazzName, e);
    }

    json = com.mongodb.util.JSON.serialize(doc);
    return gson.fromJson(json, clazz);
}

JSON.serialize()を指摘してくれたAlekseyに感謝します。

0
David Wood

"myObject"内でDateオブジェクトを使用しているようです。その場合、JsonSerializer<LocalDate>, JsonDeserializer<LocalDate>を実装するDateSerializerを使用し、それをGsonBuilderに登録する必要があります。サンプルコードは次のとおりです。

public class My_DateSerializer implements JsonSerializer<LocalDate>,
                                                          JsonDeserializer<LocalDate> {

@Override
public LocalDate deserialize(JsonElement json, Type typeOfT,
                        JsonDeserializationContext context) throws JsonParseException {
    final String dateAsString = json.getAsString();
    final DateTimeFormatter dtf = DateTimeFormat.forPattern(DATE_FORMAT);
    if (dateAsString.length() == 0)
    {
        return null;
    }
    else
    {
        return dtf.parseLocalDate(dateAsString);
    }
}

@Override
public JsonElement serialize(LocalDate src, Type typeOfSrc,
                                                     JsonSerializationContext context) {
    String retVal;
    final DateTimeFormatter dtf = DateTimeFormat.forPattern(DATE_FORMAT);
    if (src == null)
    {
        retVal = "";
    }
    else
    {
        retVal = dtf.print(src);
    }
    return new JsonPrimitive(retVal);
}
}

それをGsonBuilderに登録します。

final GsonBuilder builder = new GsonBuilder()
           .registerTypeAdapter(LocalDate.class, new My_DateSerializer());      
final Gson gson = builder.create();
0
Visakh