From 9005e1903daca2230b4475a08f595d40e49fbdb4 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 28 Feb 2012 19:03:58 +0100 Subject: [PATCH] DATACMNS-133 - Improved DomainClassConverter implementation. DomainClassConverter now registers itself with the ConversionService handed into it. Added integration tests for lookup of RepositoryFactoryInformation. --- .../support/DomainClassConverter.java | 60 +++++------ .../AbstractEntityInformationUnitTests.java | 29 ------ .../DummyAbstractEntityInformation.java | 51 ++++++++++ .../DomainClassConverterIntegrationTests.java | 99 +++++++++++++++++++ .../DomainClassConverterUnitTests.java | 11 +-- 5 files changed, 177 insertions(+), 73 deletions(-) create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/DummyAbstractEntityInformation.java create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/repository/support/DomainClassConverterIntegrationTests.java diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java index 01fb2f854..df932e11f 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java @@ -28,6 +28,7 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.ConditionalGenericConverter; +import org.springframework.core.convert.converter.ConverterRegistry; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.core.support.RepositoryFactoryInformation; @@ -40,57 +41,41 @@ import org.springframework.data.repository.core.support.RepositoryFactoryInforma * * @author Oliver Gierke */ -public class DomainClassConverter implements ConditionalGenericConverter, ApplicationContextAware { +public class DomainClassConverter implements + ConditionalGenericConverter, ApplicationContextAware { private final Map, CrudRepository> repositories = new HashMap, CrudRepository>(); - private final ConversionService service; + private final T conversionService; - /** - * Creates a new {@link DomainClassConverter}. - * - * @param service - */ - public DomainClassConverter(ConversionService service) { - - this.service = service; + public DomainClassConverter(T conversionService) { + this.conversionService = conversionService; } /* - * (non-Javadoc) - * - * @see org.springframework.core.convert.converter.GenericConverter# - * getConvertibleTypes() - */ + * (non-Javadoc) + * @see org.springframework.core.convert.converter.GenericConverter#getConvertibleTypes() + */ public Set getConvertibleTypes() { - return Collections.singleton(new ConvertiblePair(Object.class, Object.class)); } /* - * (non-Javadoc) - * - * @see - * org.springframework.core.convert.converter.GenericConverter#convert(java - * .lang.Object, org.springframework.core.convert.TypeDescriptor, - * org.springframework.core.convert.TypeDescriptor) - */ + * (non-Javadoc) + * @see org.springframework.core.convert.converter.GenericConverter#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor) + */ public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { EntityInformation info = getRepositoryForDomainType(targetType.getType()); CrudRepository repository = repositories.get(info); - Serializable id = service.convert(source, info.getIdType()); + Serializable id = conversionService.convert(source, info.getIdType()); return repository.findOne(id); } /* - * (non-Javadoc) - * - * @see - * org.springframework.core.convert.converter.ConditionalGenericConverter - * #matches(org.springframework.core.convert.TypeDescriptor, - * org.springframework.core.convert.TypeDescriptor) - */ + * (non-Javadoc) + * @see org.springframework.core.convert.converter.ConditionalGenericConverter#matches(org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor) + */ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { EntityInformation info = getRepositoryForDomainType(targetType.getType()); @@ -99,7 +84,7 @@ public class DomainClassConverter implements ConditionalGenericConverter, Applic return false; } - return service.canConvert(sourceType.getType(), info.getIdType()); + return conversionService.canConvert(sourceType.getType(), info.getIdType()); } private EntityInformation getRepositoryForDomainType(Class domainType) { @@ -115,12 +100,9 @@ public class DomainClassConverter implements ConditionalGenericConverter, Applic } /* - * (non-Javadoc) - * - * @see - * org.springframework.context.ApplicationContextAware#setApplicationContext - * (org.springframework.context.ApplicationContext) - */ + * (non-Javadoc) + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ @SuppressWarnings({ "unchecked", "rawtypes" }) public void setApplicationContext(ApplicationContext context) { @@ -135,5 +117,7 @@ public class DomainClassConverter implements ConditionalGenericConverter, Applic this.repositories.put(metadata, repository); } + + this.conversionService.addConverter(this); } } diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/AbstractEntityInformationUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/AbstractEntityInformationUnitTests.java index 238033386..fe00a2bbe 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/AbstractEntityInformationUnitTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/AbstractEntityInformationUnitTests.java @@ -22,7 +22,6 @@ import java.io.Serializable; import org.junit.Test; import org.springframework.data.repository.core.EntityInformation; -import org.springframework.data.repository.core.support.AbstractEntityInformation; /** * Unit tests for {@link AbstractEntityInformation}. @@ -44,32 +43,4 @@ public class AbstractEntityInformationUnitTests { assertThat(metadata.isNew(null), is(true)); assertThat(metadata.isNew(new Object()), is(false)); } - - private static class DummyAbstractEntityInformation extends AbstractEntityInformation { - - public DummyAbstractEntityInformation(Class domainClass) { - - super(domainClass); - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.data.repository.support.EntityMetadata#getId( - * java.lang.Object) - */ - public Serializable getId(Object entity) { - - return entity == null ? null : entity.toString(); - } - - /* (non-Javadoc) - * @see org.springframework.data.repository.support.EntityInformation#getIdType() - */ - public Class getIdType() { - - return Serializable.class; - } - } } diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/DummyAbstractEntityInformation.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/DummyAbstractEntityInformation.java new file mode 100644 index 000000000..817c71b86 --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/DummyAbstractEntityInformation.java @@ -0,0 +1,51 @@ +/* + * 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.repository.core.support; + +import java.io.Serializable; + +/** + * Dummy implementation of {@link AbstractEntityInformation}. + * + * @author Oliver Gierke + */ +public class DummyAbstractEntityInformation extends AbstractEntityInformation { + + /** + * Creates a new {@link DummyAbstractEntityInformation} for the given domain class. + * + * @param domainClass + */ + public DummyAbstractEntityInformation(Class domainClass) { + super(domainClass); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.EntityInformation#getId(java.lang.Object) + */ + public Serializable getId(Object entity) { + return entity == null ? null : entity.toString(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.EntityInformation#getIdType() + */ + public Class getIdType() { + return Serializable.class; + } +} \ No newline at end of file diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/DomainClassConverterIntegrationTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/DomainClassConverterIntegrationTests.java new file mode 100644 index 000000000..add88aefe --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/DomainClassConverterIntegrationTests.java @@ -0,0 +1,99 @@ +/* + * 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.repository.support; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.Serializable; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.core.support.DummyAbstractEntityInformation; +import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport; +import org.springframework.data.repository.core.support.RepositoryFactoryInformation; + +/** + * Integration test for {@link DomainClassConverter}. + * + * @author Oliver Gierke + */ +@RunWith(MockitoJUnitRunner.class) +public class DomainClassConverterIntegrationTests { + + @Mock + @SuppressWarnings("rawtypes") + static RepositoryFactoryBeanSupport factory; + @Mock + static PersonRepository repository; + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void findsRepositoryFactories() { + + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory() { + @Override + protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) { + return beanName.equals("repoFactory") ? new BeanWrapperImpl(factory) : super.instantiateBean(beanName, mbd); + } + }; + + beanFactory.registerBeanDefinition("postProcessor", new RootBeanDefinition(PredictingProcessor.class)); + beanFactory.registerBeanDefinition("repoFactory", new RootBeanDefinition(RepositoryFactoryBeanSupport.class)); + + DummyAbstractEntityInformation entityInformation = new DummyAbstractEntityInformation(Person.class); + when(factory.getObject()).thenReturn(repository); + when(factory.getObjectType()).thenReturn(PersonRepository.class); + when(factory.getEntityInformation()).thenReturn(entityInformation); + when(factory.getRepositoryInterface()).thenReturn(PersonRepository.class); + + GenericApplicationContext context = new GenericApplicationContext(beanFactory); + assertThat(context.getBeansOfType(RepositoryFactoryInformation.class).values().size(), is(1)); + + DomainClassConverter converter = new DomainClassConverter(new DefaultConversionService()); + converter.setApplicationContext(context); + + assertThat(converter.matches(TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Person.class)), is(true)); + } + + static class Person { + + } + + static interface PersonRepository extends CrudRepository { + + } + + static class PredictingProcessor extends InstantiationAwareBeanPostProcessorAdapter { + + @Override + public Class predictBeanType(Class beanClass, String beanName) { + return RepositoryFactoryBeanSupport.class.equals(beanClass) ? PersonRepository.class : null; + } + } +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/DomainClassConverterUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/DomainClassConverterUnitTests.java index 9d489d954..74c651ba4 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/DomainClassConverterUnitTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/DomainClassConverterUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 the original author or authors. + * Copyright 2008-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. @@ -17,9 +17,7 @@ package org.springframework.data.repository.support; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.argThat; -import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; import java.util.HashMap; @@ -33,8 +31,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.context.ApplicationContext; -import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.core.support.RepositoryFactoryInformation; @@ -49,6 +47,7 @@ public class DomainClassConverterUnitTests { static final User USER = new User(); + @SuppressWarnings("rawtypes") DomainClassConverter converter; TypeDescriptor sourceDescriptor; @@ -62,7 +61,7 @@ public class DomainClassConverterUnitTests { @Mock UserRepository repository; @Mock - ConversionService service; + DefaultConversionService service; @Mock EntityInformation information; @Mock