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 lombok.Data;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.hibernate.annotations.UuidGenerator;
 | 
			
		||||
import org.thingsboard.common.util.JacksonUtil;
 | 
			
		||||
import org.thingsboard.server.common.data.BaseData;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.UUIDBased;
 | 
			
		||||
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.Collections;
 | 
			
		||||
@ -46,7 +45,7 @@ public abstract class BaseSqlEntity<D> implements BaseEntity<D> {
 | 
			
		||||
 | 
			
		||||
    @Id
 | 
			
		||||
    @Column(name = ModelConstants.ID_PROPERTY, columnDefinition = "uuid")
 | 
			
		||||
    @UuidGenerator(style = UuidGenerator.Style.AUTO, algorithm = IdGenerator.class)
 | 
			
		||||
    @GeneratedId
 | 
			
		||||
    protected UUID id;
 | 
			
		||||
 | 
			
		||||
    @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 lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.hibernate.annotations.IdGeneratorType;
 | 
			
		||||
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
 | 
			
		||||
public class IdGenerator implements UuidValueGenerator {
 | 
			
		||||
public class IdGenerator implements BeforeExecutionGenerator {
 | 
			
		||||
 | 
			
		||||
    @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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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;
 | 
			
		||||
 | 
			
		||||
import com.datastax.oss.driver.api.core.uuid.Uuids;
 | 
			
		||||
import com.google.common.collect.Lists;
 | 
			
		||||
import com.google.common.util.concurrent.ListenableFuture;
 | 
			
		||||
import jakarta.persistence.EntityManager;
 | 
			
		||||
import jakarta.persistence.OptimisticLockException;
 | 
			
		||||
import jakarta.persistence.PersistenceContext;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.hibernate.Session;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.jdbc.core.JdbcTemplate;
 | 
			
		||||
@ -69,6 +71,14 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
 | 
			
		||||
        boolean isNew = entity.getUuid() == null;
 | 
			
		||||
        if (isNew) {
 | 
			
		||||
            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 {
 | 
			
		||||
            entity = doSave(entity, isNew, flush);
 | 
			
		||||
@ -82,33 +92,9 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
 | 
			
		||||
        boolean flushed = false;
 | 
			
		||||
        EntityManager entityManager = getEntityManager();
 | 
			
		||||
        if (isNew) {
 | 
			
		||||
            entityManager.persist(entity);
 | 
			
		||||
            if (entity instanceof HasVersion versionedEntity) {
 | 
			
		||||
                versionedEntity.setVersion(1L);
 | 
			
		||||
            }
 | 
			
		||||
            entity = create(entity);
 | 
			
		||||
        } else {
 | 
			
		||||
            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 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);
 | 
			
		||||
            }
 | 
			
		||||
            entity = update(entity);
 | 
			
		||||
        }
 | 
			
		||||
        if (entity instanceof HasVersion versionedEntity) {
 | 
			
		||||
            /*
 | 
			
		||||
@ -125,6 +111,53 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
 | 
			
		||||
        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
 | 
			
		||||
    @Transactional
 | 
			
		||||
    public D saveAndFlush(TenantId tenantId, D domain) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user