DATAJPA-69 - Added JavaConfig support for repositories.

The repositories can now be bootstrapped using @EnableJpaRepositories annotation as follows:

@Configuration
@EnableJpaRepositories
class ApplicationConfig {
  
  // … declare EntityManagerFactory
  // … declare PlatformTransactionManager
}
This commit is contained in:
Oliver Gierke
2011-12-02 17:40:47 +01:00
parent de16544194
commit 2087ce29d2
18 changed files with 637 additions and 287 deletions

View File

@@ -92,6 +92,66 @@
</table>
</simplesect>
</section>
<section>
<title>Annotation based configuration</title>
<para>The Spring Data JPA repositories support cannot only be activated
through an XML namespace but also using an annotation through
JavaConfig. </para>
<example id="id2371211_05-jpa">
<title>Spring Data JPA repositories using JavaConfig</title>
<programlisting id="id2359286_05-jpa" language="java">@Configuration
@EnableJpaRepositories
@EnableTransactionManagement
class ApplicationConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
@Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.acme.domain");
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
}</programlisting>
</example>
<para>The just shown configuration class sets up an embedded HSQL
database using the <classname>EmbeddedDatabaseBuilder</classname> API of
spring-jdbc. We then set up a
<interfacename>EntityManagerFactory</interfacename> and use Hibernate as
sample persistence provider. The last infrastructure component declared
here is the <classname>JpaTransactionManager</classname>. We eventually
activate Spring Data JPA repositories using the
<interfacename>@EnableJpaRepositories</interfacename> annotation which
essentially carries the same attributes as the XML namespace does. If no
base package is configured it will use the one the configuration class
resides in.</para>
</section>
</section>
<section id="jpa.query-methods">
@@ -570,7 +630,7 @@ int setFixedFirstnameFor(String firstname, String lastname);</programlisting>
<interfacename>Specification</interfacename>s in a variety of ways.</para>
<para>For example, the <code>readAll</code> method will return all
entities that match the specification: </para>
entities that match the specification:</para>
<programlisting language="java">List&lt;T&gt; readAll(Specification&lt;T&gt; spec);</programlisting>

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2012 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.config;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.persistence.EntityManagerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Annotation to enable JPA repositories. Will scan the package of the annotated configuration class for Spring Data
* repositories by default.
*
* @author Oliver Gierke
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(JpaRepositoriesRegistrar.class)
public @interface EnableJpaRepositories {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
* {@code @EnableJpaRepositories("org.my.pkg")} instead of {@code @EnableJpaRepositories(basePackages="org.my.pkg")}.
*/
String[] value() default {};
/**
* Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this
* attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names.
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The
* package of each class specified will be scanned. Consider creating a special no-op marker class or interface in
* each package that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
/**
* Specifies which types are eligible for component scanning. Further narrows the set of candidate components from
* everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters.
*/
Filter[] includeFilters() default {};
/**
* Specifies which types are not eligible for component scanning.
*/
Filter[] excludeFilters() default {};
/**
* Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So
* for a repository named {@code PersonRepository} the corresponding implementation class will be looked up scanning
* for {@code PersonRepositoryImpl}.
*
* @return
*/
String repositoryImplementationPostfix() default "Impl";
/**
* Configures the location of where to find the Spring Data named queries properties file. Will default to
* {@code META-INFO/jpa-named-queries.properties}.
*
* @return
*/
String namedQueriesLocation() default "";
/**
* Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to
* {@link Key#CREATE_IF_NOT_FOUND}.
*
* @return
*/
Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND;
/**
* Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to
* {@link JpaRepositoryFactoryBean}.
*
* @return
*/
Class<?> repositoryFactoryBeanClass() default JpaRepositoryFactoryBean.class;
// JPA sepcific configuration
/**
* Configures the name of the {@link EntityManagerFactory} bean definition to be used to create repositories
* discovered through this annotation. Defaults to {@code entityManagerFactory}.
*
* @return
*/
String entityManagerFactoryRef() default "entityManagerFactory";
/**
* /** Configures the name of the {@link PlatformTransactionManager} bean definition to be used to create repositories
* discovered through this annotation. Defaults to {@code transactionManager}.
*
* @return
*/
String transactionManagerRef() default "transactionManager";
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2012 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.config;
import java.lang.annotation.Annotation;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
/**
* {@link ImportBeanDefinitionRegistrar} to enable {@link EnableJpaRepositories} annotation.
*
* @author Oliver Gierke
*/
class JpaRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport {
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getAnnotation()
*/
@Override
protected Class<? extends Annotation> getAnnotation() {
return EnableJpaRepositories.class;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getExtension()
*/
@Override
protected RepositoryConfigurationExtension getExtension() {
return new JpaRepositoryConfigExtension();
}
}

View File

@@ -1,126 +0,0 @@
/*
* Copyright 2008-2011 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.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.SimpleJpaRepositoryConfiguration.JpaRepositoryConfiguration;
import org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser;
import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Parser to create bean definitions for repositories namespace. Registers bean definitions for repositories as well as
* {@code PersistenceAnnotationBeanPostProcessor} and {@code PersistenceExceptionTranslationPostProcessor} to
* transparently inject entity manager factory instance and apply exception translation.
* <p>
* The definition parser allows two ways of configuration. Either it looks up the manually defined repository instances
* or scans the defined domain package for candidates for repositories.
*
* @author Oliver Gierke
* @author Eberhard Wolff
* @author Gil Markham
*/
class JpaRepositoryConfigDefinitionParser extends
AbstractRepositoryConfigDefinitionParser<SimpleJpaRepositoryConfiguration, JpaRepositoryConfiguration> {
private static final Class<?> PAB_POST_PROCESSOR = PersistenceAnnotationBeanPostProcessor.class;
private static final Class<?> PET_POST_PROCESSOR = PersistenceExceptionTranslationPostProcessor.class;
private static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser#getGlobalRepositoryConfigInformation(org.w3c.dom.Element)
*/
@Override
protected SimpleJpaRepositoryConfiguration getGlobalRepositoryConfigInformation(Element element) {
return new SimpleJpaRepositoryConfiguration(element);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser#postProcessBeanDefinition(org.springframework.data.repository.config.SingleRepositoryConfigInformation, org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
*/
@Override
protected void postProcessBeanDefinition(JpaRepositoryConfiguration ctx, BeanDefinitionBuilder builder,
BeanDefinitionRegistry registry, Object beanSource) {
String transactionManagerRef = StringUtils.hasText(ctx.getTransactionManagerRef()) ? ctx.getTransactionManagerRef()
: DEFAULT_TRANSACTION_MANAGER_BEAN_NAME;
builder.addPropertyValue("transactionManager", transactionManagerRef);
String entityManagerRef = ctx.getEntityManagerFactoryRef();
if (StringUtils.hasText(entityManagerRef)) {
builder.addPropertyValue("entityManager", getEntityManagerBeanDefinitionFor(entityManagerRef, beanSource));
}
}
/**
* Creates an anonymous factory to extract the actual {@link javax.persistence.EntityManager} from the
* {@link javax.persistence.EntityManagerFactory} bean name reference.
*
* @param entityManagerFactoryBeanName
* @param source
* @return
*/
private BeanDefinition getEntityManagerBeanDefinitionFor(String entityManagerFactoryBeanName, Object source) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition("org.springframework.orm.jpa.SharedEntityManagerCreator");
builder.setFactoryMethod("createSharedEntityManager");
builder.addConstructorArgReference(entityManagerFactoryBeanName);
AbstractBeanDefinition bean = builder.getRawBeanDefinition();
bean.setSource(source);
return bean;
}
/**
* Registers an additional {@link org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor} to
* trigger automatic injextion of {@link javax.persistence.EntityManager} .
*
* @param registry
* @param source
*/
@Override
protected void registerBeansForRoot(BeanDefinitionRegistry registry, Object source) {
super.registerBeansForRoot(registry, source);
if (!hasBean(PET_POST_PROCESSOR, registry)) {
AbstractBeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(PET_POST_PROCESSOR)
.getBeanDefinition();
registerWithSourceAndGeneratedBeanName(registry, definition, source);
}
if (!hasBean(PAB_POST_PROCESSOR, registry)) {
AbstractBeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(PAB_POST_PROCESSOR)
.getBeanDefinition();
registerWithSourceAndGeneratedBeanName(registry, definition, source);
}
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright 2012 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.config;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
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;
import org.w3c.dom.Element;
/**
* JPA specific configuration extension parsing custom attributes from the XML namespace and
* {@link EnableJpaRepositories} annotation. Also, it registers bean definitions for a
* {@link PersistenceAnnotationBeanPostProcessor} (to trigger injection into {@link PersistenceContext}/
* {@link PersistenceUnit} annotated properties and methods) as well as
* {@link PersistenceExceptionTranslationPostProcessor} to enable exception translation of persistence specific
* exceptions into Spring's {@link DataAccessException} hierarchy.
*
* @author Oliver Gierke
* @author Eberhard Wolff
* @author Gil Markham
*/
public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport {
private static final Class<?> PAB_POST_PROCESSOR = PersistenceAnnotationBeanPostProcessor.class;
private static final Class<?> PET_POST_PROCESSOR = PersistenceExceptionTranslationPostProcessor.class;
private static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config14.RepositoryConfigurationExtension#getRepositoryInterface()
*/
public String getRepositoryFactoryClassName() {
return JpaRepositoryFactoryBean.class.getName();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config14.RepositoryConfigurationExtensionSupport#getModulePrefix()
*/
@Override
protected String getModulePrefix() {
return "jpa";
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config14.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config14.XmlRepositoryConfigurationSource)
*/
@Override
public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource config) {
Element element = config.getElement();
postProcess(builder, element.getAttribute("transaction-manager-ref"),
element.getAttribute("entity-manager-factory-ref"), config.getSource());
}
/*
* (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();
postProcess(builder, attributes.getString("transactionManagerRef"),
attributes.getString("entityManagerFactoryRef"), config.getSource());
}
private void postProcess(BeanDefinitionBuilder builder, String transactionManagerRef, String entityManagerRef,
Object source) {
transactionManagerRef = StringUtils.hasText(transactionManagerRef) ? transactionManagerRef
: DEFAULT_TRANSACTION_MANAGER_BEAN_NAME;
builder.addPropertyValue("transactionManager", transactionManagerRef);
if (StringUtils.hasText(entityManagerRef)) {
builder.addPropertyValue("entityManager", getEntityManagerBeanDefinitionFor(entityManagerRef, source));
}
}
/**
* Creates an anonymous factory to extract the actual {@link javax.persistence.EntityManager} from the
* {@link javax.persistence.EntityManagerFactory} bean name reference.
*
* @param entityManagerFactoryBeanName
* @param source
* @return
*/
private BeanDefinition getEntityManagerBeanDefinitionFor(String entityManagerFactoryBeanName, Object source) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition("org.springframework.orm.jpa.SharedEntityManagerCreator");
builder.setFactoryMethod("createSharedEntityManager");
builder.addConstructorArgReference(entityManagerFactoryBeanName);
AbstractBeanDefinition bean = builder.getRawBeanDefinition();
bean.setSource(source);
return bean;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#registerBeansForRoot(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.data.repository.config.RepositoryConfigurationSource)
*/
@Override
public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource configurationSource) {
super.registerBeansForRoot(registry, configurationSource);
if (!hasBean(PET_POST_PROCESSOR, registry)) {
AbstractBeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(PET_POST_PROCESSOR)
.getBeanDefinition();
registerWithSourceAndGeneratedBeanName(registry, definition, configurationSource.getSource());
}
if (!hasBean(PAB_POST_PROCESSOR, registry)) {
AbstractBeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(PAB_POST_PROCESSOR)
.getBeanDefinition();
registerWithSourceAndGeneratedBeanName(registry, definition, configurationSource.getSource());
}
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.data.jpa.repository.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.data.repository.config.RepositoryBeanDefinitionParser;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
/**
* Simple namespace handler for {@literal repositories} namespace.
@@ -31,7 +33,10 @@ public class JpaRepositoryNameSpaceHandler extends NamespaceHandlerSupport {
*/
public void init() {
registerBeanDefinitionParser("repositories", new JpaRepositoryConfigDefinitionParser());
RepositoryConfigurationExtension extension = new JpaRepositoryConfigExtension();
RepositoryBeanDefinitionParser repositoryBeanDefinitionParser = new RepositoryBeanDefinitionParser(extension);
registerBeanDefinitionParser("repositories", repositoryBeanDefinitionParser);
registerBeanDefinitionParser("auditing", new AuditingBeanDefinitionParser());
}
}

View File

@@ -1,135 +0,0 @@
/*
* Copyright 2008-2011 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.config;
import org.springframework.data.repository.config.AutomaticRepositoryConfigInformation;
import org.springframework.data.repository.config.ManualRepositoryConfigInformation;
import org.springframework.data.repository.config.RepositoryConfig;
import org.springframework.data.repository.config.SingleRepositoryConfigInformation;
import org.w3c.dom.Element;
/**
* @author Oliver Gierke
*/
public class SimpleJpaRepositoryConfiguration extends
RepositoryConfig<SimpleJpaRepositoryConfiguration.JpaRepositoryConfiguration, SimpleJpaRepositoryConfiguration> {
private static final String FACTORY_CLASS = "org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean";
private static final String ENTITY_MANAGER_FACTORY_REF = "entity-manager-factory-ref";
/**
* @param repositoriesElement
*/
public SimpleJpaRepositoryConfiguration(Element repositoriesElement) {
super(repositoriesElement, FACTORY_CLASS);
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.repository.config.GlobalRepositoryConfigInformation
* #getAutoconfigRepositoryInformation(java.lang.String)
*/
public JpaRepositoryConfiguration getAutoconfigRepositoryInformation(String interfaceName) {
return new AutomaticJpaRepositoryConfigInformation(interfaceName, this);
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.jpa.repository.config.RepositoryConfigContext
* #getManualRepositoryInformation(org.w3c.dom.Element,
* org.springframework.data
* .jpa.repository.config.CommonRepositoryInformation)
*/
@Override
public JpaRepositoryConfiguration createSingleRepositoryConfigInformationFor(Element element) {
return new ManualJpaRepositoryConfigInformation(element, this);
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.repository.config.CommonRepositoryConfigInformation
* #getNamedQueriesLocation()
*/
public String getNamedQueriesLocation() {
return "classpath*:META-INF/jpa-named-queries.properties";
}
/**
* Returns the name of the entity manager factory bean.
*
* @return
*/
public String getEntityManagerFactoryRef() {
return getSource().getAttribute(ENTITY_MANAGER_FACTORY_REF);
}
private static class AutomaticJpaRepositoryConfigInformation extends
AutomaticRepositoryConfigInformation<SimpleJpaRepositoryConfiguration> implements JpaRepositoryConfiguration {
public AutomaticJpaRepositoryConfigInformation(String interfaceName, SimpleJpaRepositoryConfiguration parent) {
super(interfaceName, parent);
}
/**
* Returns the {@link javax.persistence.EntityManagerFactory} reference to be used for all the repository instances
* configured.
*
* @return
*/
public String getEntityManagerFactoryRef() {
return getParent().getEntityManagerFactoryRef();
}
}
private static class ManualJpaRepositoryConfigInformation extends
ManualRepositoryConfigInformation<SimpleJpaRepositoryConfiguration> implements JpaRepositoryConfiguration {
public ManualJpaRepositoryConfigInformation(Element element, SimpleJpaRepositoryConfiguration parent) {
super(element, parent);
}
/*
* (non-Javadoc)
*
* @see org.springframework.data.jpa.repository.config.
* SimpleJpaRepositoryConfiguration
* .JpaRepositoryConfiguration#getEntityManagerFactoryRef()
*/
public String getEntityManagerFactoryRef() {
return getAttribute(ENTITY_MANAGER_FACTORY_REF);
}
}
interface JpaRepositoryConfiguration extends SingleRepositoryConfigInformation<SimpleJpaRepositoryConfiguration> {
String getEntityManagerFactoryRef();
}
}

View File

@@ -1,3 +1,4 @@
http\://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd=org/springframework/data/jpa/repository/config/spring-jpa-1.0.xsd
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.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.xsd=org/springframework/data/jpa/repository/config/spring-jpa-1.2.xsd

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://www.springframework.org/schema/data/jpa"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:repository="http://www.springframework.org/schema/data/repository"
targetNamespace="http://www.springframework.org/schema/data/jpa"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/tool" />
<xsd:import namespace="http://www.springframework.org/schema/context"
schemaLocation="http://www.springframework.org/schema/context/spring-context.xsd" />
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository.xsd" />
<xsd:element name="repositories">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="repository:repositories">
<xsd:attributeGroup ref="repository:transactional-repository-attributes" />
<xsd:attribute name="entity-manager-factory-ref" type="entityManagerFactoryRef" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="auditing">
<xsd:complexType>
<xsd:attribute name="auditor-aware-ref">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.domain.AuditorAware" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="set-dates" default="true" type="xsd:boolean" />
<xsd:attribute name="date-time-provider-ref">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.jpa.domain.support.DateTimeProvider" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="entityManagerFactoryRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.orm.jpa.AbstractEntityManagerFactoryBean" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string" />
</xsd:simpleType>
</xsd:schema>

View File

@@ -61,7 +61,7 @@ import org.springframework.transaction.annotation.Transactional;
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:application-context.xml" })
@ContextConfiguration("classpath:application-context.xml")
@Transactional
public class UserRepositoryTests {
@@ -889,6 +889,18 @@ public class UserRepositoryTests {
assertThat(repository.count(), is(count));
}
@Test
public void ordersByReferencedEntityCorrectly() {
flushTestUsers();
firstUser.setManager(thirdUser);
repository.save(firstUser);
Page<User> all = repository.findAll(new PageRequest(0, 10, new Sort("manager.id")));
assertThat(all.getContent().isEmpty(), is(false));
}
private Page<User> executeSpecWithSort(Sort sort) {
flushTestUsers();

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2012 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.config;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.orm.jpa.JpaDialect;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Integration test for {@link JpaRepositoriesRegistrar}.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class JpaRepositoriesRegistrarIntegrationTests {
@Autowired
UserRepository repository;
@Configuration
@EnableJpaRepositories(basePackages = "org.springframework.data.jpa.repository.sample")
static class Config {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().build();
}
@Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource());
factory.setPersistenceUnitName("default");
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean
public JpaDialect jpaDialect() {
return new HibernateJpaDialect();
}
@Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
}
@Test
public void foo() {
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2012 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.config;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.data.jpa.repository.sample.UserRepository;
/**
* Unit test for {@link JpaRepositoriesRegistrar}.
*
* @author Oliver Gierke
*/
public class JpaRepositoriesRegistrarUnitTests {
BeanDefinitionRegistry registry;
AnnotationMetadata metadata;
@Before
public void setUp() {
metadata = new StandardAnnotationMetadata(Config.class, true);
registry = new DefaultListableBeanFactory();
}
@Test
public void configuresRepositoriesCorrectly() {
ImportBeanDefinitionRegistrar registrar = new JpaRepositoriesRegistrar();
registrar.registerBeanDefinitions(metadata, registry);
Iterable<String> names = Arrays.asList(registry.getBeanDefinitionNames());
assertThat(names, hasItems("userRepository", "auditableUserRepository", "roleRepository"));
}
@EnableJpaRepositories(basePackageClasses = UserRepository.class)
class Config {
}
}

View File

@@ -5,7 +5,7 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" default-lazy-init="true">
<!-- Needed to check that the BFPP only adds depends-on if spring-configured s activated -->
<!-- Needed to check that the BFPP only adds depends-on if spring-configured is activated -->
<context:spring-configured />
<import resource="../infrastructure.xml" />

View File

@@ -3,21 +3,18 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="../infrastructure.xml" />
<context:spring-configured />
<jpa:auditing auditor-aware-ref="auditorAware" />
<bean id="auditorAware" class="org.springframework.data.jpa.domain.sample.AuditorAwareStub">
<constructor-arg ref="auditableUserRepository" />
</bean>
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample">
<jpa:repository id="auditableUserRepository" />
</jpa:repositories>
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample" />
</beans>

View File

@@ -7,8 +7,6 @@
<import resource="../infrastructure.xml" />
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample">
<jpa:repository id="roleRepository" query-lookup-strategy="use-declared-query" />
</jpa:repositories>
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample" query-lookup-strategy="use-declared-query" />
</beans>

View File

@@ -23,11 +23,7 @@
! do not have to be explicitly registered as they are included by namespace parser !
-->
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample" >
<jpa:repository id="userRepository" />
<jpa:repository id="roleRepository" />
<jpa:repository id="auditableUserRepository" query-lookup-strategy="create" />
</jpa:repositories>
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample" />
<!-- Register custom DAO implementation explicitly -->
<bean id="userRepositoryImpl" class="org.springframework.data.jpa.repository.sample.UserRepositoryImpl" />

View File

@@ -3,8 +3,11 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:repository="http://www.springframework.org/schema/data/repository"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="entityManagerFactory" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="javax.persistence.EntityManagerFactory" />
@@ -15,7 +18,7 @@
</bean>
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample" entity-manager-factory-ref="secondEntityManagerFactory">
<jpa:repository id="userRepository" />
<repository:include-filter type="assignable" expression="org.springframework.data.jpa.repository.sample.UserRepository" />
</jpa:repositories>
</beans>

View File

@@ -2,8 +2,10 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:repository="http://www.springframework.org/schema/data/repository"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
@@ -39,14 +41,13 @@
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample"
entity-manager-factory-ref="entityManagerFactory">
<jpa:repository id="userRepository" />
<jpa:repository id="roleRepository" />
<repository:exclude-filter type="assignable" expression="org.springframework.data.jpa.repository.sample.AuditableUserRepository" />
</jpa:repositories>
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample"
entity-manager-factory-ref="entityManagerFactory-2"
transaction-manager-ref="transactionManager-2">
<jpa:repository id="auditableUserRepository" />
<repository:include-filter type="assignable" expression="org.springframework.data.jpa.repository.sample.AuditableUserRepository" />
</jpa:repositories>
</beans>