Использование enum для фильтрации статуса - PullRequest
1 голос
/ 23 октября 2019

Привет, у меня есть служба Spring, и в хранилище я пытаюсь отфильтровать по enum

List<Organization> findAllByStatus(StatusType type);

, и по какой-то причине этот параметр enum не передается в SQL-запрос.

Я вижу where organizati0_.status=? в SQL, но параметры не передаются.

Есть идеи, что может быть причиной?

Перечисление:

public enum StatusType {
  ACTIVE,
  TO_BE_DELETED,
  @Deprecated IN_ACTIVE
} 

Служба:

public List<Organization> getAllOrganizations() {
        return Lists.newArrayList(organizationRepository.findAllByStatus(StatusType.TO_BE_DELETED));
}

1 Ответ

0 голосов
/ 24 октября 2019
import java.io.Serializable;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import com.example.demo.jobs.CustomQueryParamMethodInterceptor;

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
import org.springframework.util.Assert;

public class MyJpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
        extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> {

    private EntityManager entityManager;

    private static final CustomQueryParamMethodInterceptor interceptor = new CustomQueryParamMethodInterceptor();
    /**
     * Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
     *
     * @param repositoryInterface must not be {@literal null}.
     */
    public MyJpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
        super(repositoryInterface);
    }

    /**
     * The {@link EntityManager} to be used.
     *
     * @param entityManager the entityManager to set
     */
    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#setMappingContext(org.springframework.data.mapping.context.MappingContext)
     */
    @Override
    public void setMappingContext(MappingContext<?, ?> mappingContext) {
        super.setMappingContext(mappingContext);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.springframework.data.repository.support.
     * TransactionalRepositoryFactoryBeanSupport#doCreateRepositoryFactory()
     */
    @Override
    protected RepositoryFactorySupport doCreateRepositoryFactory() {
        RepositoryFactorySupport support = createRepositoryFactory(entityManager);
        support.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
            @Override
            public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
                factory.addAdvice(interceptor);
            }
        });
        return support;
    }

    /**
     * Returns a {@link RepositoryFactorySupport}.
     *
     * @param entityManager
     * @return
     */
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        return new JpaRepositoryFactory(entityManager);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    @Override
    public void afterPropertiesSet() {

        Assert.notNull(entityManager, "EntityManager must not be null!");
        super.afterPropertiesSet();
    }
}

, а затем добавьте аннотацию к классу приложения Spring

@EnableJpaRepositories(repositoryFactoryBeanClass = MyJpaRepositoryFactoryBean.class)

и создайте метод-перехватчик для преобразования параметра Enum в определенный тип

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;

import com.example.demo.dto.ParamWrapper;
import com.example.demo.dto.StatusType;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import org.springframework.aop.framework.ReflectiveMethodInvocation;

public class CustomQueryParamMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        if (invocation instanceof ReflectiveMethodInvocation) {
            ReflectiveMethodInvocation rmi = (ReflectiveMethodInvocation)invocation;
            Object[] args = invocation.getArguments();
            if (args != null && args.length > 0) {
                Object[] newArgs = new Object[args.length];
                for (int i=0 ;i<args.length; i++) {
                    if (args[i] instanceof ParamWrapper) {
                        ParamWrapper p = (ParamWrapper)args[i];
                        newArgs[i] = p.getValue();
                    } else {
                        newArgs[i] = args[i];
                    }
                }
                rmi.setArguments(newArgs);
            }
        }
        return invocation.proceed();
    }
}

ParamWrapperявляется универсальным типом, который ваше перечисление должно реализовать

public interface ParamWrapper<T> {
    T getValue();
}

, тогда ваше перечисление должно измениться следующим образом

public enum StatusType implements ParamWrapper<Integer> {
    ACTIVE,
    TO_BE_DELETED,
    @Deprecated IN_ACTIVE;

    @Override
    public Integer getValue() {
        //you should determine your value
        return 1;
    }
}
...