Skip to content

Commit

Permalink
Add support for mapping java.util.Date ARRAY or List to PostgreSQL DA…
Browse files Browse the repository at this point in the history
…TE[] and TIMESTAMP[] vladmihalcea#150
  • Loading branch information
Guillaume Briand authored and vladmihalcea committed Dec 9, 2019
1 parent 0895840 commit 9b07dd6
Show file tree
Hide file tree
Showing 32 changed files with 892 additions and 114 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.vladmihalcea.hibernate.type.array;

import com.vladmihalcea.hibernate.type.AbstractHibernateType;
import com.vladmihalcea.hibernate.type.array.internal.ArraySqlTypeDescriptor;
import com.vladmihalcea.hibernate.type.array.internal.DateArrayTypeDescriptor;
import com.vladmihalcea.hibernate.type.util.Configuration;
import org.hibernate.usertype.DynamicParameterizedType;

import java.util.Date;
import java.util.Properties;

/**
* Maps an {@code Date[]} array on a PostgreSQL ARRAY type.
* <p>
* For more details about how to use it, check out <a href="https://vladmihalcea.com/how-to-map-java-and-sql-arrays-with-jpa-and-hibernate/">this article</a> on <a href="https://vladmihalcea.com/">vladmihalcea.com</a>.
*
* @author Guillaume Briand
*/
public class DateArrayType
extends AbstractHibernateType<Date[]>
implements DynamicParameterizedType {

public static final DateArrayType INSTANCE = new DateArrayType();

public DateArrayType() {
super(
ArraySqlTypeDescriptor.INSTANCE,
new DateArrayTypeDescriptor()
);
}

public DateArrayType(Configuration configuration) {
super(
ArraySqlTypeDescriptor.INSTANCE,
new DateArrayTypeDescriptor(), configuration
);
}

public String getName() {
return "date-array";
}

@Override
protected boolean registerUnderJavaType() {
return true;
}

@Override
public void setParameterValues(Properties parameters) {
((DateArrayTypeDescriptor) getJavaTypeDescriptor()).setParameterValues(parameters);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.vladmihalcea.hibernate.type.array;

import com.vladmihalcea.hibernate.type.array.internal.AbstractArrayType;
import com.vladmihalcea.hibernate.type.array.internal.TimestampArrayTypeDescriptor;
import com.vladmihalcea.hibernate.type.util.Configuration;

import java.util.Date;

/**
* Maps an {@code Date[]} array on a PostgreSQL timestamp[] ARRAY type.
* <p>
* For more details about how to use it, check out <a href="https://vladmihalcea.com/how-to-map-java-and-sql-arrays-with-jpa-and-hibernate/">this article</a> on <a href="https://vladmihalcea.com/">vladmihalcea.com</a>.
*
* @author Vlad Mihalcea
*/
public class TimestampArrayType extends AbstractArrayType<Date[]> {

public static final TimestampArrayType INSTANCE = new TimestampArrayType();

public TimestampArrayType() {
super(
new TimestampArrayTypeDescriptor()
);
}

public TimestampArrayType(Configuration configuration) {
super(
new TimestampArrayTypeDescriptor(), configuration
);
}

public String getName() {
return "timestamp-array";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.vladmihalcea.hibernate.type.array.internal;

import java.util.Date;

/**
* @author Guillaume Briand
*/
public class DateArrayTypeDescriptor
extends AbstractArrayTypeDescriptor<Date[]> {

public DateArrayTypeDescriptor() {
super(Date[].class);
}

@Override
protected String getSqlArrayType() {
return "date";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ public void setParameterValues(Properties parameters) {
sqlArrayType = "text";
} else if (UUID.class.isAssignableFrom(arrayElementClass)) {
sqlArrayType = "uuid";
} else if (Date.class.isAssignableFrom(arrayElementClass)) {
sqlArrayType = "timestamp";
} else {
throw new UnsupportedOperationException("The " + arrayElementClass + " is not supported yet!");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.vladmihalcea.hibernate.type.array.internal;

import java.util.Date;

/**
* @author Vlad Mihalcea
*/
public class TimestampArrayTypeDescriptor extends AbstractArrayTypeDescriptor<Date[]> {

public TimestampArrayTypeDescriptor() {
super(Date[].class);
}

@Override
protected String getSqlArrayType() {
return "timestamp";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@
import javax.persistence.EntityManager;
import javax.persistence.Table;
import javax.sql.DataSource;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.fail;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

/**
* @author Vlad Mihalcea
*/
Expand Down Expand Up @@ -93,6 +97,10 @@ public String hibernateDialect() {

@Test
public void test() {

final Date date1 = Timestamp.valueOf("1991-12-31 00:00:00");
final Date date2 = Timestamp.valueOf("1990-01-01 00:00:00");

doInJPA(new JPATransactionFunction<Void>() {

@Override
Expand All @@ -107,7 +115,10 @@ public Void apply(EntityManager entityManager) {
event.setSensorNames(new String[]{"Temperature", "Pressure"});
event.setSensorValues(new int[]{12, 756});
event.setSensorLongValues(new long[]{42L, 9223372036854775800L});
event.setSensorStates(new SensorState[] {SensorState.ONLINE, SensorState.OFFLINE, SensorState.ONLINE, SensorState.UNKNOWN});
event.setSensorStates(new SensorState[]{SensorState.ONLINE, SensorState.OFFLINE, SensorState.ONLINE, SensorState.UNKNOWN});
event.setDateValues(new Date[]{date1, date2});
event.setTimestampValues(new Date[]{date1, date2});

entityManager.persist(event);

return null;
Expand All @@ -124,6 +135,10 @@ public Void apply(EntityManager entityManager) {
assertArrayEquals(new int[]{12, 756}, event.getSensorValues());
assertArrayEquals(new long[]{42L, 9223372036854775800L}, event.getSensorLongValues());
assertArrayEquals(new SensorState[]{SensorState.ONLINE, SensorState.OFFLINE, SensorState.ONLINE, SensorState.UNKNOWN}, event.getSensorStates());
assertEquals(date1.getTime(), event.getDateValues()[0].getTime());
assertEquals(date2.getTime(), event.getDateValues()[1].getTime());
assertEquals(date1.getTime(), event.getTimestampValues()[0].getTime());
assertEquals(date2.getTime(), event.getTimestampValues()[1].getTime());

return null;
}
Expand All @@ -147,12 +162,20 @@ public static class Event extends BaseEntity {
@Type(type = "int-array")
@Column(name = "sensor_values", columnDefinition = "integer[]")
private int[] sensorValues;

@Type(type = "long-array")
@Column(name = "sensor_long_values", columnDefinition = "bigint[]")
private long[] sensorLongValues;

@Type( type = "sensor-state-array")

@Type(type = "date-array")
@Column(name = "date_values", columnDefinition = "date[]")
private Date[] dateValues;

@Type(type = "timestamp-array")
@Column(name = "timestamp_values", columnDefinition = "timestamp[]")
private Date[] timestampValues;

@Type(type = "sensor-state-array")
@Column(name = "sensor_states", columnDefinition = "sensor_state[]")
private SensorState[] sensorStates;

Expand All @@ -179,26 +202,41 @@ public int[] getSensorValues() {
public void setSensorValues(int[] sensorValues) {
this.sensorValues = sensorValues;
}

public long[] getSensorLongValues() {
return sensorLongValues;
}

public void setSensorLongValues(long[] sensorLongValues) {
this.sensorLongValues = sensorLongValues;
}

public SensorState[] getSensorStates() {
return sensorStates;
return sensorStates;
}

public void setSensorStates(SensorState[] sensorStates) {
this.sensorStates = sensorStates;
this.sensorStates = sensorStates;
}

public Date[] getDateValues() {
return dateValues;
}

public void setDateValues(Date[] dateValues) {
this.dateValues = dateValues;
}

public Date[] getTimestampValues() {
return timestampValues;
}

public void setTimestampValues(Date[] timestampValues) {
this.timestampValues = timestampValues;
}
}

public enum SensorState {
ONLINE, OFFLINE, UNKNOWN;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

Expand Down Expand Up @@ -94,6 +96,10 @@ public String hibernateDialect() {

@Test
public void test() {

final Date date1 = Timestamp.valueOf("1991-12-31 00:00:00");
final Date date2 = Timestamp.valueOf("1990-01-01 00:00:00");

doInJPA(new JPATransactionFunction<Void>() {

@Override
Expand All @@ -109,6 +115,8 @@ public Void apply(EntityManager entityManager) {
event.setSensorValues(Arrays.asList(12, 756));
event.setSensorLongValues(Arrays.asList(42L, 9223372036854775800L));
event.setSensorStates(Arrays.asList(SensorState.ONLINE, SensorState.OFFLINE, SensorState.ONLINE, SensorState.UNKNOWN));
event.setDateValues(Arrays.asList(date1, date2));
event.setTimestampValues(Arrays.asList(date1, date2));

entityManager.persist(event);

Expand All @@ -127,6 +135,10 @@ public Void apply(EntityManager entityManager) {
assertArrayEquals(new Integer[]{12, 756}, event.getSensorValues().toArray());
assertArrayEquals(new Long[]{42L, 9223372036854775800L}, event.getSensorLongValues().toArray());
assertArrayEquals(new SensorState[]{SensorState.ONLINE, SensorState.OFFLINE, SensorState.ONLINE, SensorState.UNKNOWN}, event.getSensorStates().toArray());
assertEquals(date1.getTime(), event.getDateValues().get(0).getTime());
assertEquals(date2.getTime(), event.getDateValues().get(1).getTime());
assertEquals(date1.getTime(), event.getTimestampValues().get(0).getTime());
assertEquals(date2.getTime(), event.getTimestampValues().get(1).getTime());

return null;
}
Expand Down Expand Up @@ -163,10 +175,11 @@ public Void apply(EntityManager entityManager) {
@TypeDef(name = "string-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "int-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "long-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "date-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "timestamp-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "sensor-state-array", typeClass = ListArrayType.class, parameters = {
@Parameter(name = ListArrayType.SQL_ARRAY_TYPE, value = "sensor_state")}
)

})
@Table(name = "event")
public static class Event extends BaseEntity {
Expand All @@ -190,6 +203,14 @@ public static class Event extends BaseEntity {
@Column(name = "sensor_states", columnDefinition = "sensor_state[]")
private List<SensorState> sensorStates;

@Type(type = "date-list-array")
@Column(name = "date_values", columnDefinition = "date[]")
private List<Date> dateValues;

@Type(type = "timestamp-list-array")
@Column(name = "timestamp_values", columnDefinition = "timestamp[]")
private List<Date> timestampValues;

public List<UUID> getSensorIds() {
return sensorIds;
}
Expand Down Expand Up @@ -229,6 +250,22 @@ public List<SensorState> getSensorStates() {
public void setSensorStates(List<SensorState> sensorStates) {
this.sensorStates = sensorStates;
}

public List<Date> getDateValues() {
return dateValues;
}

public void setDateValues(List<Date> dateValues) {
this.dateValues = dateValues;
}

public List<Date> getTimestampValues() {
return timestampValues;
}

public void setTimestampValues(List<Date> timestampValues) {
this.timestampValues = timestampValues;
}
}

public enum SensorState {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package com.vladmihalcea.hibernate.type.model;

import com.vladmihalcea.hibernate.type.array.IntArrayType;
import com.vladmihalcea.hibernate.type.array.LongArrayType;
import com.vladmihalcea.hibernate.type.array.StringArrayType;
import com.vladmihalcea.hibernate.type.array.UUIDArrayType;
import com.vladmihalcea.hibernate.type.array.*;
import com.vladmihalcea.hibernate.type.json.JsonNodeBinaryType;
import com.vladmihalcea.hibernate.type.json.JsonNodeStringType;

import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;

Expand All @@ -18,12 +14,14 @@
* @author Vlad Mihalcea
*/
@TypeDefs({
@TypeDef(name = "uuid-array", typeClass = UUIDArrayType.class),
@TypeDef(name = "string-array", typeClass = StringArrayType.class),
@TypeDef(name = "int-array", typeClass = IntArrayType.class),
@TypeDef(name = "long-array", typeClass = LongArrayType.class),
@TypeDef(name = "jsonb-node", typeClass = JsonNodeBinaryType.class),
@TypeDef(name = "json-node", typeClass = JsonNodeStringType.class),
@TypeDef(name = "uuid-array", typeClass = UUIDArrayType.class),
@TypeDef(name = "string-array", typeClass = StringArrayType.class),
@TypeDef(name = "int-array", typeClass = IntArrayType.class),
@TypeDef(name = "long-array", typeClass = LongArrayType.class),
@TypeDef(name = "date-array", typeClass = DateArrayType.class),
@TypeDef(name = "timestamp-array", typeClass = TimestampArrayType.class),
@TypeDef(name = "jsonb-node", typeClass = JsonNodeBinaryType.class),
@TypeDef(name = "json-node", typeClass = JsonNodeStringType.class)
})
@MappedSuperclass
public class BaseEntity {
Expand Down
Loading

0 comments on commit 9b07dd6

Please sign in to comment.