Announcement Announcement Module
Collapse
No announcement yet.
Query derivation and Custom Repository Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Query derivation and Custom Repository

    Hi,

    I am having a particular issue that doesn't want to go away.
    I have created a Custom Repository that handles dynamic search in my own custom way. See the code below

    Code:
    @NoRepositoryBean
    public interface BaseRepository<T, ID extends Serializable, Q extends BaseEntityQueryCriteria>
            extends JpaRepository<T, ID>, Serializable {
    
        List<T> criteriaSearch(
                Q entityCriteria);
    }
    The implementation is adapted from a custom search I built in the Jpa 1.x days. I am still comfortable with it.
    Code:
    class BaseRepositoryImpl<T, ID extends Serializable, Q extends BaseEntityQueryCriteria>
            extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID, Q> {
    
        @Resource
        private EntityManager entityManager;
        /**
         * EMPTY_STRING
         */
        //private final static String EMPTY_STRING = " ";
        /**
         * PRIMARY_ENTITY
         */
        private final String PRIMARY_ENTITY = "{PRIMARY_ENTITY}";
    
    //    public BaseRepositoryImpl() {
    //    }
    
        /**
         * constructor
         */
        public BaseRepositoryImpl(Class<T> entityClass, EntityManager _entityManager) {
            super(entityClass, _entityManager);
            //set this entitymanager
            this.entityManager = _entityManager;
        }
    
        @SuppressWarnings("unchecked")
        @Override
        public List<T> criteriaSearch(
                Q entityCriteria) {
    
            String queryString = buildQuery(entityCriteria);
            Query query = entityManager.createQuery(queryString);
            setQueryParameter(query, entityCriteria.getParameters());
            return query.getResultList();
        }
    
        /**
         *
         *
         */
        private String buildQuery(BaseQueryCriteria baseQueryBuilder) {
            String entityName = baseQueryBuilder.getEntityName();
            String sqlScript = baseQueryBuilder.getSqlString();
            sqlScript = sqlScript.replace(PRIMARY_ENTITY, entityName);
            baseQueryBuilder = null;
            return sqlScript;
        }
    
        /**
         * sets the various parameters on the JPQL using the map that is passed in.
         *
         * @param Query - the query object to be set
         * @Map - parameters
         */
        private void setQueryParameter(Query query, Map<String, Object> parameters) {
            Set<String> keySet = parameters.keySet();
            if (keySet.size() > 0) {
                for (String placeHolder : keySet) {
                    Object object = parameters.get(placeHolder);
                    if (object instanceof String) {
                        object = ((String) object).toLowerCase();
                    }
                    query.setParameter(placeHolder, object);
                }
            }
        }
    }
    the factory bean is
    Code:
    public class BaseRepositoryFactoryBean<R extends JpaRepository<T, ID>, T, ID extends Serializable>
            extends JpaRepositoryFactoryBean<R, T, ID> {
    
        @Override
        protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
    
            return new MyRepositoryFactory(entityManager);
        }
    
        /**
         *
         * @param <T>
         * @param <I>
         */
        private static class MyRepositoryFactory<T, ID extends Serializable, Q extends BaseEntityQueryCriteria>
                extends JpaRepositoryFactory {
    
            /**
             *
             */
            private EntityManager entityManager;
    
            /**
             * constructor
             *
             * @param entityManager
             */
            public MyRepositoryFactory(EntityManager entityManager) {
                super(entityManager);
    
                this.entityManager = entityManager;
            }
    
            @Override
            protected Object getTargetRepository(RepositoryMetadata metadata) {
                return new BaseRepositoryImpl<T, ID, Q>((Class<T>) metadata.getDomainType(), entityManager);
            }
    
            @Override
            protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
                // The RepositoryMetadata can be safely ignored, it is used by the JpaRepositoryFactory
                //to check for QueryDslJpaRepository's which is out of scope.
                return BaseRepositoryImpl.class;
            }
        }
    }
    The problem now is that I have a repository interface that extends BaseRepository like this
    Code:
    @Repository
    public interface StoreRepo extends BaseRepository<Store, Integer, StoreQueryCriteria> {
    }
    However, a call to storeRepo.criteriaSearch(new StoreQueryCriteria())
    throws the exception

    Code:
    Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'storeRepo': FactoryBean threw exception on object creation; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property criteria found for type com.okmich.storeruns.common.entity.Store
    	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:149)
    	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:102)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1441)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:305)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
    	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
    	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
    	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    	at StoreTest.main(StoreTest.java:22)
    Caused by: org.springframework.data.mapping.PropertyReferenceException: No property criteria found for type com.okmich.storeruns.common.entity.Store
    	at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:74)
    	at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:326)
    	at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:352)
    	at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:306)
    	at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:270)
    	at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:244)
    	at org.springframework.data.repository.query.parser.Part.<init>(Part.java:73)
    	at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:180)
    	at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:260)
    	at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:240)
    	at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:68)
    	at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:57)
    	at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:90)
    	at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:162)
    	at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:68)
    	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:280)
    	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:148)
    	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:125)
    	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:41)
    	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
    	... 10 more

    I know this has to do with the Query Derivation strategy. However, for my case I want to override it or better still have a fine grain control so as to prevent derivation of query for this custom method.

    How do I do this? I have googled for a clue but no way so far.


    Regards.
Working...
X