diff --git a/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java index 776177a19..55933a649 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java @@ -18,6 +18,7 @@ package org.springframework.data.jpa.repository.query; import javax.persistence.EntityManager; import javax.persistence.Query; import javax.persistence.Tuple; +import javax.persistence.metamodel.ManagedType; import org.springframework.data.repository.query.EvaluationContextProvider; import org.springframework.data.repository.query.ParameterAccessor; @@ -137,6 +138,25 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery { ResultProcessor resultFactory = getQueryMethod().getResultProcessor(); ReturnedType returnedType = resultFactory.getReturnedType(); - return returnedType.isProjecting() ? em.createQuery(queryString, Tuple.class) : em.createQuery(queryString); + return returnedType.isProjecting() && !isJpaManaged(returnedType.getReturnedType(), em) + ? em.createQuery(queryString, Tuple.class) : em.createQuery(queryString); + } + + /** + * Returns whether the given type is managed by the given {@link EntityManager} + * @param type must not be {@literal null}. + * @param em must not be {@literal null}. + * + * @return + */ + private static boolean isJpaManaged(Class type, EntityManager em) { + + for (ManagedType managedType : em.getMetamodel().getManagedTypes()) { + if (managedType.getJavaType().equals(type)) { + return true; + } + } + + return false; } } diff --git a/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java new file mode 100644 index 000000000..4c7fbdcfd --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2016 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.query; + +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +import java.lang.reflect.Method; +import java.util.Set; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.Tuple; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.data.jpa.domain.sample.Role; +import org.springframework.data.jpa.domain.sample.User; +import org.springframework.data.jpa.provider.PersistenceProvider; +import org.springframework.data.projection.SpelAwareProxyProjectionFactory; +import org.springframework.data.repository.Repository; +import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; +import org.springframework.data.repository.query.DefaultEvaluationContextProvider; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * Integration tests for {@link AbstractStringBasedJpaQuery}. + * + * @author Oliver Gierke + * @soundtrack Henrik Freischlader Trio - Nobody Else To Blame (Openness) + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:infrastructure.xml") +public class AbstractStringBasedJpaQueryIntegrationTests { + + @PersistenceContext EntityManager em; + + /** + * @see DATAJPA-885 + */ + @Test + public void createsNormalQueryForJpaManagedReturnTypes() throws Exception { + + EntityManager mock = mock(EntityManager.class); + when(mock.getEntityManagerFactory()).thenReturn(em.getEntityManagerFactory()); + when(mock.getMetamodel()).thenReturn(em.getMetamodel()); + + JpaQueryMethod method = getMethod("findRolesByEmailAddress", String.class); + AbstractStringBasedJpaQuery jpaQuery = new SimpleJpaQuery(method, mock, DefaultEvaluationContextProvider.INSTANCE, + new SpelExpressionParser()); + + jpaQuery.createJpaQuery(method.getAnnotatedQuery()); + + verify(mock, times(1)).createQuery(anyString()); + verify(mock, times(0)).createQuery(anyString(), eq(Tuple.class)); + } + + private JpaQueryMethod getMethod(String name, Class... parameterTypes) throws Exception { + + Method method = SampleRepository.class.getMethod(name, parameterTypes); + PersistenceProvider persistenceProvider = PersistenceProvider.fromEntityManager(em); + + return new JpaQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class), + new SpelAwareProxyProjectionFactory(), persistenceProvider); + } + + interface SampleRepository extends Repository { + + @org.springframework.data.jpa.repository.Query("select u.roles from User u where u.emailAddress = ?1") + Set findRolesByEmailAddress(String emailAddress); + } +}