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

Как настроить отображение объектов Джексона, используемое типами гибернации

Узнайте, как настроить приложение Jackson ObjectMapper, используемое для сериализации и десериализации объектов JSON в типы столбцов JSON при использовании проекта hibernate-types.

Автор оригинала: Vlad Mihalcea.

Вступление

Как уже объяснялось , проект hibernate-типы с открытым исходным кодом позволяет сопоставлять JSON, МАССИВ при использовании JPA и Hibernate.

С тех пор как я запустил этот проект, одной из самых востребованных функций было добавление поддержки настройки базового приложения Jackson ObjectMapper , и начиная с версии 2.1.1 , это может быть сделано либо декларативно, либо программно.

В этой статье вы увидите, как настроить ObjectMapper при использовании проекта hibernate-типов.

Как настроить отображение объектов Джексона, используемое #Hibernate -Типы – @vlad_mihalcea https://t.co/nF1CcLVL7I pic.twitter.com/lBIMsw0Hh7

Декларативная конфигурация

Самый простой способ достичь этой цели-установить свойство hibernate.types.jackson.object.mapper конфигурации в файле hibernate.properties :

hibernate.types.jackson.object.mapper=com.vladmihalcea.hibernate.type.json.loader.CustomObjectMapperSupplier

Это свойство принимает полное имя класса реализации ObjectMapper поставщика интерфейса:

Что хорошо в настройке проекта hibernate-types , так это то, что вы можете использовать либо специфичный для Hibernate hibernate.properties , либо вы можете предоставить файл hibernate-types.properties , если вы не можете изменить hibernate.properties .

Вы даже можете предоставить другой файл свойств Java через hibernate-types.properties.путь Системное свойство.

Поставщик пользовательских объектов может выглядеть следующим образом:

public class CustomObjectMapperSupplier 
    implements ObjectMapperSupplier {

    @Override
    public ObjectMapper get() {
        ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
        
        objectMapper.setTimeZone(
            TimeZone.getTimeZone("GMT")
        );
        SimpleModule simpleModule = new SimpleModule(
            "SimpleModule", 
            new Version(1, 0, 0, null, null, null)
        );
        simpleModule.addSerializer(new MoneySerializer());
        objectMapper.registerModule(simpleModule);
        
        return objectMapper;
    }
}

Здесь мы используем пользовательский ObjectMapper , который использует наш собственный Сериализатор денег для обработки BigDecimal Типов объектов Java:

public class MoneySerializer 
    extends JsonSerializer {

    @Override
    public void serialize(
                BigDecimal value, 
                JsonGenerator jsonGenerator, 
                SerializerProvider provider)
            throws IOException {
        jsonGenerator.writeString(
            value.setScale(2, BigDecimal.ROUND_HALF_UP).toString()
        );
    }

    @Override
    public Class handledType() {
        return BigDecimal.class;
    }
}

Итак, если вы сохраняете следующую Книгу сущность, которая имеет атрибут JSON свойства :

Book book = new Book();
book.setIsbn("978-9730228236");
book.setProperties(
    JacksonUtil.toJsonNode(
        "{" +
        "   \"title\": \"High-Performance Java Persistence\"," +
        "   \"author\": \"Vlad Mihalcea\"," +
        "   \"publisher\": \"Amazon\"," +
        "   \"price\": 44.991234567" + 
        "}"
    )
);

entityManager.persist(book);

При извлечении сущности Book мы видим, что BigDecimal принимает только два десятичных знака:

Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");

assertEquals(
    "44.99", 
    book.getProperties().get("price").asText()
);

Программная конфигурация

Для еще большей гибкости вы можете использовать программную конфигурацию.

Предполагая, что у нас есть следующий тип объекта, который мы хотим сериализовать как JSON:

public class Location 
    implements Serializable {

    private String country;

    private String city;

    private BigDecimal reference;

    //Getters and setters omitted for brevity
}

И у нас есть Событие сущность, которая сопоставляет объект Location Java с типом столбца jsonb PostgreSQL:

@Entity(name = "Event")
@Table(name = "event")
public class Event {

    @Id
    private Long id;

    @Type(type = "location")
    @Column(columnDefinition = "jsonb")
    private Location location;

    //Getters and setters omitted for brevity
}

Мы можем использовать пользовательский ObjectMapper следующим образом:

JsonType jsonType = new JsonType(
    new CustomObjectMapperSupplier().get(), 
    Location.class
);

properties.put("hibernate.type_contributors",
    (TypeContributorList) () -> Collections.singletonList(
        (typeContributions, serviceRegistry) ->
            typeContributions.contributeType(
                jsonType, "location"
            )
    )
);

Свойство конфигурации hibernate.type_contributors позволяет регистрировать пользовательские типы гибернации, и мы можем использовать эту функцию для предоставления нашего собственного пользовательского объектного в JsonType , предоставляемого проектом hibernate-types .

Итак, если мы сохраняем следующее Событие сущность:

Location location = new Location();
location.setCountry("Romania");
location.setCity("Cluj-Napoca");
location.setReference(
    BigDecimal.valueOf(2.25262562526626D)
);

Event event = new Event();
event.setId(1L);
event.setLocation(location);

entityManager.persist(event);

При извлечении События сущности мы видим, что BigDecimal принимает только два десятичных знака:

Event event = entityManager.find(Event.class, 1L);

assertEquals("2.25", event.getLocation().getReference().toString());

Круто, правда?

Вывод

Мало того, что вы можете настроить ObjectMapper при использовании проекта hibernate-types , но новый механизм конфигурации позволит настраивать и другие варианты поведения.

Так что оставайтесь с нами, чтобы узнать больше!