slawalata
slawalata

Reputation: 441

Mapping Java Generic to String value

I want to persist into DB 2 entities :

Thanks in advance for any help or suggestion to solve this problem.

Upvotes: 0

Views: 1524

Answers (2)

slawalata
slawalata

Reputation: 441

sbjavateam, thank you for your thoroughly explanation. I have arrived in almost the same conclusion after I try to implement AttributeConverter. I stuck to convert T value to to String. It ends up to use instance of to get Object type only but I cant map its value. It is well explained in your explained Also in relational databases you can't persist java object without appropriate type.

I ends up almost the same approach like you to create additional class wrapper but Attribute<T> really a good idea.... It brings me arsenal to prove design your entity first clean and nice and do mapping latter.

Upvotes: 0

xyz
xyz

Reputation: 5407

You can't persist generic T due to java type erasure Type Erasure. Type T exist only in source and at runtime it's type Object. hibernate doent's know how to store / present Object in database it might be any type - entity , collection ,embeded object , some simple object - string , integer .....

Also in relational databases you can't persist java object without appropriate type (you can try to serialize object and save it as blob and in java side de-serialize it :) :) )

General :

  1. if T it's entity : need to provide an interface/superclass instead of T, be it only an empty marker one if the differences between subclasses are large.

    @ManyToOne(targetEntity=T_EntityClass.class) @JoinColumn(name = "") private T value;

  2. if it's not entity - looks like your case : create abstract entity with all fields except value field , and extends from this entity child - implementation , like for String , Integer....

    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    public abstract class Attribute<T> {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @ManyToOne
        @JoinColumn(name = "item_id")
        private Item item;
    
        @Column
        private String name;
    
        @Column
        boolean isTemplate;
    
        public abstract T getValue();
    
        public abstract void setValue(T value);
        ........
       }  
    

String implementation :

@Entity
public class AttributeStringValue extends Attribute<String>{

    @Column
    String value;

    @Override
    public String getValue() {
        return value;
    }

    @Override
    public void setValue(String value) {
        this.value = value;
    }
}

Integer implementation :

@Entity
public class AttributeIntegerValue extends Attribute<Integer>{

    @Column
    Integer value;

    @Override
    public Integer getValue() {
        return value;
    }

    @Override
    public void setValue(Integer value) {
        this.value = value;
    }
}

as result you have 3 tables :

create table attribute (
    id bigint generated by default as identity,
    is_template boolean,
    name varchar(255),
    item_id bigint,
    primary key (id)
)

create table attribute_integer_value (
    value integer,
    id bigint not null,
    primary key (id)
)

create table attribute_string_value (
    value varchar(255),
    id bigint not null,
    primary key (id)
)

Upvotes: 2

Related Questions