Announcement Announcement Module
Collapse
No announcement yet.
Spring Data JPA: Custom Implementation Entity Not Managed Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring Data JPA: Custom Implementation Entity Not Managed

    I have created a web application that uses Spring Data + Hibernate + JPA + Quartz. In one of my Quartz jobs I need to refresh an entity, because the entity may have been changed by a user through the user interface. Basically the entity contains the configuration for the Quartz job and if the entity is changed outside the job the data within the entity is stale, so I want to refresh before I persist the entity so that it does not overwrite the updated information.

    Since Spring Data does provide a refresh method on repositories, I created a custom implementation for all Repositories in Spring Data.

    Here is how I setup the custom implementation:

    CustomRepository.java (Interface)

    Code:
        @NoRepositoryBean
        public interface CustomRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
        
        	public void refresh(T entity);
        }
    CustomRepositoryImpl.java (Implementation)

    Code:
        @NoRepositoryBean
        public class CustomRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements CustomRepository<T, ID> {
        
        	private EntityManager entityManager;
        	
        	public CustomRepositoryImpl(Class<T> domainClass, EntityManager entityManager){
        		super(domainClass, entityManager);
        		
        		this.entityManager = entityManager;
        	}
        
        	public void refresh(T entity) {
        		this.entityManager.refresh(entity);
        		
        	}
        }
    CustomRepositoryFactoryBean.java (Factory Bean for Spring)

    Code:
       public class CustomRepositoryFactoryBean<T extends JpaRepository<S,ID>,S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {
        
        	protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager){
        		return new CustomRepositoryFactory(entityManager);
        	}
        	
        	private static class CustomRepositoryFactory<T, ID extends Serializable> extends JpaRepositoryFactory{
        		
        		private EntityManager entityManager;
        		
        		public CustomRepositoryFactory(EntityManager entityManager) {
        			super(entityManager);
        			this.entityManager = entityManager;
        		}
        		
        		protected Object getTargetRepository(RepositoryMetadata metadata){
        			return new CustomRepositoryImpl<T, ID>((Class<T>) metadata.getDomainType(), entityManager);
        		}
        		
        		protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata){
        			return CustomRepository.class;
        		}
        	}
        }
    spring-config.xml

    Code:
        <jpa:repositories base-package="com.network.socially.data.repositories" 
          factory-class="com.network.socially.data.repositories.custom.CustomRepositoryFactoryBean">  
        </jpa:repositories>
    The setup of the custom implementation seems to work when the application initializes via Tomcat, however when I attempt to call the refresh method I recieve an exception.

    Here is the code that calls the refresh method:

    Code:
    	public void execute(JobExecutionContext context) throws JobExecutionException {
    		super.logExecution(context);
    		super.initialize(context);
    
    		this.extractObjects();
    
    		MyJob myJob = this.myJobRepository.findOne(super.applicationJob.getJobId());
    		this.myJobRepository.refresh(myJob);
    	        this.myJobRepository.save(myJob);
    	}
    This throws the exception:

    Code:
        Caused by: java.lang.IllegalArgumentException: Entity not managed
        	at org.hibernate.ejb.AbstractEntityManagerImpl.refresh(AbstractEntityManagerImpl.java:914)
        	at org.hibernate.ejb.AbstractEntityManagerImpl.refresh(AbstractEntityManagerImpl.java:895)
        	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        	at java.lang.reflect.Method.invoke(Unknown Source)
        	at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
        	at $Proxy25.refresh(Unknown Source)
        	at com.network.socially.data.repositories.custom.CustomRepositoryImpl.refresh(CustomRepositoryImpl.java:22)
        	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        	at java.lang.reflect.Method.invoke(Unknown Source)
        	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:333)
        	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:318)
        	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
        	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
        	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
        	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
        	... 10 more
    I don't understand why the entity is not managed since retreiving an entity from the database causes it to be managed in the persistence context.

    Can anyone point out where I am going wrong? Do I need to use JTA instead of RESOURCE-LOCAL? Why is the entity not managed when I retreive it via JPA?
Working...
X