Рубрики
Без рубрики

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

Краткое и практическое руководство по преобразованию BSON в JSON на Java.

Автор оригинала: Benjamin Caure.

1. Обзор

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

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

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

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

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

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

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

@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.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. Преобразование документа 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.baeldung.morphia.domain.Book",
    "publisher": {
        "_id": {
            "$oid": "fffffffffffffffffffffffa"
        },
        "name": "publisher"
    },
    "price": 3.95,
    "publishDate": {
        "$date": 1577898812000
    }
}

Это, по-видимому, соответствует стандартному отображению JSON.

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

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

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

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

В результате мы можем увидеть “расслабленное” преобразование поля Дата публикации :

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

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

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

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

public class JsonDateTimeConverter implements Converter {

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

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

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

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

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

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

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

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

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

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