Overriding @Id defined in a @MappedSuperclass with JPA
Asked Answered
B

3

12

I have a class AbstractEntity that is extended by all the entities in my application and basically acts as an Identifier provider.

@MappedSuperclass
public class AbstractEntity implements DomainEntity {

    private static final long serialVersionUID = 1L;

    /** This object's id */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected long id;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="creation_date", nullable = false, updatable=false)
    private Date creationDate = new Date();

    /**
     * @return the id
     */
    public long getId() {
        return this.id;
    }

    /**
     * @param id the id to set
     */
    public void setId(long id) {
        this.id = id;
    }
}

I have a case now where I need to define a separate Id for couple of my Entity classes as these need to have a custom Sequence Generator. How can this be achieved?

@Entity
@Table(name = "sample_entity")
public class ChildEntity extends AbstractChangeableEntity {

    @Column(name = "batch_priority")
    private int priority;

    public int getPriority() {
        return priority;
    }

    public void setPriority(int priority) {
        this.priority = priority;
    }

}
Bittencourt answered 29/4, 2015 at 12:1 Comment(1)
One option could be to override generator name in subclass that needs to customize, but it would imply you use the same type of generator (sequence generator) for all entities. Check out this post for more info. It would be ideal if you/we could override the whole generator in subclass but I don't think it can work at this time.Poulos
M
13

You can't do it, as demonstrated by this GitHub example.

Once you define the @Id in a base class you won't be able to override it in a sub-class, meaning it's better to leave the @Id responsibility to each individual concrete class.

Marquita answered 29/4, 2015 at 12:58 Comment(0)
A
6

Split your base class.

Defines all common fields but ID:

@MappedSuperclass
public  abstract class AbstractEntityNoId implements DomainEntity {
 private static final long serialVersionUID = 1L;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="creation_date", nullable = false, updatable=false)
    private Date creationDate = new Date();
}

Extends above with Default ID generator:

@MappedSuperclass
public abstract class AbstractEntity extends AbstractEntityNoId {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected Long id;

    public Long getId(){
       return id;
    }
}

Classes requiring custom ID generation extend the former and others the latter.

With the above, no existing code will have to change other than the Entities requiring the custom ID generation.

Artisan answered 29/4, 2015 at 13:54 Comment(2)
But i want to maintain the hierarchy, all i want is to somehow hide the Identifier provided by the base classBittencourt
As has been pointed out, you can't. With the above you do not need to change any existing code other than the superclass of those entities requiring custom ID generation. Everything is still an instance of DomainEntity.Artisan
P
3

One of the solution, which is not feasible in some cases, is to use the annotations on the get methods instead of the fields. It will gives you more flexibility specially to override whatever you want.

In code :

@MappedSuperclass
public class AbstractEntity implements DomainEntity {

    private static final long serialVersionUID = 1L;

    protected long id;

    private Date creationDate = new Date();

    /**
     * @return the id
     */
    /** This object's id */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long getId() {
        return this.id;
    }

    /**
     * @param id the id to set
     */
    public void setId(long id) {
        this.id = id;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="creation_date", nullable = false, updatable=false)
    public Date getCreationDate () {
        return this.creationDate ;
    }
}

And your subclass :

@Entity
@Table(name = "sample_entity")
public class ChildEntity extends AbstractChangeableEntity {


private int priority;

@Override
@Id
@GeneratedValue(strategy = GenerationType.ANOTHER_STRATEGY)
public long getId() {
    return this.id;
}

@Column(name = "batch_priority")
public int getPriority() {
        return priority;
    }
public void setPriority(int priority) {
        this.priority = priority;
    }

}

Pikeman answered 6/8, 2018 at 17:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.