From f2816c505ebfe2ed964bced26982c3b5bed96277 Mon Sep 17 00:00:00 2001
From: Tor-Einar Skog <tor-einar.skog@nibio.no>
Date: Thu, 4 Jan 2024 10:29:26 +0000
Subject: [PATCH] Revert "Non-functioning commit of Hibernate upgrade
 adaptations"

This reverts commit 63b94469328427ee6cca96006d6707a8f6b3298b
---
 pom.xml                                       |   1 +
 .../nibio/vips/logic/entity/CropCategory.java |   7 +-
 .../no/nibio/vips/logic/entity/CropPest.java  |   7 +-
 .../logic/entity/ForecastConfiguration.java   |  10 +-
 .../no/nibio/vips/logic/entity/Message.java   |   8 +-
 .../nibio/vips/logic/entity/Observation.java  |   8 +-
 .../nibio/vips/logic/entity/UserUuidPK.java   |   1 +
 ...ForecastEventNotificationSubscription.java |   9 +-
 .../MessageNotificationSubscription.java      |  10 +-
 .../ObservationNotificationSubscription.java  |   7 +-
 .../logic/messaging/UniversalMessage.java     |  10 +-
 .../vips/logic/util/IntegerArrayUserType.java | 215 ++++++++++++++----
 .../logic/util/JsonPostgreSQLDialect.java     |  35 +++
 .../vips/logic/util/StringJsonUserType.java   | 169 ++++++++++----
 .../ObservationDataSchema.java                |  11 +-
 src/main/resources/META-INF/persistence.xml   |   6 +-
 16 files changed, 402 insertions(+), 112 deletions(-)
 create mode 100755 src/main/java/no/nibio/vips/logic/util/JsonPostgreSQLDialect.java

diff --git a/pom.xml b/pom.xml
index dc89bad7..22b57e70 100755
--- a/pom.xml
+++ b/pom.xml
@@ -171,6 +171,7 @@
                 </exclusion>
             </exclusions>
         </dependency>
+
         <dependency>
             <groupId>org.postgresql</groupId>
             <artifactId>postgresql</artifactId>
diff --git a/src/main/java/no/nibio/vips/logic/entity/CropCategory.java b/src/main/java/no/nibio/vips/logic/entity/CropCategory.java
index c1c588f7..43cc4587 100755
--- a/src/main/java/no/nibio/vips/logic/entity/CropCategory.java
+++ b/src/main/java/no/nibio/vips/logic/entity/CropCategory.java
@@ -26,7 +26,6 @@ import java.util.Set;
 import javax.persistence.Basic;
 import javax.persistence.CascadeType;
 import javax.persistence.Column;
-import javax.persistence.Convert;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.Id;
@@ -38,6 +37,9 @@ import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
 import javax.xml.bind.annotation.XmlRootElement;
 import no.nibio.vips.logic.util.IntegerArrayUserType;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
 
 /**
  * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
@@ -46,6 +48,7 @@ import no.nibio.vips.logic.util.IntegerArrayUserType;
 @Entity
 @Table(name = "crop_category")
 @XmlRootElement
+@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)})
 @NamedQueries({
     @NamedQuery(name = "CropCategory.findAll", query = "SELECT c FROM CropCategory c"),
     @NamedQuery(name = "CropCategory.findByCropCategoryId", query = "SELECT c FROM CropCategory c WHERE c.cropCategoryId = :cropCategoryId"),
@@ -67,7 +70,7 @@ public class CropCategory implements Serializable {
     private String defaultName;
     @OneToMany(cascade = CascadeType.ALL, mappedBy = "cropCategoryId", fetch = FetchType.EAGER)
     private Set<CropCategoryLocal> cropCategoryLocalSet;
-    @Convert(converter = IntegerArrayUserType.class)
+    @Type(type = "IntegerArray")
     @Column(name = "crop_organism_ids")
     private Integer[] cropOrganismIds;
     @Column(name = "organization_id")
diff --git a/src/main/java/no/nibio/vips/logic/entity/CropPest.java b/src/main/java/no/nibio/vips/logic/entity/CropPest.java
index 9ba62175..0443494b 100755
--- a/src/main/java/no/nibio/vips/logic/entity/CropPest.java
+++ b/src/main/java/no/nibio/vips/logic/entity/CropPest.java
@@ -21,7 +21,6 @@ package no.nibio.vips.logic.entity;
 import java.io.Serializable;
 import javax.persistence.Basic;
 import javax.persistence.Column;
-import javax.persistence.Convert;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.NamedQueries;
@@ -30,6 +29,9 @@ import javax.persistence.Table;
 import javax.validation.constraints.NotNull;
 import javax.xml.bind.annotation.XmlRootElement;
 import no.nibio.vips.logic.util.IntegerArrayUserType;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
 
 /**
  * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
@@ -37,6 +39,7 @@ import no.nibio.vips.logic.util.IntegerArrayUserType;
  */
 @Entity
 @Table(name = "crop_pest")
