web-dev-qa-db-fra.com

convertir des objets de document dans MongoDB 3 en POJOS

Je sauvegarde un objet avec un champ Java.util.Date dans une instance de MongoDB 3.2.

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

la chaîne contient:

"captured": 1454549266735

alors je l'ai lu à partir de l'instance 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);

la désérialisation échoue:

Java.lang.RuntimeException: com.fasterxml.jackson.databind.JsonMappingException: Impossible de désérialiser l'instance de Java.util.Date hors du jeton START_OBJECT

Je vois que la chaîne json créée par "document.toJson ()" contient:

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

au lieu de ce qui était à l'origine ("capturé": 1454549266735) Les documents MongoDB disent qu'ils ont commencé à utiliser "MongoDB Extended Json". J'ai essayé les Jackson 1 et 2 pour l'analyser - pas de chance.

quel est le moyen le plus simple de convertir les objets Document fournis par MongoDB 3 en POJO Java? peut-être que je peux sauter toJson () étape complètement?

J'ai essayé mongojack - celui-là ne supporte pas MongoDB3.

Nous avons examiné quelques autres mappeurs POJO répertoriés dans la page de documentation de MongoDB. Ils ont tous besoin de mettre leurs annotations personnalisées dans les classes Java.

12
Alex

Vous devez définir et utiliser des paramètres JsonWriterSettings personnalisés pour optimiser la génération JSON:

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

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

Produira:

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

Si vous n'utilisez pas les paramètres personnalisés, le document produira un fichier json étendu:

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

Cela ressemble au bogue du pilote Java Mongo, dans lequel Document.toJson génère du JSON non standard même si JsonMode.STRICT est utilisé. Ce problème est décrit dans le bogue suivant https://jira.mongodb.org/browse/Java-2173 pour lequel je vous encourage à voter.

Une solution de contournement consiste à utiliser com.mongodb.util.JSON.serialize (document).

5
Aleksey Korolev

Je sauvegarde une balise avec mon document mongo qui spécifie le type d'origine de l'objet stocké. J'utilise ensuite Gson pour l'analyser avec le nom de ce type. Tout d'abord, pour créer le document stocké

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

puis de relire le document dans 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);
}

Merci à Aleksey pour avoir signalé JSON.serialize ().

0
David Wood

On dirait que vous utilisez l'objet Date dans "myObject". Dans ce cas, vous devez utiliser une variable DateSerializer qui implémente JsonSerializer<LocalDate>, JsonDeserializer<LocalDate>, puis l'enregistrer avec GsonBuilder. Exemple de code suit:

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

Maintenant, enregistrez-le avec GsonBuilder:

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