Перейти к основному содержимому

Преобразование документов BSON в JSON в Java

· 4 мин. чтения

1. Обзор

В этой предыдущей статье мы увидели, как получить документы BSON как объекты Java из MongoDB.

Это очень распространенный способ разработки REST API, так как мы можем захотеть изменить эти объекты перед преобразованием их в JSON (например, используя Jackson ).

Однако мы можем не захотеть ничего менять в наших документах. Чтобы избавить нас от необходимости кодировать подробное сопоставление объектов Java, мы можем использовать прямое преобразование документов BSON в JSON .

Давайте посмотрим, как API MongoDB BSON работает для этого варианта использования.

2. Создание документа BSON в MongoDB с помощью Morphia

Прежде всего, настроим наши зависимости с помощью Morphia, как описано в этой статье .

Вот наш пример `` объекта, который включает в себя различные типы атрибутов:

@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 ...
}

Затем давайте создадим новый объект BSON для нашего теста и сохраним его в 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.foreach.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. Преобразование документов BSON в JSON по умолчанию

Теперь давайте проверим преобразование по умолчанию, которое очень простое: просто вызовите метод toJson из класса BSON Document :

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

Ожидаемое значение Json :

{
"_id": "isbn",
"className": "com.foreach.morphia.domain.Book",
"publisher": {
"_id": {
"$oid": "fffffffffffffffffffffffa"
},
"name": "publisher"
},
"price": 3.95,
"publishDate": {
"$date": 1577898812000
}
}

Кажется, это соответствует стандартному отображению JSON.

Однако мы видим, что дата была преобразована по умолчанию как объект с полем $date в формате времени эпохи . Давайте теперь посмотрим, как мы можем изменить этот формат даты.

4. Облегченное преобразование даты BSON в JSON

Например, если нам нужно более классическое представление даты в формате ISO (например, для клиента JavaScript), мы можем передать расслабленный режим JSON методу toJson , используя JsonWriterSettings.builder :

bson.toJson(JsonWriterSettings
.builder()
.outputMode(JsonMode.RELAXED)
.build());

В результате мы можем увидеть «расслабленное» преобразование поля publishDate :

{
...
"publishDate": {
"$date": "2020-01-01T17:13:32Z"
}
...
}

Этот формат кажется правильным, но у нас все еще есть поле $date — давайте посмотрим, как избавиться от него с помощью пользовательского конвертера.

5. Пользовательское преобразование даты BSON в JSON

Во-первых, мы должны реализовать интерфейс BSON Converter для типа Long , так как значения даты выражаются в миллисекундах с начала эпохи. Мы используем DateTimeFormatter.ISO_INSTANT , чтобы получить ожидаемый формат вывода:

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

Затем мы можем передать экземпляр этого класса в качестве преобразователя DateTime в построитель JsonWriterSettings :

bson.toJson(JsonWriterSettings
.builder()
.dateTimeConverter(new JsonDateTimeConverter())
.build());

Наконец, мы получаем простой формат даты JSON ISO :

{
...
"publishDate": "2020-01-01T17:13:32Z"
...
}

6. Заключение

В этой статье мы рассмотрели стандартное поведение преобразования документов BSON в JSON.

Мы рассказали, как настроить формат даты, что является распространенной проблемой, с помощью BSON Converter .

Конечно, мы можем действовать таким же образом для преобразования других типов данных : число, логическое значение, нулевое значение или идентификатор объекта, например.

Как всегда, код можно найти на GitHub .