{"id":410862,"date":"2024-06-29T21:37:53","date_gmt":"2024-06-29T21:37:53","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=410862"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=410862","title":{"rendered":"<span>\u041a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0445 JSON-\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e JPA \u0438 Hibernate<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5f2\/5f0\/cff\/5f25f0cffc0486a3b4c089a3468b579f.png\" width=\"780\" height=\"439\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5f2\/5f0\/cff\/5f25f0cffc0486a3b4c089a3468b579f.png\"\/><figcaption><\/figcaption><\/figure>\n<p><strong>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/strong><\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0441\u044c \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0430\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 JSON \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f JPA \u0438 Hibernate.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 Hibernate \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 JSON \u043d\u0430\u0442\u0438\u0432\u043d\u043e, \u0442\u043e \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0446\u0435\u043b\u0438 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/github.com\/vladmihalcea\/hibernate-types\"><u>Hibernate Types<\/u><\/a>.<\/p>\n<p><strong>\u041f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0435 \u0442\u0438\u043f\u044b<\/strong><\/p>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u043e\u0432 <code>DiscountCoupon<\/code>:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ebb\/5f6\/967\/ebb5f6967ae2da98411c97f0b9c94f6b.png\" width=\"1539\" height=\"554\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ebb\/5f6\/967\/ebb5f6967ae2da98411c97f0b9c94f6b.png\"\/><figcaption><\/figcaption><\/figure>\n<p><code>DiscountCoupon<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0431\u0430\u0437\u043e\u0432\u044b\u043c \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 <code>AmountDiscountCoupon<\/code> \u0438 <code>PercentageDiscountCoupon<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 \u0434\u0432\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0441\u043a\u0438\u0434\u043a\u0438 \u043d\u0430 \u0446\u0435\u043d\u0443 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 Book.<\/p>\n<p>\u0421\u0443\u0449\u043d\u043e\u0441\u0442\u044c <code>Book<\/code> \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"java\">@Entity(name = \"Book\") @Table(name = \"book\") public class Book {       @Id     @GeneratedValue     private Long id;       @NaturalId     @Column(length = 15)     private String isbn;       @Column(columnDefinition = \"jsonb\")     private List&lt;DiscountCoupon> coupons = new ArrayList&lt;>(); }<\/code><\/pre>\n<p>\u0417\u0430\u043c\u0435\u0442\u0438\u043c, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 (\u0441\u043f\u0438\u0441\u043a\u0430) <code>List<\/code> \u043a\u0443\u043f\u043e\u043d\u043e\u0432 \u0441\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u043c JSON \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u0435\u043d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0442\u0438\u043f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b.<\/p>\n<p><code>JsonType<\/code> \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u043d\u043e \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a\u0430 <code>List<\/code> \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0442\u0438\u043f \u0442\u0435\u0440\u044f\u0435\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u043c\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u0435\u0433\u043e \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<p><strong>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 JSON \u0441 Jackson DefaultTyping \u0438 Hibernate<\/strong><\/p>\n<p>\u041e\u0434\u043d\u0438\u043c \u0438\u0437 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 <code>JsonType<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0438\u043c\u0435\u044e\u0442 \u044f\u0432\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430, \u043a\u0430\u043a \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 \u0438\u043b\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u043c\u0438.<\/p>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 <code>DiscountCoupon<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043e\u043d \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u043d Jackson, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u043d\u0430\u0442\u044c \u0442\u043e\u0447\u043d\u044b\u0439 \u0442\u0438\u043f \u043a\u043b\u0430\u0441\u0441\u0430 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442 <code>DiscountCoupon<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 JSON-\u043a\u043e\u043b\u043e\u043d\u043a\u0438 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u041f\u043e \u044d\u0442\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 JsonType:<\/p>\n<pre><code class=\"java\">ObjectMapper objectMapper = new ObjectMapperWrapper().getObjectMapper();   properties.put(     \"hibernate.type_contributors\",     (TypeContributorList) () -> Collections.singletonList(         (typeContributions, serviceRegistry) ->             typeContributions.contributeType(                 new JsonType(                     objectMapper.activateDefaultTypingAsProperty(                         objectMapper.getPolymorphicTypeValidator(),                         ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE,                         \"type\"                     ),                     ArrayList.class                 ) {                     @Override                     public String getName() {                         return \"json-polymorphic-list\";                     }                 }             )     ) );<\/code><\/pre>\n<p><code>json-polymorphic-list<\/code> \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u0442 <a href=\"https:\/\/vladmihalcea.com\/how-to-map-json-objects-using-generic-hibernate-types\/\"><u>\u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a JsonType<\/u><\/a> \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 Jackson <code>ObjectMapper<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044e <code>DefaultTyping.OBJECT_AND_NON_CONCRETE<\/code>.<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 <code>json-polymorphic-list<\/code> \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e coupons:<\/p>\n<pre><code class=\"java\">@Type(type = \"json-polymorphic-list\") @Column(columnDefinition = \"jsonb\") private List&lt;DiscountCoupon> coupons = new ArrayList&lt;>();<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043f\u0440\u0438 \u043f\u0435\u0440\u0441\u0438\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 Book:<\/p>\n<pre><code class=\"java\">entityManager.persist(     new Book()         .setIsbn(\"978-9730228236\")         .addCoupon(             new AmountDiscountCoupon(\"PPP\")                 .setAmount(new BigDecimal(\"4.99\"))         )         .addCoupon(             new PercentageDiscountCoupon(\"Black Friday\")                 .setPercentage(BigDecimal.valueOf(0.02))         ) );<\/code><\/pre>\n<p>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Jackson <code>ObjectMapper<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 Hibernate Types, \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0432 <a href=\"https:\/\/vladmihalcea.com\/hibernate-types-customize-jackson-objectmapper\/\"><u>\u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/u><\/a>.<\/p>\n<p>Hibernate \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b SQL <code>INSERT<\/code>:<\/p>\n<pre><code>INSERT INTO book (   coupons,   isbn,   id ) VALUES (   [     {       \"type\":\"com.vladmihalcea.hibernate.type.json.polymorphic.AmountDiscountCoupon\",       \"name\":\"PPP\",       \"amount\":4.99     },     {       \"type\":\"com.vladmihalcea.hibernate.type.json.polymorphic.PercentageDiscountCoupon\",       \"name\":\"Black Friday\",       \"percentage\":0.02     }   ],   978-9730228236,   1 )<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e Jackson \u0432\u0441\u0442\u0430\u0432\u0438\u043b \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>type<\/code> \u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u044b <code>DiscountCoupon<\/code> JSON. \u0410\u0442\u0440\u0438\u0431\u0443\u0442 <code>type<\/code> \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Jackson \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 <code>Book<\/code>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 JSON-\u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0442\u0438\u043f\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u0430 <code>DiscountCoupon<\/code>.<\/p>\n<p>\u041f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 <code>Book<\/code> \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043e\u043d\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u044b <code>DiscountCoupon<\/code> \u0434\u043e\u043b\u0436\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"java\">Book book = entityManager.unwrap(Session.class)     .bySimpleNaturalId(Book.class)     .load(\"978-9730228236\");   Map&lt;String, DiscountCoupon> topics = book.getCoupons()     .stream()     .collect(         Collectors.toMap(             DiscountCoupon::getName,             Function.identity()         )     );   assertEquals(2, topics.size());   AmountDiscountCoupon amountDiscountCoupon =     (AmountDiscountCoupon) topics.get(\"PPP\"); assertEquals(     new BigDecimal(\"4.99\"),     amountDiscountCoupon.getAmount() );   PercentageDiscountCoupon percentageDiscountCoupon =     (PercentageDiscountCoupon) topics.get(\"Black Friday\"); assertEquals(     BigDecimal.valueOf(0.02),     percentageDiscountCoupon.getPercentage() );<\/code><\/pre>\n<p><strong>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0445 JSON-\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Jackson JsonTypeInfo<\/strong><\/p>\n<p>\u0414\u0440\u0443\u0433\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 Jackson <code>@JsonTypeInfo<\/code> \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u0438\u0441\u043a\u0440\u0438\u043c\u0438\u043d\u0430\u0442\u043e\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 Jackson \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 Java-\u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0438\u0437 \u0435\u0433\u043e \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e JSON-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>getType<\/code> \u0432 <code>DiscountCoupon<\/code> \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043c\u0435\u0436\u0434\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>type<\/code> \u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 <code>DiscountCoupon<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@JsonSubTypes<\/code>:<\/p>\n<pre><code class=\"java\">@JsonTypeInfo(     use = JsonTypeInfo.Id.NAME,     include = JsonTypeInfo.As.PROPERTY,     property = \"type\" ) @JsonSubTypes({     @JsonSubTypes.Type(         name = \"discount.coupon.amount\",         value = AmountDiscountCoupon.class     ),     @JsonSubTypes.Type(         name = \"discount.coupon.percentage\",         value = PercentageDiscountCoupon.class     ), }) public abstract class DiscountCoupon implements Serializable {       private String name;       public DiscountCoupon() {     }       public DiscountCoupon(String name) {         this.name = name;     }       public String getName() {         return name;     }       public void setName(String name) {         this.name = name;     }       @JsonTypeInfo(use = JsonTypeInfo.Id.NAME)     public abstract String getType();       @Override     public boolean equals(Object o) {         if (this == o) return true;         if (!(o instanceof DiscountCoupon)) return false;         DiscountCoupon that = (DiscountCoupon) o;         return Objects.equals(getName(), that.getName());     }       @Override     public int hashCode() {         return Objects.hash(getName());     } }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b <code>equals<\/code> \u0438 <code>hashCode<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b <a href=\"https:\/\/vladmihalcea.com\/the-anatomy-of-hibernate-dirty-checking\/\"><u>\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0443 dirty checking Hibernate<\/u><\/a>, \u0447\u0442\u043e\u0431\u044b \u0443\u0437\u043d\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0432\u044b \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0435 \u043a\u0443\u043f\u043e\u043d\u044b, \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e UPDATE.<\/p>\n<p><code>AmountDiscountCoupon<\/code> \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <code>getType<\/code> \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0442\u043e \u0436\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u0438\u0441\u043a\u0440\u0438\u043c\u0438\u043d\u0430\u0442\u043e\u0440\u0430, \u0447\u0442\u043e \u0438 <code>DiscountCoupon<\/code>, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u043e\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@JsonSubTypes.Type<\/code>.<\/p>\n<pre><code class=\"java\">public class AmountDiscountCoupon extends DiscountCoupon {       public static final String DISCRIMINATOR = \"discount.coupon.amount\";       private BigDecimal amount;       public AmountDiscountCoupon() {     }       public AmountDiscountCoupon(String name) {         super(name);     }       public BigDecimal getAmount() {         return amount;     }       public AmountDiscountCoupon setAmount(BigDecimal amount) {         this.amount = amount;         return this;     }       @Override     public String getType() {         return DISCRIMINATOR;     } }<\/code><\/pre>\n<p><code>PercentageDiscountCoupon<\/code> \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <code>getType<\/code> \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0442\u043e \u0436\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u0438\u0441\u043a\u0440\u0438\u043c\u0438\u043d\u0430\u0442\u043e\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0439 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0435\u0439 <code>@JsonSubTypes.Type<\/code> \u0432 \u0431\u0430\u0437\u043e\u0432\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 <code>DiscountCoupon<\/code>:<\/p>\n<pre><code class=\"java\">public class PercentageDiscountCoupon extends DiscountCoupon {       public static final String DISCRIMINATOR = \"discount.coupon.percentage\";       private BigDecimal percentage;       public PercentageDiscountCoupon() {     }       public PercentageDiscountCoupon(String name) {         super(name);     }       public BigDecimal getPercentage() {         return percentage;     }       public PercentageDiscountCoupon setPercentage(BigDecimal amount) {         this.percentage = amount;         return this;     }       @Override     public String getType() {         return DISCRIMINATOR;     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c Book \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a <code>JsonType<\/code>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 Java-\u043e\u0431\u044a\u0435\u043a\u0442\u044b <code>DiscountCoupun<\/code> \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u044b Jackson \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0433\u043e \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 <code>@JsonTypeInfo<\/code>:<\/p>\n<pre><code class=\"java\">@Entity(name = \"Book\") @Table(name = \"book\") @TypeDef(name = \"json\", typeClass = JsonType.class) public static class Book {       @Id     @GeneratedValue     private Long id;       @NaturalId     @Column(length = 15)     private String isbn;       @Type(type = \"json\")     @Column(columnDefinition = \"jsonb\")     private List&lt;DiscountCoupon> coupons = new ArrayList&lt;>();       }<\/code><\/pre>\n<p>\u0410 \u043f\u0440\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438 \u0442\u043e\u0439 \u0436\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 Book Hibernate \u0431\u0443\u0434\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 SQL-\u0437\u0430\u043f\u0440\u043e\u0441 <code>INSERT<\/code>:<\/p>\n<pre><code class=\"java\">INSERT INTO book (   coupons,   isbn,   id ) VALUES (   [     {       \"name\":\"PPP\",       \"amount\":4.99,       \"type\":\"discount.coupon.amount\"     },     {       \"name\":\"Black Friday\",       \"percentage\":0.02,       \"type\":\"discount.coupon.percentage\"     }   ],   978-9730228236,   1 )<\/code><\/pre>\n<p>\u041a\u0440\u0443\u0442\u043e, \u043f\u0440\u0430\u0432\u0434\u0430?<\/p>\n<p><strong>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/strong><\/p>\n<p>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0445 JSON-\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442 \u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c Hibernate Types. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432\u044b \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c Jackson <code>ObjectMapper<\/code> \u0442\u0430\u043a, \u043a\u0430\u043a \u0432\u0430\u043c \u0437\u0430\u0445\u043e\u0447\u0435\u0442\u0441\u044f, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0448\u0430\u0442\u044c \u0441\u0430\u043c\u044b\u0435 \u0440\u0430\u0437\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<hr\/>\n<blockquote>\n<p>\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043a\u0443\u0440\u0441\u0430<a href=\"https:\/\/otus.pw\/l4VB\/\"> \u00abJava Developer. Professional\u00bb<\/a>. <\/p>\n<p>\u0412\u0441\u0435\u0445 \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u0445 \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0435\u043c \u043d\u0430 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0435 demo-\u0437\u0430\u043d\u044f\u0442\u0438\u0435 <strong>\u00ab\u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Java Spring Boot\u00bb.<\/strong> \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u0430 \u0432\u0430\u043b\u044e\u0442\u044b. \u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043c \u043e\u0434\u0438\u043d \u0438\u0437 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0440\u0435\u043b\u044c\u0441\u044b. <a href=\"https:\/\/otus.pw\/T15r\/\"><strong>>> \u0420\u0415\u0413\u0418\u0421\u0422\u0420\u0410\u0426\u0418\u042f<\/strong><\/a><\/p>\n<\/blockquote>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/593941\/\"> https:\/\/habr.com\/ru\/articles\/593941\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p><strong>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/strong><\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0441\u044c \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0430\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 JSON \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f JPA \u0438 Hibernate.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 Hibernate \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 JSON \u043d\u0430\u0442\u0438\u0432\u043d\u043e, \u0442\u043e \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0446\u0435\u043b\u0438 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/github.com\/vladmihalcea\/hibernate-types\"><u>Hibernate Types<\/u><\/a>.<\/p>\n<p><strong>\u041f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0435 \u0442\u0438\u043f\u044b<\/strong><\/p>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u043e\u0432 <code>DiscountCoupon<\/code>:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p><code>DiscountCoupon<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0431\u0430\u0437\u043e\u0432\u044b\u043c \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 <code>AmountDiscountCoupon<\/code> \u0438 <code>PercentageDiscountCoupon<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 \u0434\u0432\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0441\u043a\u0438\u0434\u043a\u0438 \u043d\u0430 \u0446\u0435\u043d\u0443 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 Book.<\/p>\n<p>\u0421\u0443\u0449\u043d\u043e\u0441\u0442\u044c <code>Book<\/code> \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"java\">@Entity(name = \"Book\") @Table(name = \"book\") public class Book {       @Id     @GeneratedValue     private Long id;       @NaturalId     @Column(length = 15)     private String isbn;       @Column(columnDefinition = \"jsonb\")     private List&lt;DiscountCoupon> coupons = new ArrayList&lt;>(); }<\/code><\/pre>\n<p>\u0417\u0430\u043c\u0435\u0442\u0438\u043c, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 (\u0441\u043f\u0438\u0441\u043a\u0430) <code>List<\/code> \u043a\u0443\u043f\u043e\u043d\u043e\u0432 \u0441\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u043c JSON \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u0435\u043d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0442\u0438\u043f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b.<\/p>\n<p><code>JsonType<\/code> \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u043d\u043e \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a\u0430 <code>List<\/code> \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0442\u0438\u043f \u0442\u0435\u0440\u044f\u0435\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u043c\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u0435\u0433\u043e \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<p><strong>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 JSON \u0441 Jackson DefaultTyping \u0438 Hibernate<\/strong><\/p>\n<p>\u041e\u0434\u043d\u0438\u043c \u0438\u0437 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 <code>JsonType<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0438\u043c\u0435\u044e\u0442 \u044f\u0432\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430, \u043a\u0430\u043a \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 \u0438\u043b\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u043c\u0438.<\/p>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 <code>DiscountCoupon<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043e\u043d \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u043d Jackson, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u043d\u0430\u0442\u044c \u0442\u043e\u0447\u043d\u044b\u0439 \u0442\u0438\u043f \u043a\u043b\u0430\u0441\u0441\u0430 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442 <code>DiscountCoupon<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 JSON-\u043a\u043e\u043b\u043e\u043d\u043a\u0438 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u041f\u043e \u044d\u0442\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 JsonType:<\/p>\n<pre><code class=\"java\">ObjectMapper objectMapper = new ObjectMapperWrapper().getObjectMapper();   properties.put(     \"hibernate.type_contributors\",     (TypeContributorList) () -> Collections.singletonList(         (typeContributions, serviceRegistry) ->             typeContributions.contributeType(                 new JsonType(                     objectMapper.activateDefaultTypingAsProperty(                         objectMapper.getPolymorphicTypeValidator(),                         ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE,                         \"type\"                     ),                     ArrayList.class                 ) {                     @Override                     public String getName() {                         return \"json-polymorphic-list\";                     }                 }             )     ) );<\/code><\/pre>\n<p><code>json-polymorphic-list<\/code> \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u0442 <a href=\"https:\/\/vladmihalcea.com\/how-to-map-json-objects-using-generic-hibernate-types\/\"><u>\u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a JsonType<\/u><\/a> \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 Jackson <code>ObjectMapper<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044e <code>DefaultTyping.OBJECT_AND_NON_CONCRETE<\/code>.<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 <code>json-polymorphic-list<\/code> \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e coupons:<\/p>\n<pre><code class=\"java\">@Type(type = \"json-polymorphic-list\") @Column(columnDefinition = \"jsonb\") private List&lt;DiscountCoupon> coupons = new ArrayList&lt;>();<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043f\u0440\u0438 \u043f\u0435\u0440\u0441\u0438\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 Book:<\/p>\n<pre><code class=\"java\">entityManager.persist(     new Book()         .setIsbn(\"978-9730228236\")         .addCoupon(             new AmountDiscountCoupon(\"PPP\")                 .setAmount(new BigDecimal(\"4.99\"))         )         .addCoupon(             new PercentageDiscountCoupon(\"Black Friday\")                 .setPercentage(BigDecimal.valueOf(0.02))         ) );<\/code><\/pre>\n<p>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Jackson <code>ObjectMapper<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 Hibernate Types, \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0432 <a href=\"https:\/\/vladmihalcea.com\/hibernate-types-customize-jackson-objectmapper\/\"><u>\u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/u><\/a>.<\/p>\n<p>Hibernate \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b SQL <code>INSERT<\/code>:<\/p>\n<pre><code>INSERT INTO book (   coupons,   isbn,   id ) VALUES (   [     {       \"type\":\"com.vladmihalcea.hibernate.type.json.polymorphic.AmountDiscountCoupon\",       \"name\":\"PPP\",       \"amount\":4.99     },     {       \"type\":\"com.vladmihalcea.hibernate.type.json.polymorphic.PercentageDiscountCoupon\",       \"name\":\"Black Friday\",       \"percentage\":0.02     }   ],   978-9730228236,   1 )<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e Jackson \u0432\u0441\u0442\u0430\u0432\u0438\u043b \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>type<\/code> \u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u044b <code>DiscountCoupon<\/code> JSON. \u0410\u0442\u0440\u0438\u0431\u0443\u0442 <code>type<\/code> \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Jackson \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 <code>Book<\/code>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 JSON-\u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0442\u0438\u043f\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u0430 <code>DiscountCoupon<\/code>.<\/p>\n<p>\u041f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 <code>Book<\/code> \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043e\u043d\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u044b <code>DiscountCoupon<\/code> \u0434\u043e\u043b\u0436\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"java\">Book book = entityManager.unwrap(Session.class)     .bySimpleNaturalId(Book.class)     .load(\"978-9730228236\");   Map&lt;String, DiscountCoupon> topics = book.getCoupons()     .stream()     .collect(         Collectors.toMap(             DiscountCoupon::getName,             Function.identity()         )     );   assertEquals(2, topics.size());   AmountDiscountCoupon amountDiscountCoupon =     (AmountDiscountCoupon) topics.get(\"PPP\"); assertEquals(     new BigDecimal(\"4.99\"),     amountDiscountCoupon.getAmount() );   PercentageDiscountCoupon percentageDiscountCoupon =     (PercentageDiscountCoupon) topics.get(\"Black Friday\"); assertEquals(     BigDecimal.valueOf(0.02),     percentageDiscountCoupon.getPercentage() );<\/code><\/pre>\n<p><strong>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0445 JSON-\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Jackson JsonTypeInfo<\/strong><\/p>\n<p>\u0414\u0440\u0443\u0433\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 Jackson <code>@JsonTypeInfo<\/code> \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u0438\u0441\u043a\u0440\u0438\u043c\u0438\u043d\u0430\u0442\u043e\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 Jackson \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 Java-\u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0438\u0437 \u0435\u0433\u043e \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e JSON-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>getType<\/code> \u0432 <code>DiscountCoupon<\/code> \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043c\u0435\u0436\u0434\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>type<\/code> \u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 <code>DiscountCoupon<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@JsonSubTypes<\/code>:<\/p>\n<pre><code class=\"java\">@JsonTypeInfo(     use = JsonTypeInfo.Id.NAME,     include = JsonTypeInfo.As.PROPERTY,     property = \"type\" ) @JsonSubTypes({     @JsonSubTypes.Type(         name = \"discount.coupon.amount\",         value = AmountDiscountCoupon.class     ),     @JsonSubTypes.Type(         name = \"discount.coupon.percentage\",         value = PercentageDiscountCoupon.class     ), }) public abstract class DiscountCoupon implements Serializable {       private String name;       public DiscountCoupon() {     }       public DiscountCoupon(String name) {         this.name = name;     }       public String getName() {         return name;     }       public void setName(String name) {         this.name = name;     }       @JsonTypeInfo(use = JsonTypeInfo.Id.NAME)     public abstract String getType();       @Override     public boolean equals(Object o) {         if (this == o) return true;         if (!(o instanceof DiscountCoupon)) return false;         DiscountCoupon that = (DiscountCoupon) o;         return Objects.equals(getName(), that.getName());     }       @Override     public int hashCode() {         return Objects.hash(getName());     } }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b <code>equals<\/code> \u0438 <code>hashCode<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b <a href=\"https:\/\/vladmihalcea.com\/the-anatomy-of-hibernate-dirty-checking\/\"><u>\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0443 dirty checking Hibernate<\/u><\/a>, \u0447\u0442\u043e\u0431\u044b \u0443\u0437\u043d\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0432\u044b \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0435 \u043a\u0443\u043f\u043e\u043d\u044b, \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e UPDATE.<\/p>\n<p><code>AmountDiscountCoupon<\/code> \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <code>getType<\/code> \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0442\u043e \u0436\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u0438\u0441\u043a\u0440\u0438\u043c\u0438\u043d\u0430\u0442\u043e\u0440\u0430, \u0447\u0442\u043e \u0438 <code>DiscountCoupon<\/code>, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u043e\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@JsonSubTypes.Type<\/code>.<\/p>\n<pre><code class=\"java\">public class AmountDiscountCoupon extends DiscountCoupon {       public static final String DISCRIMINATOR = \"discount.coupon.amount\";       private BigDecimal amount;       public AmountDiscountCoupon() {     }       public AmountDiscountCoupon(String name) {         super(name);     }       public BigDecimal getAmount() {         return amount;     }       public AmountDiscountCoupon setAmount(BigDecimal amount) {         this.amount = amount;         return this;     }       @Override     public String getType() {         return DISCRIMINATOR;     } }<\/code><\/pre>\n<p><code>PercentageDiscountCoupon<\/code> \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <code>getType<\/code> \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0442\u043e \u0436\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u0438\u0441\u043a\u0440\u0438\u043c\u0438\u043d\u0430\u0442\u043e\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0439 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0435\u0439 <code>@JsonSubTypes.Type<\/code> \u0432 \u0431\u0430\u0437\u043e\u0432\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 <code>DiscountCoupon<\/code>:<\/p>\n<pre><code class=\"java\">public class PercentageDiscountCoupon extends DiscountCoupon {       public static final String DISCRIMINATOR = \"discount.coupon.percentage\";       private BigDecimal percentage;       public PercentageDiscountCoupon() {     }       public PercentageDiscountCoupon(String name) {         super(name);     }       public BigDecimal getPercentage() {         return percentage;     }       public PercentageDiscountCoupon setPercentage(BigDecimal amount) {         this.percentage = amount;         return this;     }       @Override     public String getType() {         return DISCRIMINATOR;     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c Book \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a <code>JsonType<\/code>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 Java-\u043e\u0431\u044a\u0435\u043a\u0442\u044b <code>DiscountCoupun<\/code> \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u044b Jackson \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0433\u043e \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 <code>@JsonTypeInfo<\/code>:<\/p>\n<pre><code class=\"java\">@Entity(name = \"Book\") @Table(name = \"book\") @TypeDef(name = \"json\", typeClass = JsonType.class) public static class Book {       @Id     @GeneratedValue     private Long id;       @NaturalId     @Column(length = 15)     private String isbn;       @Type(type = \"json\")     @Column(columnDefinition = \"jsonb\")     private List&lt;DiscountCoupon> coupons = new ArrayList&lt;>();       }<\/code><\/pre>\n<p>\u0410 \u043f\u0440\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438 \u0442\u043e\u0439 \u0436\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 Book Hibernate \u0431\u0443\u0434\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 SQL-\u0437\u0430\u043f\u0440\u043e\u0441 <code>INSERT<\/code>:<\/p>\n<pre><code class=\"java\">INSERT INTO book (   coupons,   isbn,   id ) VALUES (   [     {       \"name\":\"PPP\",       \"amount\":4.99,       \"type\":\"discount.coupon.amount\"     },     {       \"name\":\"Black Friday\",       \"percentage\":0.02,       \"type\":\"discount.coupon.percentage\"     }   ],   978-9730228236,   1 )<\/code><\/pre>\n<p>\u041a\u0440\u0443\u0442\u043e, \u043f\u0440\u0430\u0432\u0434\u0430?<\/p>\n<p><strong>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/strong><\/p>\n<p>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0445 JSON-\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442 \u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c Hibernate Types. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432\u044b \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c Jackson <code>ObjectMapper<\/code> \u0442\u0430\u043a, \u043a\u0430\u043a \u0432\u0430\u043c \u0437\u0430\u0445\u043e\u0447\u0435\u0442\u0441\u044f, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0448\u0430\u0442\u044c \u0441\u0430\u043c\u044b\u0435 \u0440\u0430\u0437\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<hr\/>\n<blockquote>\n<p>\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043a\u0443\u0440\u0441\u0430<a href=\"https:\/\/otus.pw\/l4VB\/\"> \u00abJava Developer. Professional\u00bb<\/a>. <\/p>\n<p>\u0412\u0441\u0435\u0445 \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u0445 \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0435\u043c \u043d\u0430 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0435 demo-\u0437\u0430\u043d\u044f\u0442\u0438\u0435 <strong>\u00ab\u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Java Spring Boot\u00bb.<\/strong> \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u0430 \u0432\u0430\u043b\u044e\u0442\u044b. \u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043c \u043e\u0434\u0438\u043d \u0438\u0437 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0440\u0435\u043b\u044c\u0441\u044b. <a href=\"https:\/\/otus.pw\/T15r\/\"><strong>>> \u0420\u0415\u0413\u0418\u0421\u0422\u0420\u0410\u0426\u0418\u042f<\/strong><\/a><\/p>\n<\/blockquote>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/593941\/\"> https:\/\/habr.com\/ru\/articles\/593941\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-410862","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/410862","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=410862"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/410862\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=410862"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=410862"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=410862"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}