1. Présentation
Dans cet article précédent, nous avons vu comment récupérer des documents BSON en tant qu'objets Java à partir de MongoDB.
C'est une façon très courante de développer une API REST, car on peut vouloir modifier ces objets avant de les convertir en JSON (en utilisant Jackson par exemple).
Cependant, nous ne voudrions peut-être rien changer à nos documents. Pour nous éviter d'avoir à coder le mappage d'objets Java verbeux, nous pouvons utiliser la conversion directe de documents BSON en JSON .
Voyons comment l'API MongoDB BSON fonctionne pour ce cas d'utilisation.
2. Création de documents BSON dans MongoDB avec Morphia
Tout d'abord, configurons nos dépendances en utilisant Morphia comme décrit dans cet article.
Voici notre exemple entité qui comprend différents types d'attribut :
@Entity("Books")
public class Book {
@Id
private String isbn;
@Embedded
private Publisher publisher;
@Property("price")
private double cost;
@Property
private LocalDateTime publishDate;
// Getters and setters ...
}
Créons ensuite une nouvelle entité BSON pour notre test et enregistrons-la dans MongoDB :
public class BsonToJsonIntegrationTest {
private static final String DB_NAME = "library";
private static Datastore datastore;
@BeforeClass
public static void setUp() {
Morphia morphia = new Morphia();
morphia.mapPackage("com.baeldung.morphia");
datastore = morphia.createDatastore(new MongoClient(), DB_NAME);
datastore.ensureIndexes();
datastore.save(new Book()
.setIsbn("isbn")
.setCost(3.95)
.setPublisher(new Publisher(new ObjectId("fffffffffffffffffffffffa"),"publisher"))
.setPublishDate(LocalDateTime.parse("2020-01-01T18:13:32Z", DateTimeFormatter.ISO_DATE_TIME)));
}
}
3. Conversion de document BSON en JSON par défaut
Testons maintenant la conversion par défaut qui est très simple :appelez simplement toJson méthode du Document BSON classe :
@Test
public void givenBsonDocument_whenUsingStandardJsonTransformation_thenJsonDateIsObjectEpochTime() {
String json = null;
try (MongoClient mongoClient = new MongoClient()) {
MongoDatabase mongoDatabase = mongoClient.getDatabase(DB_NAME);
Document bson = mongoDatabase.getCollection("Books").find().first();
assertEquals(expectedJson, bson.toJson());
}
}
Le expectedJson la valeur est :
{
"_id": "isbn",
"className": "com.baeldung.morphia.domain.Book",
"publisher": {
"_id": {
"$oid": "fffffffffffffffffffffffa"
},
"name": "publisher"
},
"price": 3.95,
"publishDate": {
"$date": 1577898812000
}
}
Cela semble correspondre à un mappage JSON standard.
Cependant, nous pouvons voir que la date a été convertie par défaut en tant qu'objet avec un $date champ au format d'heure d'époque. Voyons maintenant comment changer ce format de date.
4. Conversion de date BSON en JSON détendue
Par exemple, si nous voulons une représentation de date ISO plus classique (comme pour un client JavaScript), nous pouvons passer le détendu Mode JSON vers toJson méthode, en utilisant JsonWriterSettings.builder :
bson.toJson(JsonWriterSettings
.builder()
.outputMode(JsonMode.RELAXED)
.build());
En conséquence, nous pouvons voir le publishDate conversion "relâchée" du champ :
{
...
"publishDate": {
"$date": "2020-01-01T17:13:32Z"
}
...
}
Ce format semble correct, mais nous avons toujours le $date — voyons comment s'en débarrasser à l'aide d'un convertisseur personnalisé.
5. Conversion de date BSON en JSON personnalisée
Tout d'abord, nous devons implémenter le BSON Converter interface pour le type Long , car les valeurs de date sont exprimées en millisecondes depuis l'époque. Nous utilisons DateTimeFormatter.ISO_INSTANT pour obtenir le format de sortie attendu :
public class JsonDateTimeConverter implements Converter<Long> {
private static final Logger LOGGER = LoggerFactory.getLogger(JsonDateTimeConverter.class);
static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ISO_INSTANT
.withZone(ZoneId.of("UTC"));
@Override
public void convert(Long value, StrictJsonWriter writer) {
try {
Instant instant = new Date(value).toInstant();
String s = DATE_TIME_FORMATTER.format(instant);
writer.writeString(s);
} catch (Exception e) {
LOGGER.error(String.format("Fail to convert offset %d to JSON date", value), e);
}
}
}
Ensuite, nous pouvons passer une instance de cette classe en tant que convertisseur DateTime au JsonWriterSettings constructeur :
bson.toJson(JsonWriterSettings
.builder()
.dateTimeConverter(new JsonDateTimeConverter())
.build());
Enfin, nous obtenons un format de date ISO JSON simple :
{
...
"publishDate": "2020-01-01T17:13:32Z"
...
}