Skip to content

DATAJPA-562 - Support for pluggable generic post-processing of JPA Query results. #99

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.7.0.BUILD-SNAPSHOT</version>
<version>1.7.0.DATAJPA-562-SNAPSHOT</version>

<name>Spring Data JPA</name>
<description>Spring Data module for JPA repositories.</description>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2008-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.support;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;

import org.springframework.util.Assert;

/**
* A {@link JpaResultPostProcessor} that potentially detaches resulting Domain-Objects from the configured
* {@link EntityManager}.
*
* @author Thomas Darimont
*/
public class DetachingJpaResultPostProcessor implements JpaResultPostProcessor {

private final EntityManager em;

/**
* Creates a new {@link DetachingJpaResultPostProcessor}.
*
* @param em must not be {@literal null}.
*/
public DetachingJpaResultPostProcessor(EntityManager em) {

Assert.notNull(em, "EntityManager must not be null!");

this.em = em;
}

/* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.JpaResultPostProcessor#postProcessResult(java.lang.Class, java.lang.Object)
*/
@Override
public <T, R> R postProcessResult(Class<T> domainClass, R entity) {

if (domainClass.isInstance(entity)) {
em.detach(entity);
}

return entity;
}

/* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.JpaResultPostProcessor#postProcessResults(java.lang.Class, java.util.List)
*/
@Override
public <T> List<T> postProcessResults(Class<T> domainClass, List<T> results) {

List<T> postProcessedResults = new ArrayList<T>();

for (T entity : results) {
if (domainClass.isInstance(entity)) {
postProcessedResults.add(postProcessResult(domainClass, entity));
}
}

return postProcessedResults;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,38 @@
* JPA specific generic repository factory.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class JpaRepositoryFactory extends RepositoryFactorySupport {

private final EntityManager entityManager;
private final QueryExtractor extractor;
private final CrudMethodMetadataPostProcessor lockModePostProcessor;
private final JpaResultPostProcessor jpaResultPostProcessor;

/**
* Creates a new {@link JpaRepositoryFactory}.
*
* @param entityManager must not be {@literal null}
*/
public JpaRepositoryFactory(EntityManager entityManager) {
this(entityManager, NoopJpaResultPostProcessor.INSTANCE);
}

/**
* Creates a new {@link JpaRepositoryFactory}.
*
* @param entityManager must not be {@literal null}
* @param evaluationContextProvider must not be {@literal null}
*/
public JpaRepositoryFactory(EntityManager entityManager, JpaResultPostProcessor jpaResultPostProcessor) {

Assert.notNull(entityManager);

this.entityManager = entityManager;
this.extractor = PersistenceProvider.fromEntityManager(entityManager);
this.lockModePostProcessor = CrudMethodMetadataPostProcessor.INSTANCE;
this.jpaResultPostProcessor = jpaResultPostProcessor;

addRepositoryProxyPostProcessor(lockModePostProcessor);
}
Expand All @@ -68,6 +81,10 @@ protected Object getTargetRepository(RepositoryMetadata metadata) {
SimpleJpaRepository<?, ?> repository = getTargetRepository(metadata, entityManager);
repository.setRepositoryMethodMetadata(lockModePostProcessor.getLockMetadataProvider());

if (jpaResultPostProcessor != null) {
repository.setJpaResultPostProcessor(jpaResultPostProcessor);
}

return repository;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
public class JpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends
TransactionalRepositoryFactoryBeanSupport<T, S, ID> {

private EntityManager entityManager;
protected EntityManager entityManager;

private JpaResultPostProcessor jpaResultPostProcessor;

/**
* The {@link EntityManager} to be used.
Expand All @@ -58,6 +60,16 @@ public void setMappingContext(MappingContext<?, ?> mappingContext) {
super.setMappingContext(mappingContext);
}

/**
* The {@link JpaResultPostProcessor} to be used.
*
* @param jpaResultPostProcessor the jpaResultPostProcessor to set.
* @since 1.7
*/
public void setJpaResultPostProcessor(JpaResultPostProcessor jpaResultPostProcessor) {
this.jpaResultPostProcessor = jpaResultPostProcessor;
}

/*
* (non-Javadoc)
*
Expand All @@ -76,7 +88,7 @@ protected RepositoryFactorySupport doCreateRepositoryFactory() {
* @return
*/
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new JpaRepositoryFactory(entityManager);
return new JpaRepositoryFactory(entityManager, jpaResultPostProcessor);
}

/*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2008-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.support;

import java.util.List;

/**
* A {@link JpaResultPostProcessor} allows to post-process a single or multiple entity result.
*
* @author Thomas Darimont
*/
public interface JpaResultPostProcessor {

/**
* @param domainClass
* @param entity
* @return
*/
<T, R> R postProcessResult(Class<T> domainClass, R entity);

/**
* @param domainClass
* @param results
* @return
*/
<T> List<T> postProcessResults(Class<T> domainClass, List<T> results);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2008-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.support;

import java.util.List;

/**
* A {@link JpaResultPostProcessor} that simply returns the results as is.
*
* @author Thomas Darimont
*/
enum NoopJpaResultPostProcessor implements JpaResultPostProcessor {

INSTANCE;

/* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.JpaResultPostProcessor#postProcessResult(java.lang.Class, java.lang.Object)
*/
@Override
public <T, R> R postProcessResult(Class<T> domainClass, R entity) {
return entity;
}

/* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.JpaResultPostProcessor#postProcessResults(java.lang.Class, java.util.List)
*/
@Override
public <T> List<T> postProcessResults(Class<T> domainClass, List<T> results) {
return results;
}
}
Loading