diff --git a/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/util/ObjectMapperWrapper.java b/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/util/ObjectMapperWrapper.java index a60e140a1..6a57d729b 100644 --- a/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/util/ObjectMapperWrapper.java +++ b/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/util/ObjectMapperWrapper.java @@ -1,12 +1,17 @@ package com.vladmihalcea.hibernate.type.util; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.module.SimpleModule; import org.hibernate.HibernateException; import java.io.IOException; import java.lang.reflect.Type; +import java.time.OffsetDateTime; + +import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME; /** * Wraps a Jackson {@link ObjectMapper} so that you can supply your own {@link ObjectMapper} reference. @@ -23,7 +28,14 @@ public class ObjectMapperWrapper { private JsonSerializer jsonSerializer; public ObjectMapperWrapper() { - this(new ObjectMapper().findAndRegisterModules()); + this(new ObjectMapper() + .findAndRegisterModules() + .registerModule( + new SimpleModule() + .addSerializer(OffsetDateTime.class, OffsetDateTimeSerializer.INSTANCE) + .addDeserializer(OffsetDateTime.class, OffsetDateTimeDeserializer.INSTANCE) + ) + ); } public ObjectMapperWrapper(ObjectMapper objectMapper) { @@ -112,4 +124,41 @@ public JsonNode toJsonNode(String value) { public T clone(T value) { return jsonSerializer.clone(value); } + + public static class OffsetDateTimeSerializer extends com.fasterxml.jackson.databind.JsonSerializer { + + public static final OffsetDateTimeSerializer INSTANCE = new OffsetDateTimeSerializer(); + + @Override + public void serialize(OffsetDateTime offsetDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + if (offsetDateTime == null) { + jsonGenerator.writeNull(); + } else { + jsonGenerator.writeString(offsetDateTime.format(ISO_OFFSET_DATE_TIME)); + } + } + + @Override + public Class handledType() { + return OffsetDateTime.class; + } + } + + public static class OffsetDateTimeDeserializer extends JsonDeserializer { + + public static final OffsetDateTimeDeserializer INSTANCE = new OffsetDateTimeDeserializer(); + + @Override + public OffsetDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + if (jsonParser.getText() != null) { + return OffsetDateTime.parse(jsonParser.getText(), ISO_OFFSET_DATE_TIME); + } + return null; + } + + @Override + public Class handledType() { + return OffsetDateTime.class; + } + } } diff --git a/hibernate-types-52/src/test/java/com/vladmihalcea/hibernate/type/json/OffsetDateTimeJsonTest.java b/hibernate-types-52/src/test/java/com/vladmihalcea/hibernate/type/json/OffsetDateTimeJsonTest.java new file mode 100644 index 000000000..ae7403949 --- /dev/null +++ b/hibernate-types-52/src/test/java/com/vladmihalcea/hibernate/type/json/OffsetDateTimeJsonTest.java @@ -0,0 +1,122 @@ +package com.vladmihalcea.hibernate.type.json; + +import com.vladmihalcea.hibernate.util.AbstractPostgreSQLIntegrationTest; +import org.hibernate.annotations.TypeDef; +import org.junit.Test; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import static org.junit.Assert.assertEquals; + +/** + * @author Vlad Mihalcea + */ +public class OffsetDateTimeJsonTest extends AbstractPostgreSQLIntegrationTest { + + @Override + protected Class[] entities() { + return new Class[]{ + Event.class, + }; + } + + @Test + public void test() { + OffsetDateTime dateTime = OffsetDateTime.of(2015, 10, 1, 9, 0 , 0, 0, ZoneOffset.ofHours(2)); + + doInJPA(entityManager -> { + Location location = new Location(); + location.setCountry("Romania"); + location.setCity("Cluj-Napoca"); + location.setRentedAt(dateTime); + + Event event = new Event(); + event.setId(1L); + event.setLocation(location); + entityManager.persist(event); + }); + + doInJPA(entityManager -> { + Event event = entityManager.find(Event.class, 1L); + assertEquals(dateTime, event.getLocation().getRentedAt()); + }); + } + + @Entity(name = "Event") + @Table(name = "event") + @TypeDef(defaultForType = Location.class, typeClass = JsonType.class) + public static class Event { + + @Id + private Long id; + + @Column(columnDefinition = "jsonb") + private Location location; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } + } + + public static class Location implements Serializable { + + private String country; + + private String city; + + private BigDecimal reference; + + private OffsetDateTime rentedAt; + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public BigDecimal getReference() { + return reference; + } + + public void setReference(BigDecimal reference) { + this.reference = reference; + } + + public OffsetDateTime getRentedAt() { + return rentedAt; + } + + public void setRentedAt(OffsetDateTime rentedAt) { + this.rentedAt = rentedAt; + } + } +} diff --git a/hibernate-types-55/src/main/java/com/vladmihalcea/hibernate/type/util/ObjectMapperWrapper.java b/hibernate-types-55/src/main/java/com/vladmihalcea/hibernate/type/util/ObjectMapperWrapper.java index a60e140a1..6a57d729b 100644 --- a/hibernate-types-55/src/main/java/com/vladmihalcea/hibernate/type/util/ObjectMapperWrapper.java +++ b/hibernate-types-55/src/main/java/com/vladmihalcea/hibernate/type/util/ObjectMapperWrapper.java @@ -1,12 +1,17 @@ package com.vladmihalcea.hibernate.type.util; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.module.SimpleModule; import org.hibernate.HibernateException; import java.io.IOException; import java.lang.reflect.Type; +import java.time.OffsetDateTime; + +import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME; /** * Wraps a Jackson {@link ObjectMapper} so that you can supply your own {@link ObjectMapper} reference. @@ -23,7 +28,14 @@ public class ObjectMapperWrapper { private JsonSerializer jsonSerializer; public ObjectMapperWrapper() { - this(new ObjectMapper().findAndRegisterModules()); + this(new ObjectMapper() + .findAndRegisterModules() + .registerModule( + new SimpleModule() + .addSerializer(OffsetDateTime.class, OffsetDateTimeSerializer.INSTANCE) + .addDeserializer(OffsetDateTime.class, OffsetDateTimeDeserializer.INSTANCE) + ) + ); } public ObjectMapperWrapper(ObjectMapper objectMapper) { @@ -112,4 +124,41 @@ public JsonNode toJsonNode(String value) { public T clone(T value) { return jsonSerializer.clone(value); } + + public static class OffsetDateTimeSerializer extends com.fasterxml.jackson.databind.JsonSerializer { + + public static final OffsetDateTimeSerializer INSTANCE = new OffsetDateTimeSerializer(); + + @Override + public void serialize(OffsetDateTime offsetDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + if (offsetDateTime == null) { + jsonGenerator.writeNull(); + } else { + jsonGenerator.writeString(offsetDateTime.format(ISO_OFFSET_DATE_TIME)); + } + } + + @Override + public Class handledType() { + return OffsetDateTime.class; + } + } + + public static class OffsetDateTimeDeserializer extends JsonDeserializer { + + public static final OffsetDateTimeDeserializer INSTANCE = new OffsetDateTimeDeserializer(); + + @Override + public OffsetDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + if (jsonParser.getText() != null) { + return OffsetDateTime.parse(jsonParser.getText(), ISO_OFFSET_DATE_TIME); + } + return null; + } + + @Override + public Class handledType() { + return OffsetDateTime.class; + } + } } diff --git a/hibernate-types-55/src/test/java/com/vladmihalcea/hibernate/type/json/OffsetDateTimeJsonTest.java b/hibernate-types-55/src/test/java/com/vladmihalcea/hibernate/type/json/OffsetDateTimeJsonTest.java new file mode 100644 index 000000000..ae7403949 --- /dev/null +++ b/hibernate-types-55/src/test/java/com/vladmihalcea/hibernate/type/json/OffsetDateTimeJsonTest.java @@ -0,0 +1,122 @@ +package com.vladmihalcea.hibernate.type.json; + +import com.vladmihalcea.hibernate.util.AbstractPostgreSQLIntegrationTest; +import org.hibernate.annotations.TypeDef; +import org.junit.Test; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import static org.junit.Assert.assertEquals; + +/** + * @author Vlad Mihalcea + */ +public class OffsetDateTimeJsonTest extends AbstractPostgreSQLIntegrationTest { + + @Override + protected Class[] entities() { + return new Class[]{ + Event.class, + }; + } + + @Test + public void test() { + OffsetDateTime dateTime = OffsetDateTime.of(2015, 10, 1, 9, 0 , 0, 0, ZoneOffset.ofHours(2)); + + doInJPA(entityManager -> { + Location location = new Location(); + location.setCountry("Romania"); + location.setCity("Cluj-Napoca"); + location.setRentedAt(dateTime); + + Event event = new Event(); + event.setId(1L); + event.setLocation(location); + entityManager.persist(event); + }); + + doInJPA(entityManager -> { + Event event = entityManager.find(Event.class, 1L); + assertEquals(dateTime, event.getLocation().getRentedAt()); + }); + } + + @Entity(name = "Event") + @Table(name = "event") + @TypeDef(defaultForType = Location.class, typeClass = JsonType.class) + public static class Event { + + @Id + private Long id; + + @Column(columnDefinition = "jsonb") + private Location location; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } + } + + public static class Location implements Serializable { + + private String country; + + private String city; + + private BigDecimal reference; + + private OffsetDateTime rentedAt; + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public BigDecimal getReference() { + return reference; + } + + public void setReference(BigDecimal reference) { + this.reference = reference; + } + + public OffsetDateTime getRentedAt() { + return rentedAt; + } + + public void setRentedAt(OffsetDateTime rentedAt) { + this.rentedAt = rentedAt; + } + } +}