Persist dynamically typed entity properties with Hibernate and PostgreSQL


#1

I would like to build field which can be String, Boolean or Long. In this case I tried use generics type and inheratiance. All code compiles correctly but when I want to get some parameters from database I got a error like:

Object [id=1] was not of the specified subclass [unity.app.domain.Parameter] : Discriminator: 1",

What is more if I want to use post method to adding parameter to DB I got error like this:

“Type definition error: [simple type, class unity.app.domain.Parameter]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of unity.app.domain.Parameter (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information\n at [Source: (PushbackInputStream); line: 1, column: 1]”,

I don’t have any ideas how to resolve this problem :frowning:

@Data
@Entity
@Table(name = "parameter")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "parameter", discriminatorType = DiscriminatorType.STRING)
public abstract class Parameter<T> {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name = "id", nullable = false)
    private Long id;

    @Column(name = "code")
    private String code;

    private T value;

    @Transient
    public abstract T getValue();

    public abstract void setValue(T value);
}

@Entity
@DiscriminatorValue(value = "boolean")
public class BooleanValue extends Parameter<Boolean> {

    @Column(name = "bool_value")
    private Boolean booleanValue;

    getValue()/setValue()[...]
}

@Entity
@DiscriminatorValue(value = "long")
public class LongValue extends Parameter<Long> {}

@Entity
@DiscriminatorValue(value = "string")
public class StringValue extends Parameter<String> {}

I am using postgresql and this is my table “parameter”:

  id BIGINT,
  code VARCHAR,
  name VARCHAR,
  description VARCHAR,
  bool_value BOOLEAN,
  string_value VARCHAR,
  long_value BIGINT

#2
  1. There is no parameter column in your table and you told Hibernate that the discriminator should be found in the parameter column.
  2. The table you have there is not what Hibernate expects for SINGLE_TABLE inheritance. Just activate the hbm2ddl schema generatrion to see what tables Hibernate expects.
  3. Since you use PostgreSQL, you don-t need this inheritance-based design to handle your requirement. Just use a JSON property and store whatever you want in it.
  4. The exception Cannot construct instance of unity.app.domain.Parameter (no Creators, like default construct, exist) is because you fetch entities as abstract class references and try to serialize to Jackson. Once you remove the inheritance model as suggested above, you will no longer have this problem.