webentwicklung-frage-antwort-db.com.de

dokumentobjekte in MongoDB 3 nach POJOS konvertieren

Ich speichere ein Objekt mit einem Java.util.Date-Feld in einer MongoDB 3.2-Instanz.

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

der String enthält:

"captured": 1454549266735

dann las ich es aus der MongoDB-Instanz:

    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);

die Deserialisierung schlägt fehl:

Java.lang.RuntimeException: com.fasterxml.jackson.databind.JsonMappingException: Instanz von Java.util.Date kann nicht aus dem START_OBJECT-Token deserialisiert werden

Ich sehe, dass der von "document.toJson ()" erstellte Json-String Folgendes enthält:

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

anstelle dessen, was ursprünglich dort war ("erfasst": 1454549266735) MongoDB-Dokumente sagen, dass sie begonnen haben, "MongoDB Extended Json" zu verwenden. Ich habe sowohl Jackson 1 als auch 2 versucht, es zu analysieren - kein Glück.

was ist der einfachste Weg, um die von MongoDB 3 bereitgestellten Document-Objekte in Java-POJOs zu konvertieren? vielleicht kann ich toJson () Schritt ganz überspringen?

Ich habe Mongojack ausprobiert - dieser unterstützt MongoDB3 nicht.

Sehen Sie sich einige andere POJO-Mapper an, die auf der MongoDB-Dokumentseite aufgeführt sind. Sie alle müssen ihre benutzerdefinierten Annotationen in Java-Klassen einfügen.

12
Alex

Sie sollten benutzerdefinierte JsonWriterSettings definieren und verwenden, um die JSON-Generierung zu optimieren:

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

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

Wird herstellen:

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

Wenn Sie keine benutzerdefinierten Einstellungen verwenden, erzeugt das Dokument einen erweiterten Json-Code:

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

Dies sieht aus wie ein Mongo-Java-Treiberfehler, bei dem Document.toJson nicht standardmäßigen JSON-Code erzeugt, selbst wenn JsonMode.STRICT verwendet wird. Dieses Problem wird im folgenden Bug https://jira.mongodb.org/browse/Java-2173 beschrieben, für den ich Sie ermutige, abzustimmen.

Eine Problemumgehung besteht in der Verwendung von com.mongodb.util.JSON.serialize (document).

5
Aleksey Korolev

Ich speichere mit meinem Mongo-Dokument ein Tag, das den ursprünglichen Typ des gespeicherten Objekts angibt. Ich verwende dann Gson, um es mit dem Namen dieses Typs zu analysieren. Zuerst das gespeicherte Dokument erstellen

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;
}

dann das Dokument wieder in Java einlesen,

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);
}

Danke an Aleksey für den Hinweis auf JSON.serialize ().

0
David Wood

Es sieht so aus, als würden Sie ein Date-Objekt in "myObject" verwenden. In diesem Fall sollten Sie eine DateSerializer verwenden, die JsonSerializer<LocalDate>, JsonDeserializer<LocalDate> implementiert, und diese dann mit GsonBuilder registrieren. Beispielcode folgt:

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);
}
}

Registrieren Sie es jetzt bei GsonBuilder:

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