diff --git a/src/main/java/org/springframework/data/jpa/repository/config/EnableJpaRepositories.java b/src/main/java/org/springframework/data/jpa/repository/config/EnableJpaRepositories.java index 299704a4b..96826f684 100644 --- a/src/main/java/org/springframework/data/jpa/repository/config/EnableJpaRepositories.java +++ b/src/main/java/org/springframework/data/jpa/repository/config/EnableJpaRepositories.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2015 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. @@ -131,4 +131,13 @@ public @interface EnableJpaRepositories { * repositories infrastructure. */ boolean considerNestedRepositories() default false; + + /** + * Configures whether to enable default transactions for Spring Data JPA repositories. Defaults to {@literal true}. If + * disabled, repositories must be used behind a facade that's configuring transactions (e.g. using Spring's annotation + * driven transaction facilities) or repository methods have to be used to demarcate transactions. + * + * @return whether to enable default transactions, defaults to {@literal true}. + */ + boolean enableDefaultTransactions() default true; } diff --git a/src/main/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtension.java b/src/main/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtension.java index d992952ed..48c365932 100644 --- a/src/main/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtension.java +++ b/src/main/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -33,14 +33,18 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.dao.DataAccessException; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.support.EntityManagerBeanDefinitionRegistrarPostProcessor; import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean; +import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource; import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport; import org.springframework.data.repository.config.RepositoryConfigurationSource; +import org.springframework.data.repository.config.XmlRepositoryConfigurationSource; import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor; +import org.springframework.util.StringUtils; /** * JPA specific configuration extension parsing custom attributes from the XML namespace and @@ -59,6 +63,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi private static final Class PAB_POST_PROCESSOR = PersistenceAnnotationBeanPostProcessor.class; private static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager"; + private static final String ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE = "enableDefaultTransactions"; /* * (non-Javadoc) @@ -119,6 +124,33 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi builder.addPropertyReference("mappingContext", JPA_MAPPING_CONTEXT_BEAN_NAME); } + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource) + */ + @Override + public void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfigurationSource config) { + + AnnotationAttributes attributes = config.getAttributes(); + + builder.addPropertyValue(ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE, + attributes.getBoolean(ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.XmlRepositoryConfigurationSource) + */ + @Override + public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource config) { + + String enableDefaultTransactions = config.getAttribute(ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE); + + if (StringUtils.hasText(enableDefaultTransactions)) { + builder.addPropertyValue(ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE, enableDefaultTransactions); + } + } + /* * (non-Javadoc) * @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#registerBeansForRoot(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.data.repository.config.RepositoryConfigurationSource) diff --git a/src/main/resources/META-INF/spring.schemas b/src/main/resources/META-INF/spring.schemas index 5589199e3..7d65aa229 100644 --- a/src/main/resources/META-INF/spring.schemas +++ b/src/main/resources/META-INF/spring.schemas @@ -2,4 +2,5 @@ http\://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd=org/springfra http\://www.springframework.org/schema/data/jpa/spring-jpa-1.1.xsd=org/springframework/data/jpa/repository/config/spring-jpa-1.1.xsd http\://www.springframework.org/schema/data/jpa/spring-jpa-1.2.xsd=org/springframework/data/jpa/repository/config/spring-jpa-1.2.xsd http\://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd=org/springframework/data/jpa/repository/config/spring-jpa-1.3.xsd -http\://www.springframework.org/schema/data/jpa/spring-jpa.xsd=org/springframework/data/jpa/repository/config/spring-jpa-1.3.xsd +http\://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd=org/springframework/data/jpa/repository/config/spring-jpa-1.8.xsd +http\://www.springframework.org/schema/data/jpa/spring-jpa.xsd=org/springframework/data/jpa/repository/config/spring-jpa-1.8.xsd diff --git a/src/main/resources/org/springframework/data/jpa/repository/config/spring-jpa-1.8.xsd b/src/main/resources/org/springframework/data/jpa/repository/config/spring-jpa-1.8.xsd new file mode 100644 index 000000000..ae5b2852b --- /dev/null +++ b/src/main/resources/org/springframework/data/jpa/repository/config/spring-jpa-1.8.xsd @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/org/springframework/data/jpa/repository/support/DefaultTransactionDisablingIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/support/DefaultTransactionDisablingIntegrationTests.java new file mode 100644 index 000000000..17311e12b --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/support/DefaultTransactionDisablingIntegrationTests.java @@ -0,0 +1,83 @@ +/* + * Copyright 2015 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 static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import javax.persistence.TransactionRequiredException; + +import org.hamcrest.Matchers; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.jpa.domain.sample.User; +import org.springframework.data.jpa.repository.sample.UserRepository; +import org.springframework.data.jpa.repository.support.TransactionalRepositoryTests.DelegatingTransactionManager; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * Integration tests for disabling default transactions using JavaConfig. + * + * @author Oliver Gierke + * @soundtrack The Intersphere - Live in Mannheim + */ +@RunWith(SpringJUnit4ClassRunner.class) +public abstract class DefaultTransactionDisablingIntegrationTests { + + public @Rule ExpectedException exception = ExpectedException.none(); + + @Autowired UserRepository repository; + @Autowired DelegatingTransactionManager txManager; + + /** + * @see DATAJPA-685 + */ + @Test + public void considersExplicitConfigurationOnRepositoryInterface() { + + repository.findOne(1); + + assertThat(txManager.getDefinition().isReadOnly(), is(false)); + } + + /** + * @see DATAJPA-685 + */ + @Test + public void doesNotUseDefaultTransactionsOnNonRedeclaredMethod() { + + repository.findAll(new PageRequest(0, 10)); + + assertThat(txManager.getDefinition(), is(nullValue())); + } + + /** + * @see DATAJPA-685 + */ + @Test + public void persistingAnEntityShouldThrowExceptionDueToMissingTransaction() { + + exception.expect(InvalidDataAccessApiUsageException.class); + exception.expectCause(is(Matchers. instanceOf(TransactionRequiredException.class))); + + repository.saveAndFlush(new User()); + } +} diff --git a/src/test/java/org/springframework/data/jpa/repository/support/JavaConfigDefaultTransactionDisablingIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/support/JavaConfigDefaultTransactionDisablingIntegrationTests.java new file mode 100644 index 000000000..1dc1175fb --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/support/JavaConfigDefaultTransactionDisablingIntegrationTests.java @@ -0,0 +1,39 @@ +/* + * Copyright 2015 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 org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.data.jpa.repository.sample.UserRepository; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * Integration tests for disabled default configurations via JavaConfig. + * + * @author Oliver Gierke + * @soundtrack The Intersphere - Live in Mannheim + */ +@ContextConfiguration +public class JavaConfigDefaultTransactionDisablingIntegrationTests extends DefaultTransactionDisablingIntegrationTests { + + @Configuration + @EnableJpaRepositories(basePackageClasses = UserRepository.class, enableDefaultTransactions = false) + @EnableTransactionManagement + @ImportResource({ "classpath:infrastructure.xml", "classpath:tx-manager.xml" }) + static class Config {} +} diff --git a/src/test/java/org/springframework/data/jpa/repository/support/XmlConfigDefaultTransactionDisablingIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/support/XmlConfigDefaultTransactionDisablingIntegrationTests.java new file mode 100644 index 000000000..37fe0ed5f --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/support/XmlConfigDefaultTransactionDisablingIntegrationTests.java @@ -0,0 +1,27 @@ +/* + * Copyright 2015 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 org.springframework.test.context.ContextConfiguration; + +/** + * Integration tests for disabled default configurations via XML configuration. + * + * @author Oliver Gierke + * @soundtrack The Intersphere - Live in Mannheim + */ +@ContextConfiguration("disable-default-transactions.xml") +public class XmlConfigDefaultTransactionDisablingIntegrationTests extends DefaultTransactionDisablingIntegrationTests {} diff --git a/src/test/resources/org/springframework/data/jpa/repository/support/disable-default-transactions.xml b/src/test/resources/org/springframework/data/jpa/repository/support/disable-default-transactions.xml new file mode 100644 index 000000000..f6d23413c --- /dev/null +++ b/src/test/resources/org/springframework/data/jpa/repository/support/disable-default-transactions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + +