DATACMNS-110 - Added support for CDI integration for repositories.

Added custom CDI extension to use repositories in a CDI environment. Base class picks up all Spring Data repository interfaces and allows working with qualifiers to bind beans to be created to qualifiers.
This commit is contained in:
Dirk Mahler
2011-12-09 13:09:50 +01:00
committed by Oliver Gierke
parent 0334a2dd78
commit eebc822dff
14 changed files with 732 additions and 1 deletions

View File

@@ -0,0 +1,123 @@
/*
* 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.repository.cdi;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.BeanManager;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.repository.Repository;
/**
* Unit tests for {@link CdiRepositoryBean}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class CdiRepositoryBeanUnitTests {
static final Set<Annotation> NO_ANNOTATIONS = Collections.emptySet();
@Mock
BeanManager beanManager;
@Test(expected = IllegalArgumentException.class)
public void voidRejectsNullQualifiers() {
new DummyCdiRepositoryBean<SampleRepository>(null, SampleRepository.class, beanManager);
}
@Test(expected = IllegalArgumentException.class)
public void voidRejectsNullRepositoryType() {
new DummyCdiRepositoryBean<SampleRepository>(NO_ANNOTATIONS, null, beanManager);
}
@Test(expected = IllegalArgumentException.class)
public void voidRejectsNullBeanManager() {
new DummyCdiRepositoryBean<SampleRepository>(NO_ANNOTATIONS, SampleRepository.class, null);
}
@Test
public void returnsBasicMetadata() {
DummyCdiRepositoryBean<SampleRepository> bean = new DummyCdiRepositoryBean<SampleRepository>(
NO_ANNOTATIONS, SampleRepository.class, beanManager);
assertThat(bean.getBeanClass(), is(typeCompatibleWith(SampleRepository.class)));
assertThat(bean.getName(), is(SampleRepository.class.getName()));
assertThat(bean.isNullable(), is(false));
}
@Test
@SuppressWarnings("unchecked")
public void returnsAllImplementedTypes() {
DummyCdiRepositoryBean<SampleRepository> bean = new DummyCdiRepositoryBean<SampleRepository>(
NO_ANNOTATIONS, SampleRepository.class, beanManager);
Set<Type> types = bean.getTypes();
assertThat(types.size(), is(2));
assertThat(types.containsAll(Arrays.asList(SampleRepository.class, Repository.class)), is(true));
}
@Test
public void detectsStereotypes() {
DummyCdiRepositoryBean<StereotypedSampleRepository> bean = new DummyCdiRepositoryBean<StereotypedSampleRepository>(
NO_ANNOTATIONS, StereotypedSampleRepository.class, beanManager);
Set<Class<? extends Annotation>> stereotypes = bean.getStereotypes();
assertThat(stereotypes.size(), is(1));
assertThat(stereotypes, hasItem(StereotypeAnnotation.class));
}
static class DummyCdiRepositoryBean<T> extends CdiRepositoryBean<T> {
public DummyCdiRepositoryBean(Set<Annotation> qualifiers, Class<T> repositoryType, BeanManager beanManager) {
super(qualifiers, repositoryType, beanManager);
}
public Class<? extends Annotation> getScope() {
return null;
}
@Override
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType) {
return null;
}
}
static interface SampleRepository extends Repository<Object, Serializable> {
}
@StereotypeAnnotation
static interface StereotypedSampleRepository {
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.repository.cdi;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Test;
/**
* Common integration tests for Spring Data repository CDI extension.
*
* @author Oliver Gierke
*/
public abstract class CdiRepositoryExtensionSupportIntegrationTests {
@Test
public void createsSpringDataRepositoryBean() {
assertThat(getBean(SampleRepository.class), is(notNullValue()));
RepositoryClient client = getBean(RepositoryClient.class);
assertThat(client.repository, is(notNullValue()));
}
protected abstract <T> T getBean(Class<T> type);
}

View File

@@ -0,0 +1,68 @@
/*
* 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.repository.cdi;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map.Entry;
import java.util.Set;
import javax.enterprise.context.NormalScope;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.BeanManager;
import org.mockito.Mockito;
/**
* Dummy extension of {@link CdiRepositoryExtensionSupport} to allow integration tests. Will create mocks for repository
* interfaces being found.
*
* @author Oliver Gierke
*/
public class DummyCdiExtension extends CdiRepositoryExtensionSupport {
@SuppressWarnings({ "rawtypes", "unchecked" })
void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
for (Entry<Class<?>, Set<Annotation>> type : getRepositoryTypes()) {
afterBeanDiscovery.addBean(new DummyCdiRepositoryBean(type.getValue(), type.getKey(), beanManager));
}
}
static class DummyCdiRepositoryBean<T> extends CdiRepositoryBean<T> {
public DummyCdiRepositoryBean(Set<Annotation> qualifiers, Class<T> repositoryType, BeanManager beanManager) {
super(qualifiers, repositoryType, beanManager);
}
public Class<? extends Annotation> getScope() {
return MyScope.class;
}
@Override
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType) {
return Mockito.mock(repositoryType);
}
}
@NormalScope
@Retention(RetentionPolicy.RUNTIME)
@interface MyScope {
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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.repository.cdi;
import javax.inject.Inject;
/**
*
* @author Oliver Gierke
*/
class RepositoryClient {
@Inject
SampleRepository repository;
}

View File

@@ -0,0 +1,28 @@
/*
* 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.repository.cdi;
import java.io.Serializable;
import org.springframework.data.repository.Repository;
/**
*
* @author Oliver Gierke
*/
public interface SampleRepository extends Repository<Object, Serializable> {
}

View File

@@ -0,0 +1,27 @@
/*
* 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.repository.cdi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.enterprise.inject.Stereotype;
@Stereotype
@Retention(RetentionPolicy.RUNTIME)
@interface StereotypeAnnotation {
}

View File

@@ -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.repository.cdi;
import org.apache.webbeans.cditest.CdiTestContainer;
import org.apache.webbeans.cditest.CdiTestContainerLoader;
import org.junit.AfterClass;
import org.junit.BeforeClass;
/**
* CDI extension integration test using OpenWebbeans.
*
* @author Oliver Gierke
*/
public class WebbeansCdiRepositoryExtensionSupportIntegrationTests extends CdiRepositoryExtensionSupportIntegrationTests {
static CdiTestContainer container;
@BeforeClass
public static void setUp() throws Exception {
container = CdiTestContainerLoader.getCdiContainer();
container.bootContainer();
}
@Override
protected <T> T getBean(Class<T> type) {
return container.getInstance(type);
}
@AfterClass
public static void tearDown() throws Exception {
container.shutdownContainer();
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

View File

@@ -0,0 +1 @@
org.springframework.data.repository.cdi.DummyCdiExtension