) bean);
+ }
+ }
+ }
+
+ /**
+ * Implementation of a an observer which registers beans to the CDI container for the detected Spring Data
+ * repositories.
+ *
+ * The repository beans are associated to the EntityManagers using their qualifiers.
+ *
+ * @param beanManager The BeanManager instance.
+ */
+ void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
+
+ for (Entry, Set> entry : getRepositoryTypes()) {
+
+ Class> repositoryType = entry.getKey();
+ Set qualifiers = entry.getValue();
+ // Create the bean representing the repository.
+ Bean> repositoryBean = createRepositoryBean(repositoryType, qualifiers, beanManager);
+ LOGGER.info("Registering bean for '{}' with qualifiers {}.", repositoryType.getName(), qualifiers);
+ // Register the bean to the container.
+ afterBeanDiscovery.addBean(repositoryBean);
+ }
+ }
+
+ /**
+ * Creates a {@link Bean}.
+ *
+ * @param The type of the repository.
+ * @param repositoryType The class representing the repository.
+ * @param beanManager The BeanManager instance.
+ * @return The bean.
+ */
+ private Bean createRepositoryBean(Class repositoryType, Set qualifiers, BeanManager beanManager) {
+
+ // Determine the entity manager bean which matches the qualifiers of the repository.
+ Bean entityManagerBean = entityManagers.get(qualifiers);
+
+ if (entityManagerBean == null) {
+ throw new UnsatisfiedResolutionException(String.format("Unable to resolve a bean for '%s' with qualifiers %s.",
+ EntityManager.class.getName(), qualifiers));
+ }
+
+ // Construct and return the repository bean.
+ return new JpaRepositoryBean(beanManager, entityManagerBean, qualifiers, repositoryType);
+ }
+}
diff --git a/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
new file mode 100644
index 000000000..87ad49ceb
--- /dev/null
+++ b/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -0,0 +1 @@
+org.springframework.data.jpa.repository.cdi.JpaRepositoryExtension
\ No newline at end of file
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/CdiExtensionintegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/cdi/CdiExtensionintegrationTests.java
new file mode 100644
index 000000000..c6945a2fa
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/CdiExtensionintegrationTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 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.cdi;
+
+import org.apache.webbeans.cditest.CdiTestContainer;
+import org.apache.webbeans.cditest.CdiTestContainerLoader;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Integration tests for Spring Data JPA CDI extension.
+ *
+ * @author Dirk Mahler
+ * @author Oliver Gierke
+ */
+public class CdiExtensionintegrationTests {
+
+ static CdiTestContainer container;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ container = CdiTestContainerLoader.getCdiContainer();
+ container.bootContainer();
+ }
+
+ @Test
+ public void saveAndFindAll() {
+
+ RepositoryConsumer repositoryConsumer = container.getInstance(RepositoryConsumer.class);
+
+ Person person = new Person();
+ repositoryConsumer.save(person);
+ repositoryConsumer.findAll();
+ }
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/EntityManagerFactoryProducer.java b/src/test/java/org/springframework/data/jpa/repository/cdi/EntityManagerFactoryProducer.java
new file mode 100644
index 000000000..73e91fa53
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/EntityManagerFactoryProducer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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.cdi;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Disposes;
+import javax.enterprise.inject.Produces;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+class EntityManagerFactoryProducer {
+
+ @Produces
+ @ApplicationScoped
+ public EntityManagerFactory createEntityManagerFactory() {
+ return Persistence.createEntityManagerFactory("cdi");
+ }
+
+ public void close(@Disposes EntityManagerFactory entityManagerFactory) {
+ entityManagerFactory.close();
+ }
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/Person.java b/src/test/java/org/springframework/data/jpa/repository/cdi/Person.java
new file mode 100644
index 000000000..00cf53b2d
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/Person.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 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.cdi;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+class Person {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+
+ private String name;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/PersonDB.java b/src/test/java/org/springframework/data/jpa/repository/cdi/PersonDB.java
new file mode 100644
index 000000000..893407628
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/PersonDB.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 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.cdi;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
+@interface PersonDB {
+
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/PersonRepository.java b/src/test/java/org/springframework/data/jpa/repository/cdi/PersonRepository.java
new file mode 100644
index 000000000..30c5ba231
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/PersonRepository.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 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.cdi;
+
+import java.util.List;
+
+interface PersonRepository {
+
+ List findAll();
+
+ void save(Person person);
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedEntityManagerProducer.java b/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedEntityManagerProducer.java
new file mode 100644
index 000000000..68001fc7d
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedEntityManagerProducer.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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.cdi;
+
+import javax.enterprise.inject.Disposes;
+import javax.enterprise.inject.Produces;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+
+class QualifiedEntityManagerProducer {
+
+ @Produces
+ @PersonDB
+ public EntityManager createEntityManager(EntityManagerFactory entityManagerFactory) {
+ return entityManagerFactory.createEntityManager();
+ }
+
+ public void close(@Disposes @PersonDB EntityManager entityManager) {
+ entityManager.close();
+ }
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedPersonRepository.java b/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedPersonRepository.java
new file mode 100644
index 000000000..71882fd34
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedPersonRepository.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 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.cdi;
+
+import org.springframework.data.repository.Repository;
+
+@PersonDB
+interface QualifiedPersonRepository extends PersonRepository, Repository {
+
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/RepositoryConsumer.java b/src/test/java/org/springframework/data/jpa/repository/cdi/RepositoryConsumer.java
new file mode 100644
index 000000000..40ad8313c
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/RepositoryConsumer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.cdi;
+
+import javax.inject.Inject;
+
+@Transactional
+class RepositoryConsumer {
+
+ @Inject
+ private PersonRepository unqualifiedRepo;
+
+ @Inject
+ @PersonDB
+ private PersonRepository qualifiedRepo;
+
+ public void findAll() {
+ unqualifiedRepo.findAll();
+ qualifiedRepo.findAll();
+ }
+
+ public void save(Person person) {
+ unqualifiedRepo.save(person);
+ qualifiedRepo.save(person);
+ }
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/Transactional.java b/src/test/java/org/springframework/data/jpa/repository/cdi/Transactional.java
new file mode 100644
index 000000000..c59bb56f4
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/Transactional.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 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.cdi;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.interceptor.InterceptorBinding;
+
+@InterceptorBinding
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@interface Transactional {
+
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/TransactionalInterceptor.java b/src/test/java/org/springframework/data/jpa/repository/cdi/TransactionalInterceptor.java
new file mode 100644
index 000000000..eacf7a90c
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/TransactionalInterceptor.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 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.
+ */
+/*
+ * Copyright 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.cdi;
+
+import javax.enterprise.inject.Any;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+
+@Transactional
+@Interceptor
+class TransactionalInterceptor {
+
+ @Inject
+ @Any
+ private EntityManager entityManager;
+
+ @AroundInvoke
+ public Object runInTransaction(InvocationContext ctx) throws Exception {
+ EntityTransaction entityTransaction = this.entityManager.getTransaction();
+ boolean isNew = !entityTransaction.isActive();
+ try {
+ if (isNew) {
+ entityTransaction.begin();
+ }
+ Object result = ctx.proceed();
+ if (isNew) {
+ entityTransaction.commit();
+ }
+ return result;
+ } catch (RuntimeException r) {
+ if (isNew) {
+ entityTransaction.rollback();
+ }
+ throw r;
+ }
+ }
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedEntityManagerProducer.java b/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedEntityManagerProducer.java
new file mode 100644
index 000000000..6b90f9f37
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedEntityManagerProducer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 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.cdi;
+
+import javax.enterprise.inject.Disposes;
+import javax.enterprise.inject.Produces;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+
+class UnqualifiedEntityManagerProducer {
+
+ @Produces
+ public EntityManager createEntityManager(EntityManagerFactory entityManagerFactory) {
+ return entityManagerFactory.createEntityManager();
+ }
+
+ public void close(@Disposes EntityManager entityManager) {
+ entityManager.close();
+ }
+}
diff --git a/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedPersonRepository.java b/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedPersonRepository.java
new file mode 100644
index 000000000..9c1e9c8cd
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedPersonRepository.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 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.cdi;
+
+import org.springframework.data.repository.Repository;
+
+interface UnqualifiedPersonRepository extends PersonRepository, Repository {
+
+}
diff --git a/src/test/resources/META-INF/beans.xml b/src/test/resources/META-INF/beans.xml
new file mode 100644
index 000000000..73ae3a251
--- /dev/null
+++ b/src/test/resources/META-INF/beans.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/src/test/resources/META-INF/persistence.xml b/src/test/resources/META-INF/persistence.xml
index 26226dc55..ebda8a710 100644
--- a/src/test/resources/META-INF/persistence.xml
+++ b/src/test/resources/META-INF/persistence.xml
@@ -17,4 +17,18 @@
org.springframework.data.jpa.domain.sample.User
true
+
+ org.hibernate.ejb.HibernatePersistence
+ org.springframework.data.jpa.domain.sample.User
+ org.springframework.data.jpa.repository.cdi.Person
+ true
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/infrastructure.xml b/src/test/resources/infrastructure.xml
index 84a90e427..f9c563882 100644
--- a/src/test/resources/infrastructure.xml
+++ b/src/test/resources/infrastructure.xml
@@ -10,6 +10,7 @@
+
diff --git a/template.mf b/template.mf
index da3c9e376..424336cef 100644
--- a/template.mf
+++ b/template.mf
@@ -10,6 +10,7 @@ Import-Template:
com.mysema.query.*;version="${querydsl.version:[=.=.=,+1.0.0)}";resolution:=optional,
javax.persistence.*;version="${jpa.version:[=.=.=,+1.0.0)}",
javax.annotation.*;version="0.0.0",
+ javax.enterprise.*;version="${cdi.version:[=.=.=,+1.0.0)}";resolution:=optional,
org.aopalliance.*;version="[1.0.0,2.0.0)",
org.apache.openjpa.persistence.*;version="${openjpa.version:[=.=.=,+1.0.0)}";resolution:=optional,
org.aspectj.*;version="${aspectj.version:[=.=.=,+1.0.0)}";resolution:=optional,