1
votes

I have an abstract base class marked @MappedSuperclass that has @Id @GeneratedValue set on its id property.

I also have an @Entity derived from it that needs to set its own IDs rather than relying on generation.

I have a large number of derived entities relying on the id being set in the @MappedSuperclass, and I'd prefer not to set up the id in each one.

How can I avoid the @GeneratedValue for just this one derived entity? I expected setting the ID manually to override generation and that doesn't appear to be the case.

DDL of id column (HSQL):

id bigint generated by default as identity (start with 1)

According to http://hsqldb.org/doc/guide/ch02.html#N104B3 id generation should only occur when a null value is specified for the id column.

Here is some example code:

@MappedSuperclass
class Parent {
    @Id @GeneratedValue
    private Long id;
}

@Entity
class Child extends Parent
    @PrePersist
    public void prePersist() {
        LOG.info("PrePersist with id #{}", this.id);
    }
}

Child t = new Child();
t.setId(123);

LOG.debug("Creating: Child #{}", t.getId());
childRepository.save(t); // Spring Data JPA Repositories
LOG.debug("Created: Child #{}", t.getId());

// Outputs:
// Creating: Child #123
// PrePersist with id #123 
// Created: Child #1

Edit:

It turns out that the default @GeneratedValue strategy doesn't allow specification of ids. The database will always generate them. It turns out I needed to write a custom ID generator...

public class CustomIdGenerator extends SequenceStyleGenerator {

    @Override
    public Serializable generate(SessionImplementor session, Object object)
        throws HibernateException {
        Serializable id = session.getEntityPersister(null, object)
            .getClassMetadata().getIdentifier(object, session);
        return id != null ? id : super.generate(session, object);
    }

}

... and then annotate the parent's ID field as follows ...

@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "CustomIdGenerator")
@GenericGenerator(name = "CustomIdGenerator", strategy = "com.foo.CustomIdGenerator")
private Long id;

This causes a sequence table or native sequence to be used for ID generation, but defers to IDs set on the entity.

1

1 Answers

1
votes

Edit: Working answer: Ok, now I see that there is no way to do this in pure JPA-way, but if you're using Hibernate you might try to write custom SequenceGenerator as it is described here. Basically, it will generate a value (call to super.generate()) only when the id is not set.