Fixes for Hibernate 6 support
This commit is contained in:
parent
5e566d9d95
commit
24ff462b31
@ -21,14 +21,13 @@ import jakarta.persistence.Id;
|
|||||||
import jakarta.persistence.MappedSuperclass;
|
import jakarta.persistence.MappedSuperclass;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hibernate.annotations.UuidGenerator;
|
|
||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
import org.thingsboard.server.common.data.BaseData;
|
import org.thingsboard.server.common.data.BaseData;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.id.UUIDBased;
|
import org.thingsboard.server.common.data.id.UUIDBased;
|
||||||
import org.thingsboard.server.dao.DaoUtil;
|
import org.thingsboard.server.dao.DaoUtil;
|
||||||
import org.thingsboard.server.dao.sql.IdGenerator;
|
import org.thingsboard.server.dao.sql.IdGenerator.GeneratedId;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -46,7 +45,7 @@ public abstract class BaseSqlEntity<D> implements BaseEntity<D> {
|
|||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name = ModelConstants.ID_PROPERTY, columnDefinition = "uuid")
|
@Column(name = ModelConstants.ID_PROPERTY, columnDefinition = "uuid")
|
||||||
@UuidGenerator(style = UuidGenerator.Style.AUTO, algorithm = IdGenerator.class)
|
@GeneratedId
|
||||||
protected UUID id;
|
protected UUID id;
|
||||||
|
|
||||||
@Column(name = ModelConstants.CREATED_TIME_PROPERTY, updatable = false)
|
@Column(name = ModelConstants.CREATED_TIME_PROPERTY, updatable = false)
|
||||||
|
|||||||
@ -17,17 +17,44 @@ package org.thingsboard.server.dao.sql;
|
|||||||
|
|
||||||
import com.datastax.oss.driver.api.core.uuid.Uuids;
|
import com.datastax.oss.driver.api.core.uuid.Uuids;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.hibernate.annotations.IdGeneratorType;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.id.uuid.UuidValueGenerator;
|
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||||
|
import org.hibernate.generator.EventType;
|
||||||
|
import org.hibernate.generator.EventTypeSets;
|
||||||
|
import org.thingsboard.server.dao.model.BaseEntity;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class IdGenerator implements UuidValueGenerator {
|
public class IdGenerator implements BeforeExecutionGenerator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID generateUuid(SharedSessionContractImplementor session) {
|
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||||
|
if (owner instanceof BaseEntity<?> entity && entity.getUuid() != null) {
|
||||||
|
return entity.getUuid();
|
||||||
|
}
|
||||||
return Uuids.timeBased();
|
return Uuids.timeBased();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allowAssignedIdentifiers() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumSet<EventType> getEventTypes() {
|
||||||
|
return EventTypeSets.INSERT_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
@IdGeneratorType(IdGenerator.class)
|
||||||
|
public @interface GeneratedId {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,12 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.dao.sql;
|
package org.thingsboard.server.dao.sql;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.core.uuid.Uuids;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import jakarta.persistence.OptimisticLockException;
|
import jakarta.persistence.OptimisticLockException;
|
||||||
import jakarta.persistence.PersistenceContext;
|
import jakarta.persistence.PersistenceContext;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.hibernate.Session;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
@ -69,6 +71,14 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
|||||||
boolean isNew = entity.getUuid() == null;
|
boolean isNew = entity.getUuid() == null;
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
entity.setCreatedTime(System.currentTimeMillis());
|
entity.setCreatedTime(System.currentTimeMillis());
|
||||||
|
} else {
|
||||||
|
if (entity.getCreatedTime() == 0) {
|
||||||
|
if (entity.getUuid().version() == 1) {
|
||||||
|
entity.setCreatedTime(Uuids.unixTimestamp(entity.getUuid()));
|
||||||
|
} else {
|
||||||
|
entity.setCreatedTime(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
entity = doSave(entity, isNew, flush);
|
entity = doSave(entity, isNew, flush);
|
||||||
@ -82,33 +92,9 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
|||||||
boolean flushed = false;
|
boolean flushed = false;
|
||||||
EntityManager entityManager = getEntityManager();
|
EntityManager entityManager = getEntityManager();
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
entityManager.persist(entity);
|
entity = create(entity);
|
||||||
if (entity instanceof HasVersion versionedEntity) {
|
|
||||||
versionedEntity.setVersion(1L);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (entity instanceof HasVersion versionedEntity) {
|
entity = update(entity);
|
||||||
if (versionedEntity.getVersion() == null) {
|
|
||||||
HasVersion existingEntity = entityManager.find(versionedEntity.getClass(), entity.getUuid());
|
|
||||||
if (existingEntity != null) {
|
|
||||||
/*
|
|
||||||
* manually resetting the version to latest to allow force overwrite of the entity
|
|
||||||
* */
|
|
||||||
versionedEntity.setVersion(existingEntity.getVersion());
|
|
||||||
} else {
|
|
||||||
return doSave(entity, true, flush);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
versionedEntity = entityManager.merge(versionedEntity);
|
|
||||||
entity = (E) versionedEntity;
|
|
||||||
/*
|
|
||||||
* by default, Hibernate doesn't issue an update query and thus version increment
|
|
||||||
* if the entity was not modified. to bypass this and always increment the version, we do it manually
|
|
||||||
* */
|
|
||||||
versionedEntity.setVersion(versionedEntity.getVersion() + 1);
|
|
||||||
} else {
|
|
||||||
entity = entityManager.merge(entity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (entity instanceof HasVersion versionedEntity) {
|
if (entity instanceof HasVersion versionedEntity) {
|
||||||
/*
|
/*
|
||||||
@ -125,6 +111,53 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private E create(E entity) {
|
||||||
|
if (entity instanceof HasVersion versionedEntity) {
|
||||||
|
versionedEntity.setVersion(1L);
|
||||||
|
}
|
||||||
|
if (entity.getUuid() == null) {
|
||||||
|
getEntityManager().persist(entity);
|
||||||
|
} else {
|
||||||
|
if (entity instanceof HasVersion) {
|
||||||
|
/*
|
||||||
|
* Hibernate 6 does not allow creating versioned entities with preset IDs.
|
||||||
|
* Bypassing by calling the underlying session directly
|
||||||
|
* */
|
||||||
|
Session session = getEntityManager().unwrap(Session.class);
|
||||||
|
session.save(entity);
|
||||||
|
} else {
|
||||||
|
entity = getEntityManager().merge(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private E update(E entity) {
|
||||||
|
if (entity instanceof HasVersion versionedEntity) {
|
||||||
|
if (versionedEntity.getVersion() == null) {
|
||||||
|
HasVersion existingEntity = entityManager.find(versionedEntity.getClass(), entity.getUuid());
|
||||||
|
if (existingEntity != null) {
|
||||||
|
/*
|
||||||
|
* manually resetting the version to latest to allow force overwriting of the entity
|
||||||
|
* */
|
||||||
|
versionedEntity.setVersion(existingEntity.getVersion());
|
||||||
|
} else {
|
||||||
|
return create(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
versionedEntity = entityManager.merge(versionedEntity);
|
||||||
|
entity = (E) versionedEntity;
|
||||||
|
/*
|
||||||
|
* by default, Hibernate doesn't issue an update query and thus version increment
|
||||||
|
* if the entity was not modified. to bypass this and always increment the version, we do it manually
|
||||||
|
* */
|
||||||
|
versionedEntity.setVersion(versionedEntity.getVersion() + 1);
|
||||||
|
} else {
|
||||||
|
entity = entityManager.merge(entity);
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public D saveAndFlush(TenantId tenantId, D domain) {
|
public D saveAndFlush(TenantId tenantId, D domain) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user