All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vanillabp.springboot.utils.JpaSpringDataUtil Maven / Gradle / Ivy

There is a newer version: 1.1.3
Show newest version
package io.vanillabp.springboot.utils;

import io.vanillabp.springboot.adapter.SpringDataUtil;
import jakarta.persistence.Id;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.hibernate.Hibernate;
import org.springframework.context.ApplicationContext;
import org.springframework.data.jpa.repository.JpaContext;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.support.Repositories;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

public class JpaSpringDataUtil implements SpringDataUtil {

    private static final Map, JpaRepository> REPOSITORY_MAP = new HashMap<>();
    
    private static final Map, EntityInformation> ENTITYINFO_MAP = new HashMap<>();
    
    private final ApplicationContext applicationContext;

    private final LocalContainerEntityManagerFactoryBean containerEntityManagerFactoryBean;
    
    private final JpaContext jpaContext;
    
    public JpaSpringDataUtil(
            final ApplicationContext applicationContext,
            final JpaContext jpaContext,
            final LocalContainerEntityManagerFactoryBean containerEntityManagerFactoryBean) {
        
        this.applicationContext = applicationContext;
        this.jpaContext = jpaContext;
        this.containerEntityManagerFactoryBean = containerEntityManagerFactoryBean;
        
    }

    @SuppressWarnings("unchecked")
    public  JpaRepository getRepository(
            final O object) {

        //noinspection unchecked
        return getRepository((Class) object.getClass());

    }

    @SuppressWarnings("unchecked")
    public  JpaRepository getRepository(
            final Class type) {

        Class cls = type;

        if (REPOSITORY_MAP.containsKey(cls)) {
            return (JpaRepository) REPOSITORY_MAP.get(cls);
        }
        
        var repositories = new Repositories(applicationContext);

        Optional repository;
        do {
            repository = repositories.getRepositoryFor(cls);
            cls = repository.isPresent() ? cls : cls.getSuperclass();
        } while (repository.isEmpty() && (cls != Object.class));

        if (repository.isEmpty()) {
            throw new IllegalStateException(
                    String.format("No Spring Data repository defined for '%s'!", type.getName()));
        }
        
        REPOSITORY_MAP.put(cls, (JpaRepository) repository.get());
        
        return (JpaRepository) repository.get();

    }

    @Override
    public Class getIdType(Class type) {
        
        Class cls = type;

        if (ENTITYINFO_MAP.containsKey(cls)) {
            return ENTITYINFO_MAP
                    .get(cls)
                    .getIdType();
        }
        
        var repositories = new Repositories(applicationContext);
        
        EntityInformation entityInfo;
        do {
            entityInfo = repositories.getEntityInformationFor(cls);
            cls = entityInfo != null ? cls : cls.getSuperclass();
        } while ((entityInfo == null) && (cls != Object.class));
        
        if (entityInfo == null) {
            throw new IllegalStateException(
                    String.format("Type '%s' is not an entity!", type.getName()));
        }
        
        ENTITYINFO_MAP.put(cls, entityInfo);
        
        return entityInfo.getIdType();
        
    }

    public String getIdName(Class type){
        // TODO: get fields from parents, also check annotated getter methods
        return Arrays
                .stream(type.getDeclaredFields())
                .filter(this::isIdAnnotationPresent)
                .findFirst()
                .map(Field::getName)
                .orElse(null);
    }

    private boolean isIdAnnotationPresent(Field field){
        return field.isAnnotationPresent(Id.class) ||
                field.isAnnotationPresent(org.springframework.data.annotation.Id.class);
    }

    @SuppressWarnings("unchecked")
    public  I getId(
            final Object domainEntity) {
        
        final var id = containerEntityManagerFactoryBean
                .getNativeEntityManagerFactory()
                .getPersistenceUnitUtil()
                .getIdentifier(domainEntity);
        if (id == null) {
            return null;
        }
        return (I) id;
        
    }

    @Override
    public  boolean isPersistedEntity(
            final Class entityClass,
            final O entity) {
        
        final var em = jpaContext
                .getEntityManagerByManagedType(entityClass);
        if (em.contains(entity)) {
            return true;
        }
        final var id = getId(entity);
        if (id == null) {
            return false;
        }
        return em.find(entityClass, id) != null;

    }
    
    @SuppressWarnings("unchecked")
    @Override
    public  O unproxy(
            final O entity) {
        
        return (O) Hibernate.unproxy(entity);
        
    }
    
}