+@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)})
 @XmlRootElement
 @NamedQueries({
     @NamedQuery(name = "CropPest.findAll", query = "SELECT c FROM CropPest c"),
@@ -52,7 +55,7 @@ public class CropPest implements Serializable {
     @NotNull
     @Column(name = "crop_organism_id")
     private Integer cropOrganismId;
-    @Convert(converter = IntegerArrayUserType.class)
+    @Type(type = "IntegerArray")
     @Column(name = "pest_organism_ids")
     private Integer[] pestOrganismIds;
     @Column(name = "include_all_child_crops")
diff --git a/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java b/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java
index 57f09f87..a17f2fba 100755
--- a/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java
+++ b/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java
@@ -42,10 +42,13 @@ import javax.xml.bind.annotation.XmlTransient;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import java.util.List;
 import java.util.TimeZone;
-import javax.persistence.Convert;
 import javax.persistence.Transient;
 import no.nibio.vips.logic.util.IntegerArrayUserType;
 import no.nibio.vips.util.WeatherUtil;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
+
 /**
  * @copyright 2014-2016 <a href="http://www.nibio.no/">NIBIO</a>
  * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
@@ -53,6 +56,7 @@ import no.nibio.vips.util.WeatherUtil;
 @Entity
 @Table(name = "forecast_configuration")
 @XmlRootElement
+@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)})
 @NamedQueries({
     @NamedQuery(name = "ForecastConfiguration.findAll", query = "SELECT f FROM ForecastConfiguration f WHERE f.isPrivate = FALSE"),
     @NamedQuery(name = "ForecastConfiguration.findByForecastConfigurationId", query = "SELECT f FROM ForecastConfiguration f WHERE f.forecastConfigurationId = :forecastConfigurationId"),
@@ -81,8 +85,6 @@ import no.nibio.vips.util.WeatherUtil;
     @NamedQuery(name = "ForecastConfiguration.findByModelIdAndYear", query = "SELECT f FROM ForecastConfiguration f WHERE f.modelId = :modelId AND YEAR(f.dateStart) <= :year AND YEAR(f.dateEnd) >= :year AND f.isPrivate = FALSE")
 })
 public class ForecastConfiguration implements Serializable, Comparable {
-    
-    
     @OneToMany(cascade = CascadeType.ALL, mappedBy = "forecastConfiguration", fetch = FetchType.EAGER)
     private Set<ForecastModelConfiguration> forecastModelConfigurationSet;
     private static final long serialVersionUID = 1L;
@@ -122,7 +124,7 @@ public class ForecastConfiguration implements Serializable, Comparable {
     @Column(name = "is_private")
     private Boolean isPrivate;
     
-    @Convert(converter = IntegerArrayUserType.class)
+    @Type(type = "IntegerArray")
     @Column(name = "grid_weather_station_point_of_interest_ids")
     private Integer[] gridWeatherStationPointOfInterestIds;
     
diff --git a/src/main/java/no/nibio/vips/logic/entity/Message.java b/src/main/java/no/nibio/vips/logic/entity/Message.java
index 72cfa793..1bd92c60 100755
--- a/src/main/java/no/nibio/vips/logic/entity/Message.java
+++ b/src/main/java/no/nibio/vips/logic/entity/Message.java
@@ -27,7 +27,6 @@ import java.util.Set;
 import javax.persistence.Basic;
 import javax.persistence.CascadeType;
 import javax.persistence.Column;
-import javax.persistence.Convert;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
@@ -45,7 +44,9 @@ import javax.persistence.TemporalType;
 import javax.persistence.Transient;
 import javax.xml.bind.annotation.XmlRootElement;
 import no.nibio.vips.logic.util.IntegerArrayUserType;
-
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
 
 /**
  * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a>
@@ -54,6 +55,7 @@ import no.nibio.vips.logic.util.IntegerArrayUserType;
 @Entity
 @Table(name = "message")
 @XmlRootElement
+@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)})
 @NamedQueries({
     @NamedQuery(name = "Message.findAll", query = "SELECT m FROM Message m"),
     @NamedQuery(name = "Message.findByMessageId", query = "SELECT m FROM Message m WHERE m.messageId = :messageId"),
@@ -274,7 +276,7 @@ public class Message implements Serializable {
     /**
      * @return the cropCategoryIds
      */
-    @Convert(converter = IntegerArrayUserType.class)
+    @Type(type = "IntegerArray")
     @Column(name="crop_category_ids")
     public Integer[] getCropCategoryIds() {
         return cropCategoryIds;
diff --git a/src/main/java/no/nibio/vips/logic/entity/Observation.java b/src/main/java/no/nibio/vips/logic/entity/Observation.java
index f380af92..54fbc58b 100755
--- a/src/main/java/no/nibio/vips/logic/entity/Observation.java
+++ b/src/main/java/no/nibio/vips/logic/entity/Observation.java
@@ -42,7 +42,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import javax.persistence.CascadeType;
-import javax.persistence.Convert;
 import javax.persistence.FetchType;
 import javax.persistence.OneToMany;
 import javax.validation.constraints.Size;
@@ -51,7 +50,9 @@ import no.nibio.vips.gis.GISUtil;
 import no.nibio.vips.logic.entity.rest.ObservationListItem;
 import no.nibio.vips.logic.util.StringJsonUserType;
 import no.nibio.vips.observationdata.ObservationDataSchema;
-
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
 
 /**
  * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
@@ -60,6 +61,7 @@ import no.nibio.vips.observationdata.ObservationDataSchema;
 @Entity
 @Table(name = "observation")
 @XmlRootElement
+@TypeDefs( {@TypeDef( name= "StringJsonObject", typeClass = StringJsonUserType.class)})
 @NamedQueries({
     @NamedQuery(name = "Observation.findAll", query = "SELECT o FROM Observation o"),
     @NamedQuery(name = "Observation.findByObservationId", query = "SELECT o FROM Observation o WHERE o.observationId = :observationId"),
@@ -438,7 +440,7 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse
     /**
      * @return the observationData
      */
-    @Convert(converter = StringJsonUserType.class)
+    @Type(type = "StringJsonObject")
     @Column(name = "observation_data")
     @Override
     public String getObservationData() {
diff --git a/src/main/java/no/nibio/vips/logic/entity/UserUuidPK.java b/src/main/java/no/nibio/vips/logic/entity/UserUuidPK.java
index d48b5028..9168cdfb 100755
--- a/src/main/java/no/nibio/vips/logic/entity/UserUuidPK.java
+++ b/src/main/java/no/nibio/vips/logic/entity/UserUuidPK.java
@@ -34,6 +34,7 @@ public class UserUuidPK implements Serializable {
     @Basic(optional = false)
     @NotNull
     @Column(name = "user_uuid")
+    @org.hibernate.annotations.Type(type="pg-uuid") // Ugly implementation specific hack
     private UUID userUuid;
     @Basic(optional = false)
     @NotNull
diff --git a/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java b/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java
index 46d7b874..157953ea 100755
--- a/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java
+++ b/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java
@@ -21,11 +21,13 @@ package no.nibio.vips.logic.messaging;
 import java.util.List;
 import javax.persistence.Basic;
 import javax.persistence.Column;
-import javax.persistence.Convert;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.Table;
 import no.nibio.vips.logic.util.IntegerArrayUserType;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
 
 /**
  * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
@@ -33,6 +35,7 @@ import no.nibio.vips.logic.util.IntegerArrayUserType;
  */
 @Entity
 @Table(name = "forecast_event_notification_subscription", schema = "messaging")
+@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)})
 public class ForecastEventNotificationSubscription {
 
     @Id
@@ -43,11 +46,11 @@ public class ForecastEventNotificationSubscription {
     @Column(name = "universal_message_format_id")
     private Integer universalMessageFormatId;
     
-    @Convert(converter = IntegerArrayUserType.class)
+    @Type(type = "IntegerArray")
     @Column(name = "weather_station_ids")
     private Integer[] weatherStationIds;
     
-    @Convert(converter = IntegerArrayUserType.class)
+    @Type(type = "IntegerArray")
     @Column(name = "crop_category_ids")
     private Integer[] cropCategoryIds;
 
diff --git a/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java b/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java
index ee56bbd5..2231f3b1 100755
--- a/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java
+++ b/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java
@@ -22,12 +22,13 @@ import java.io.Serializable;
 import java.util.List;
 import javax.persistence.Basic;
 import javax.persistence.Column;
-import javax.persistence.Convert;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.Table;
 import no.nibio.vips.logic.util.IntegerArrayUserType;
-
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
 
 /**
  * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
@@ -35,6 +36,7 @@ import no.nibio.vips.logic.util.IntegerArrayUserType;
  */
 @Entity
 @Table(name = "message_notification_subscription", schema = "messaging")
+@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)})
 public class MessageNotificationSubscription implements Serializable {
 
     @Id
@@ -45,11 +47,11 @@ public class MessageNotificationSubscription implements Serializable {
     @Column(name = "universal_message_format_id")
     private Integer universalMessageFormatId;
     
-    @Convert(converter = IntegerArrayUserType.class)
+    @Type(type = "IntegerArray")
     @Column(name = "message_tag_ids")
     private Integer[] messageTagIds;
     
-    @Convert(converter = IntegerArrayUserType.class)
+    @Type(type = "IntegerArray")
     @Column(name = "crop_category_ids")
     private Integer[] cropCategoryIds;
 
diff --git a/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java b/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java
index f4e41029..7df24d95 100755
--- a/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java
+++ b/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java
@@ -22,11 +22,13 @@ import java.io.Serializable;
 import java.util.List;
 import javax.persistence.Basic;
 import javax.persistence.Column;
-import javax.persistence.Convert;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.Table;
 import no.nibio.vips.logic.util.IntegerArrayUserType;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
 
 /**
  * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
@@ -34,6 +36,7 @@ import no.nibio.vips.logic.util.IntegerArrayUserType;
  */
 @Entity
 @Table(name = "observation_notification_subscription", schema = "messaging")
+@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)})
 public class ObservationNotificationSubscription implements Serializable {
 
     @Id
@@ -44,7 +47,7 @@ public class ObservationNotificationSubscription implements Serializable {
     @Column(name = "universal_message_format_id")
     private Integer universalMessageFormatId;
     
-    @Convert(converter = IntegerArrayUserType.class)
+    @Type(type = "IntegerArray")
     @Column(name = "crop_category_ids")
     private Integer[] cropCategoryIds;
 
diff --git a/src/main/java/no/nibio/vips/logic/messaging/UniversalMessage.java b/src/main/java/no/nibio/vips/logic/messaging/UniversalMessage.java
index 8b6e704e..db8020bf 100755
--- a/src/main/java/no/nibio/vips/logic/messaging/UniversalMessage.java
+++ b/src/main/java/no/nibio/vips/logic/messaging/UniversalMessage.java
@@ -46,9 +46,10 @@ import javax.persistence.Transient;
 import javax.xml.bind.annotation.XmlRootElement;
 
 import com.ibm.icu.util.ULocale;
-import javax.persistence.Convert;
 import no.nibio.vips.logic.util.StringJsonUserType;
-
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
 
 /**
  * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
@@ -57,6 +58,7 @@ import no.nibio.vips.logic.util.StringJsonUserType;
 @Entity
 @Table(name = "universal_message", schema = "messaging")
 @XmlRootElement
+@TypeDefs( {@TypeDef( name= "StringJsonObject", typeClass = StringJsonUserType.class)})
 @NamedQueries({
     @NamedQuery(name = "UniversalMessage.findAll", query = "SELECT u FROM UniversalMessage u"),
     @NamedQuery(name = "UniversalMessage.findByUniversalMessageId", query = "SELECT u FROM UniversalMessage u WHERE u.universalMessageId = :universalMessageId"),
@@ -74,11 +76,11 @@ public class UniversalMessage implements Serializable {
     //@Column(name = "distribution_list", columnDefinition = "json")
     //@Convert(converter = PostgresJSONStringConverter.class)
     // Documentation on StackOverflow: http://stackoverflow.com/questions/15974474/mapping-postgresql-json-column-to-hibernate-value-type
-    @Convert(converter = StringJsonUserType.class)
+    @Type(type = "StringJsonObject")
     @Column(name = "distribution_list")
     private String distributionList;
     
-    @Convert(converter = StringJsonUserType.class)
+    @Type(type = "StringJsonObject")
     @Column(name = "message_local_versions")
     private String messageLocalVersions;
     
diff --git a/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java b/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java
index ef99793a..94ea3338 100755
--- a/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java
+++ b/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java
@@ -24,7 +24,6 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Types;
-import java.util.Arrays;
 import org.hibernate.HibernateException;
 import org.hibernate.engine.spi.SessionImplementor;
 import org.hibernate.engine.spi.SharedSessionContractImplementor;
@@ -36,41 +35,41 @@ import org.hibernate.usertype.UserType;
  * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
  */
 
-public class IntegerArrayUserType implements UserType<Integer[]> {
+public class IntegerArrayUserType implements UserType {
 
-    public IntegerArrayUserType()
-    {
-        super();
+    /**
+     * Return the SQL type codes for the columns mapped by this type. The
+     * codes are defined on <tt>java.sql.Types</tt>.
+     *
+     * @return int[] the typecodes
+     * @see java.sql.Types
+     */
+    @Override
+    public int[] sqlTypes() {
+        return new int[] { Types.ARRAY };
     }
+
     /**
      * The class returned by <tt>nullSafeGet()</tt>.
      *
      * @return Class
      */
     @Override
-    public Class<Integer[]> returnedClass() {
+    public Class returnedClass() {
         return Integer[].class;
     }
 
-
     /**
-     * Are objects of this type mutable?
+     * Compare two instances of the class mapped by this type for persistence "equality".
+     * Equality of the persistent state.
      *
+     * @param x
+     * @param y
      * @return boolean
      */
     @Override
-    public boolean isMutable() {
-        return true;
-    }
-
-    
-    @Override
-    public int getSqlType() {
-        return Types.ARRAY;
-    }
+    public boolean equals(Object x, Object y) throws HibernateException {
 
-    @Override
-    public boolean equals(Integer[] x, Integer[] y) {
         if( x== null){
 
             return y== null;
@@ -79,41 +78,163 @@ public class IntegerArrayUserType implements UserType<Integer[]> {
         return x.equals( y);
     }
 
+    /**
+     * Get a hashcode for the instance, consistent with persistence "equality"
+     */
     @Override
-    public int hashCode(Integer[] j) {
-        return Arrays.hashCode(j);
+    public int hashCode(Object x) throws HibernateException {
+
+        return x.hashCode();
     }
 
-    @Override
-    public void nullSafeSet(PreparedStatement ps, Integer[] j, int i, SharedSessionContractImplementor ssci) throws SQLException {
-         if (j == null) {
-            ps.setNull(i, Types.OTHER);
+    /**
+     * Retrieve an instance of the mapped class from a JDBC resultset. Implementors
+     * should handle possibility of null values.
+     *
+     * @param rs      a JDBC result set
+     * @param names   the column names
+     * @param session
+     * @param owner   the containing entity  @return Object
+     * @throws org.hibernate.HibernateException
+     *
+     * @throws java.sql.SQLException
+     */
+    //@Override
+    public Object nullSafeGet(
+            ResultSet rs, 
+            String[] names, 
+            SessionImplementor session, 
+            Object owner) throws HibernateException, SQLException {
+       if (rs.wasNull()) {
+        return null;
+    }
+
+       try
+       {
+        Integer[] array = (Integer[]) rs.getArray(names[0]).getArray();
+        return array;
+       }
+       catch(NullPointerException ex)
+       {
+           return new Integer[0];
+       }
+    }
+
+    /**
+     * Write an instance of the mapped class to a prepared statement. Implementors
+     * should handle possibility of null values. A multi-column type should be written
+     * to parameters starting from <tt>index</tt>.
+     *
+     * @param st      a JDBC prepared statement
+     * @param value   the object to write
+     * @param index   statement parameter index
+     * @param session
+     * @throws org.hibernate.HibernateException
+     *
+     * @throws java.sql.SQLException
+     */
+    //@Override
+    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
+        if (value == null) {
+            st.setNull(index, Types.OTHER);
             return;
         }
 
-        Integer[] castObject = (Integer[]) j;
-        Array array = ssci.getJdbcConnectionAccess().obtainConnection().createArrayOf("integer", castObject); // The postgres array data type
-        ps.setArray(i, array);
+        Integer[] castObject = (Integer[]) value;
+        Array array = session.connection().createArrayOf("integer", castObject); // The postgres array data type
+        st.setArray(index, array);
+    }
+
+    /**
+     * Return a deep copy of the persistent state, stopping at entities and at
+     * collections. It is not necessary to copy immutable objects, or null
+     * values, in which case it is safe to simply return the argument.
+     *
+     * @param value the object to be cloned, which may be null
+     * @return Object a copy
+     */
+    @Override
+    public Object deepCopy(Object value) throws HibernateException {
+
+        return value;
     }
 
+    /**
+     * Are objects of this type mutable?
+     *
+     * @return boolean
+     */
     @Override
-    public Integer[] deepCopy(Integer[] j) {
-        return j;
+    public boolean isMutable() {
+        return true;
     }
 
+    /**
+     * Transform the object into its cacheable representation. At the very least this
+     * method should perform a deep copy if the type is mutable. That may not be enough
+     * for some implementations, however; for example, associations must be cached as
+     * identifier values. (optional operation)
+     *
+     * @param value the object to be cached
+     * @return a cachable representation of the object
+     * @throws org.hibernate.HibernateException
+     *
+     */
     @Override
-    public Serializable disassemble(Integer[] j) {
-        throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
+    public Serializable disassemble(Object value) throws HibernateException {
+        return (Integer[])this.deepCopy( value);
     }
 
+    /**
+     * Reconstruct an object from the cacheable representation. At the very least this
+     * method should perform a deep copy if the type is mutable. (optional operation)
+     *
+     * @param cached the object to be cached
+     * @param owner  the owner of the cached object
+     * @return a reconstructed object from the cachable representation
+     * @throws org.hibernate.HibernateException
+     *
+     */
     @Override
-    public Integer[] nullSafeGet(ResultSet rs, int i, SharedSessionContractImplementor ssci, Object o) throws SQLException {
+    public Object assemble(Serializable cached, Object owner) throws HibernateException {
+        return this.deepCopy( cached);
+    }
+
+    /**
+     * During merge, replace the existing (target) value in the entity we are merging to
+     * with a new (original) value from the detached entity we are merging. For immutable
+     * objects, or null values, it is safe to simply return the first parameter. For
+     * mutable objects, it is safe to return a copy of the first parameter. For objects
+     * with component values, it might make sense to recursively replace component values.
+     *
+     * @param original the value from the detached entity being merged
+     * @param target   the value in the managed entity
+     * @return the value to be merged
+     */
+    @Override
+    public Object replace(Object original, Object target, Object owner) throws HibernateException {
+        return original;
+    }
+
+    /**
+     * Retrieve an instance of the mapped class from a JDBC resultset. Implementors
+     * should handle possibility of null values.
+     *
+     * @param rs      a JDBC result set
+     * @param strings   the column names
+     * @param ssci
+     * @throws org.hibernate.HibernateException
+     *
+     * @throws java.sql.SQLException
+     */
+    @Override
+    public Object nullSafeGet(ResultSet rs, String[] strings, SharedSessionContractImplementor ssci, Object o) throws HibernateException, SQLException {
         if (rs.wasNull()) {
             return null;
         }
         try
         {
-            Integer[] array = (Integer[]) rs.getArray(i).getArray();
+            Integer[] array = (Integer[]) rs.getArray(strings[0]).getArray();
             return array;
         }
         catch(NullPointerException ex)
@@ -122,12 +243,30 @@ public class IntegerArrayUserType implements UserType<Integer[]> {
         }
     }
 
+    /**
+     * Write an instance of the mapped class to a prepared statement. Implementors
+     * should handle possibility of null values. A multi-column type should be written
+     * to parameters starting from <tt>index</tt>.
+     *
+     * @param ps      a JDBC prepared statement
+     * @param o   the object to write
+     * @param i   statement parameter index
+     * @param ssci
+     * @throws org.hibernate.HibernateException
+     *
+     * @throws java.sql.SQLException
+     */
     @Override
-    public Integer[] assemble(Serializable srlzbl, Object o) {
-        throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
-    }
+    public void nullSafeSet(PreparedStatement ps, Object o, int i, SharedSessionContractImplementor ssci) throws HibernateException, SQLException {
+        if (o == null) {
+            ps.setNull(i, Types.OTHER);
+            return;
+        }
 
-   
+        Integer[] castObject = (Integer[]) o;
+        Array array = ssci.connection().createArrayOf("integer", castObject); // The postgres array data type
+        ps.setArray(i, array);
+    }
 
 
 }
diff --git a/src/main/java/no/nibio/vips/logic/util/JsonPostgreSQLDialect.java b/src/main/java/no/nibio/vips/logic/util/JsonPostgreSQLDialect.java
new file mode 100755
index 00000000..2e7dda6a
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/util/JsonPostgreSQLDialect.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 NIBIO <http://www.nibio.no/>. 
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+package no.nibio.vips.logic.util;
+
+import java.sql.Types;
+import org.hibernate.dialect.PostgreSQL9Dialect;
+
+/**
+ * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+public class JsonPostgreSQLDialect extends PostgreSQL9Dialect{
+    public JsonPostgreSQLDialect() {
+
+        super();
+
+        this.registerColumnType(Types.JAVA_OBJECT, "json");
+    }
+}
diff --git a/src/main/java/no/nibio/vips/logic/util/StringJsonUserType.java b/src/main/java/no/nibio/vips/logic/util/StringJsonUserType.java
index 2b36426c..1672d607 100755
--- a/src/main/java/no/nibio/vips/logic/util/StringJsonUserType.java
+++ b/src/main/java/no/nibio/vips/logic/util/StringJsonUserType.java
@@ -29,13 +29,23 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
 import org.hibernate.usertype.UserType;
 
 /**
- * @copyright 2015-2024 <a href="http://www.nibio.no/">NIBIO</a>
+ * @copyright 2015-2019 <a href="http://www.nibio.no/">NIBIO</a>
  * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
  */
 
-public class StringJsonUserType implements UserType<String> {
-
+public class StringJsonUserType implements UserType {
 
+    /**
+     * Return the SQL type codes for the columns mapped by this type. The
+     * codes are defined on <tt>java.sql.Types</tt>.
+     *
+     * @return int[] the typecodes
+     * @see java.sql.Types
+     */
+    @Override
+    public int[] sqlTypes() {
+        return new int[] { Types.JAVA_OBJECT};
+    }
 
     /**
      * The class returned by <tt>nullSafeGet()</tt>.
@@ -47,7 +57,53 @@ public class StringJsonUserType implements UserType<String> {
         return String.class;
     }
 
+    /**
+     * Compare two instances of the class mapped by this type for persistence "equality".
+     * Equality of the persistent state.
+     *
+     * @param x
+     * @param y
+     * @return boolean
+     */
+    @Override
+    public boolean equals(Object x, Object y) throws HibernateException {
+
+        if( x== null){
+
+            return y== null;
+        }
+
+        return x.equals( y);
+    }
+
+    /**
+     * Get a hashcode for the instance, consistent with persistence "equality"
+     */
+    @Override
+    public int hashCode(Object x) throws HibernateException {
+
+        return x.hashCode();
+    }
 
+    /**
+     * Retrieve an instance of the mapped class from a JDBC resultset. Implementors
+     * should handle possibility of null values.
+     *
+     * @param rs      a JDBC result set
+     * @param names   the column names
+     * @param session
+     * @param owner   the containing entity  @return Object
+     * @throws org.hibernate.HibernateException
+     *
+     * @throws java.sql.SQLException
+     */
+    //@Override
+    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
+        if(rs.getString(names[0]) == null){
+            return null;
+        }
+        return rs.getString(names[0]);
+    }
 
     /**
      * Write an instance of the mapped class to a prepared statement. Implementors
@@ -79,12 +135,12 @@ public class StringJsonUserType implements UserType<String> {
      *
      * @param value the object to be cloned, which may be null
      * @return Object a copy
-     *
+     */
     @Override
     public Object deepCopy(Object value) throws HibernateException {
 
         return value;
-    }*/
+    }
 
     /**
      * Are objects of this type mutable?
@@ -96,60 +152,95 @@ public class StringJsonUserType implements UserType<String> {
         return true;
     }
 
+    /**
+     * Transform the object into its cacheable representation. At the very least this
+     * method should perform a deep copy if the type is mutable. That may not be enough
+     * for some implementations, however; for example, associations must be cached as
+     * identifier values. (optional operation)
+     *
+     * @param value the object to be cached
+     * @return a cachable representation of the object
+     * @throws org.hibernate.HibernateException
+     *
+     */
     @Override
-    public int getSqlType() {
-        return Types.JAVA_OBJECT;
+    public Serializable disassemble(Object value) throws HibernateException {
+        return (String)this.deepCopy( value);
     }
 
+    /**
+     * Reconstruct an object from the cacheable representation. At the very least this
+     * method should perform a deep copy if the type is mutable. (optional operation)
+     *
+     * @param cached the object to be cached
+     * @param owner  the owner of the cached object
+     * @return a reconstructed object from the cachable representation
+     * @throws org.hibernate.HibernateException
+     *
+     */
     @Override
-    public boolean equals(String x, String y) {
-        if( x== null){
-
-            return y== null;
-        }
-
-        return x.equals( y);
+    public Object assemble(Serializable cached, Object owner) throws HibernateException {
+        return this.deepCopy( cached);
     }
 
+    /**
+     * During merge, replace the existing (target) value in the entity we are merging to
+     * with a new (original) value from the detached entity we are merging. For immutable
+     * objects, or null values, it is safe to simply return the first parameter. For
+     * mutable objects, it is safe to return a copy of the first parameter. For objects
+     * with component values, it might make sense to recursively replace component values.
+     *
+     * @param original the value from the detached entity being merged
+     * @param target   the value in the managed entity
+     * @return the value to be merged
+     */
     @Override
-    public int hashCode(String j) {
-        return j.hashCode();
+    public Object replace(Object original, Object target, Object owner) throws HibernateException {
+        return original;
     }
 
+    
+    /**
+     * Retrieve an instance of the mapped class from a JDBC resultset. Implementors
+     * should handle possibility of null values.
+     *
+     * @param rs      a JDBC result set
+     * @param strings   the column names
+     * @param ssci
+     * @throws org.hibernate.HibernateException
+     *
+     * @throws java.sql.SQLException
+     */
     @Override
-    public String nullSafeGet(ResultSet rs, int i, SharedSessionContractImplementor ssci, Object o) throws SQLException {
-          if(rs.getString(i) == null){
+    public Object nullSafeGet(ResultSet rs, String[] strings, SharedSessionContractImplementor ssci, Object o) throws HibernateException, SQLException {
+        if(rs.getString(strings[0]) == null){
             return null;
         }
-        return rs.getString(i);
+        return rs.getString(strings[0]);
     }
 
+    /**
+     * Write an instance of the mapped class to a prepared statement. Implementors
+     * should handle possibility of null values. A multi-column type should be written
+     * to parameters starting from <tt>index</tt>.
+     *
+     * @param ps      a JDBC prepared statement
+     * @param o   the object to write
+     * @param i   statement parameter index
+     * @param ssci
+     * @throws org.hibernate.HibernateException
+     *
+     * @throws java.sql.SQLException
+     */
     @Override
-    public void nullSafeSet(PreparedStatement ps, String j, int i, SharedSessionContractImplementor ssci) throws SQLException {
-         if (j == null) {
+    public void nullSafeSet(PreparedStatement ps, Object o, int i, SharedSessionContractImplementor ssci) throws HibernateException, SQLException {
+        if (o == null) {
             ps.setNull(i, Types.OTHER);
             return;
         }
 
-         ps.setString(i, j);
+        ps.setObject(i, o, Types.OTHER);
     }
 
-    @Override
-    public String deepCopy(String j) {
-        return j;
-    }
-
-    @Override
-    public Serializable disassemble(String j) {
-        throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
-    }
-
-    @Override
-    public String assemble(Serializable srlzbl, Object o) {
-        throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
-    }
-
-   
-
 
 }
diff --git a/src/main/java/no/nibio/vips/observationdata/ObservationDataSchema.java b/src/main/java/no/nibio/vips/observationdata/ObservationDataSchema.java
index aa1da2bf..72434325 100755
--- a/src/main/java/no/nibio/vips/observationdata/ObservationDataSchema.java
+++ b/src/main/java/no/nibio/vips/observationdata/ObservationDataSchema.java
@@ -20,7 +20,6 @@ package no.nibio.vips.observationdata;
 
 import java.io.Serializable;
 import javax.persistence.Column;
-import javax.persistence.Convert;
 import javax.persistence.EmbeddedId;
 import javax.persistence.Entity;
 import javax.persistence.NamedQueries;
@@ -29,7 +28,8 @@ import javax.persistence.Table;
 import javax.xml.bind.annotation.XmlRootElement;
 import no.nibio.vips.logic.util.StringJsonUserType;
 import org.hibernate.annotations.Type;
-
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
 
 /**
  * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
@@ -38,6 +38,7 @@ import org.hibernate.annotations.Type;
 @Entity
 @Table(name = "observation_data_schema")
 @XmlRootElement
+@TypeDefs( {@TypeDef( name= "StringJsonObject", typeClass = StringJsonUserType.class)})
 @NamedQueries({
     @NamedQuery(name = "ObservationDataSchema.findAll", query = "SELECT o FROM ObservationDataSchema o"),
     @NamedQuery(name = "ObservationDataSchema.findByPK", query = "SELECT o FROM ObservationDataSchema o WHERE o.observationDataSchemaPK.organizationId = :organizationId AND o.observationDataSchemaPK.organismId = :organismId"),
@@ -48,11 +49,11 @@ public class ObservationDataSchema implements Serializable {
     private static final long serialVersionUID = 1L;
     @EmbeddedId
     protected ObservationDataSchemaPK observationDataSchemaPK;
-    @Convert(converter = StringJsonUserType.class)
+    @Type(type = "StringJsonObject")
     @Column(name = "data_schema")
     private String dataSchema;
-    @Convert(converter = StringJsonUserType.class)
-    @Column(name = "data_model", columnDefinition="json")
+    @Type(type = "StringJsonObject")
+    @Column(name = "data_model")
     private String dataModel;
 
     public ObservationDataSchema() {
diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml
index 5e68097c..bfaf5ef4 100755
--- a/src/main/resources/META-INF/persistence.xml
+++ b/src/main/resources/META-INF/persistence.xml
@@ -25,8 +25,8 @@
     <jta-data-source>java:/jboss/datasources/vipslogic</jta-data-source>
     <class>no.nibio.vips.logic.messaging.MessageNotificationSubscription</class>
     <exclude-unlisted-classes>false</exclude-unlisted-classes>
-    <!--properties>
-      <property name="hibernate.dialect" value="org.hibernate.spatial.dialect.postgis.PostgisPG10Dialect"/>
-    </properties-->
+    <properties>
+      <property name="hibernate.dialect" value="org.hibernate.spatial.dialect.postgis.PostgisDialect"/>
+    </properties>
   </persistence-unit>
 </persistence>
-- 
GitLab