I have a class
@MappedSuperclass
public abstract class MyAbstractProperty <T extends Object>{
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
@Column(name="defaultValue")
protected T defaultValue;
//...
}
Which is basis for sub classes like class MyLongProperty extends MyAbstractProperty<Long>{}
.
This works fine. The problem arises when I want to store Text in the class class MyStringProperty extends MyAbstractProperty<String>{}
.
I have learned that hibernate per default stores Strings only with max 255 chars (see: JPA: "Data too long for column" does not change). Therefore my defaultValue
would need an additional annotation like:
@Entity
class MyStringProperty extends MyAbstractProperty<String>{
@Type(type="org.hibernate.type.StringClobType")
@Column(name="defaultValue")
protected String defaultValue; // problem since defaultValue is already defined in MyAbstractProperty<>.
}
How can I ensure this since the defaultvalue is already defined in MyAbstractProperty
? I don't think it is ok to move the type annotation to MyAbstractProperty
since this might have side effects on other classes like MyLongProperty
.
For example when I was setting @Lob
in MyAbstractProperty
the SQL definition of MyStringProperty
included DEFAULTVALUE BLOB(255)
instead of DEFAULTVALUE BIGINT
.
Additional question: There seem to be different options for defining the column as text data (e.g. @Type(type="org.hibernate.type.StringClobType")
, @Lob
) Where are the maijor differences in these options. What best to take. (My main database is HyperSQL, but I also target for SQLite, MariaDB and MySQL).
Edit
Based on the recent feedback it seems like the solution might be abstract getters/setter. I have to check what are the implications on this on my code.
I had an alternative - not finished - idea, which might cause less modifictions of my code. Is it possible to define a class
class MyText extendes String;
such as that all instances of MyText
are automatically stored as @Lob
?
Than I would just have to modify MyAbstractProperty<String>
to MyAbstractProperty<MyText>
.
You could leave only an abstract getter in the superclass, and define the field in subclasses:
@MappedSuperclass
public abstract class MyAbstractProperty<T extends Object>{
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
public abstract T getDefaultValue();
}
@Entity
class MyStringProperty extends MyAbstractProperty<String>{
@Type(type="org.hibernate.type.StringClobType")
@Column(name="defaultValue")
protected String defaultValue;
@Override
public String getDefaultValue() {
return defaultValue;
}
}
In order to avoid boilerplate for all other cases which don't require special treatment, you can simply create another abstract class which contains default mapping, and then extend other entities from it:
@MappedSuperclass
public abstract class MyDefaultProperty<T> extends MyAbstractProperty<T extends Object> {
@Column(name="defaultValue")
protected T defaultValue;
@Override
public T getDefaultValue() {
return defaultValue;
}
}