DATACMNS-122 - Introduced further abstractions to improve entity instantiation.
PersistentEntity now has a isConstructorArgument(…) allowing to find out whether a PersistentProperty is referred to from a constructor argument. The PreferredConstructor abstraction now keeps track of the PersistentEntity it is built for and thus allows finding out whether a constructor Parameter maps a PersistentProperty. Removed bean creation responsibility from BeanWrapper and introduced EntityInstantiator abstraction to allow the entity instantiation mechanism be short circuited via custom implementations. The reflection based implementation from BeanWrapper is now residing in ReflectionEntityInstantiator.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.convert;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link EntityInstantiators}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class EntityInstantiatorsUnitTests {
|
||||
|
||||
@Mock
|
||||
PersistentEntity<?, ?> entity;
|
||||
|
||||
@Mock
|
||||
EntityInstantiator customInstantiator;
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullFallbackInstantiator() {
|
||||
new EntityInstantiators((EntityInstantiator) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesReflectionEntityInstantiatorAsDefaultFallback() {
|
||||
|
||||
EntityInstantiators instantiators = new EntityInstantiators();
|
||||
assertThat(instantiators.getInstantiatorFor(entity), is((EntityInstantiator) ReflectionEntityInstantiator.INSTANCE));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void returnsCustomInstantiatorForTypeIfRegistered() {
|
||||
|
||||
when(entity.getType()).thenReturn((Class) String.class);
|
||||
|
||||
Map<Class<?>, EntityInstantiator> customInstantiators = Collections.<Class<?>, EntityInstantiator> singletonMap(
|
||||
String.class, customInstantiator);
|
||||
|
||||
EntityInstantiators instantiators = new EntityInstantiators(customInstantiators);
|
||||
assertThat(instantiators.getInstantiatorFor(entity), is(customInstantiator));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void usesCustomFallbackInstantiatorsIfConfigured() {
|
||||
|
||||
when(entity.getType()).thenReturn((Class) Object.class);
|
||||
|
||||
Map<Class<?>, EntityInstantiator> customInstantiators = Collections.<Class<?>, EntityInstantiator> singletonMap(
|
||||
String.class, ReflectionEntityInstantiator.INSTANCE);
|
||||
|
||||
EntityInstantiators instantiators = new EntityInstantiators(customInstantiator, customInstantiators);
|
||||
instantiators.getInstantiatorFor(entity);
|
||||
|
||||
assertThat(instantiators.getInstantiatorFor(entity), is(customInstantiator));
|
||||
|
||||
when(entity.getType()).thenReturn((Class) String.class);
|
||||
assertThat(instantiators.getInstantiatorFor(entity), is((EntityInstantiator) ReflectionEntityInstantiator.INSTANCE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.convert;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.convert.ReflectionEntityInstantiator.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.PreferredConstructorDiscoverer;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ReflectionEntityInstantiator}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ReflectionEntityInstantiatorUnitTest<P extends PersistentProperty<P>> {
|
||||
|
||||
@Mock
|
||||
PersistentEntity<?, P> entity;
|
||||
@Mock
|
||||
ParameterValueProvider<P> provider;
|
||||
@Mock
|
||||
PreferredConstructor<?, P> constructor;
|
||||
@Mock
|
||||
Parameter<?, P> parameter;
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void instantiatesSimpleObjectCorrectly() {
|
||||
|
||||
when(entity.getType()).thenReturn((Class) Object.class);
|
||||
INSTANCE.createInstance(entity, provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void instantiatesArrayCorrectly() {
|
||||
|
||||
when(entity.getType()).thenReturn((Class) String[][].class);
|
||||
INSTANCE.createInstance(entity, provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void instantiatesTypeWithPreferredConstructorUsingParameterValueProvider() {
|
||||
|
||||
PreferredConstructor constructor = new PreferredConstructorDiscoverer<Foo, P>(Foo.class).getConstructor();
|
||||
|
||||
when(entity.getType()).thenReturn((Class) Foo.class);
|
||||
when(entity.getPersistenceConstructor()).thenReturn(constructor);
|
||||
|
||||
Object instance = INSTANCE.createInstance(entity, provider);
|
||||
|
||||
assertTrue(instance instanceof Foo);
|
||||
verify(provider, times(1)).getParameterValue((Parameter) constructor.getParameters().iterator().next());
|
||||
}
|
||||
|
||||
static class Foo {
|
||||
|
||||
Foo(String foo) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.convert;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleTypeInformationMapperUnitTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
public void resolvesTypeByLoadingClass() {
|
||||
|
||||
TypeInformationMapper mapper = new SimpleTypeInformationMapper();
|
||||
TypeInformation type = mapper.resolveTypeFrom("java.lang.String");
|
||||
|
||||
TypeInformation expected = ClassTypeInformation.from(String.class);
|
||||
|
||||
assertThat(type, is(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnsNullForNonStringKey() {
|
||||
|
||||
TypeInformationMapper mapper = new SimpleTypeInformationMapper();
|
||||
assertThat(mapper.resolveTypeFrom(new Object()), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnsNullForEmptyTypeKey() {
|
||||
|
||||
TypeInformationMapper mapper = new SimpleTypeInformationMapper();
|
||||
assertThat(mapper.resolveTypeFrom(""), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnsNullForUnloadableClass() {
|
||||
|
||||
TypeInformationMapper mapper = new SimpleTypeInformationMapper();
|
||||
assertThat(mapper.resolveTypeFrom("Foo"), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesFullyQualifiedClassNameAsTypeKey() {
|
||||
|
||||
TypeInformationMapper mapper = new SimpleTypeInformationMapper();
|
||||
Object alias = mapper.createAliasFor(ClassTypeInformation.from(String.class));
|
||||
|
||||
assertTrue(alias instanceof String);
|
||||
assertThat(alias, is((Object) String.class.getName()));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
* Copyright 2011-2012 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,48 +25,41 @@ import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.model.PreferredConstructorDiscoverer;
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PreferredConstructorDiscoverer}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PreferredConstructorDiscovererUnitTests {
|
||||
public class PreferredConstructorDiscovererUnitTests<P extends PersistentProperty<P>> {
|
||||
|
||||
@Test
|
||||
public void findsNoArgConstructorForClassWithoutExplicitConstructor() {
|
||||
|
||||
PreferredConstructorDiscoverer<EntityWithoutConstructor> discoverer =
|
||||
new PreferredConstructorDiscoverer<EntityWithoutConstructor>(
|
||||
EntityWithoutConstructor.class);
|
||||
PreferredConstructor<EntityWithoutConstructor> constructor =
|
||||
discoverer.getConstructor();
|
||||
PreferredConstructorDiscoverer<EntityWithoutConstructor, P> discoverer = new PreferredConstructorDiscoverer<EntityWithoutConstructor, P>(
|
||||
EntityWithoutConstructor.class);
|
||||
PreferredConstructor<EntityWithoutConstructor, P> constructor = discoverer.getConstructor();
|
||||
|
||||
assertThat(constructor, is(notNullValue()));
|
||||
assertThat(constructor.isNoArgConstructor(), is(true));
|
||||
assertThat(constructor.isExplicitlyAnnotated(), is(false));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void findsNoArgConstructorForClassWithMultipleConstructorsAndNoArgOne() {
|
||||
|
||||
PreferredConstructorDiscoverer<ClassWithEmptyConstructor> discoverer =
|
||||
new PreferredConstructorDiscoverer<ClassWithEmptyConstructor>(
|
||||
ClassWithEmptyConstructor.class);
|
||||
PreferredConstructor<ClassWithEmptyConstructor> constructor =
|
||||
discoverer.getConstructor();
|
||||
PreferredConstructorDiscoverer<ClassWithEmptyConstructor, P> discoverer = new PreferredConstructorDiscoverer<ClassWithEmptyConstructor, P>(
|
||||
ClassWithEmptyConstructor.class);
|
||||
PreferredConstructor<ClassWithEmptyConstructor, P> constructor = discoverer.getConstructor();
|
||||
|
||||
assertThat(constructor, is(notNullValue()));
|
||||
assertThat(constructor.isNoArgConstructor(), is(true));
|
||||
assertThat(constructor.isExplicitlyAnnotated(), is(false));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void doesNotThrowExceptionForMultipleConstructorsAndNoNoArgConstructorWithoutAnnotation() {
|
||||
|
||||
PreferredConstructorDiscoverer<ClassWithMultipleConstructorsWithoutEmptyOne> discoverer = new PreferredConstructorDiscoverer<ClassWithMultipleConstructorsWithoutEmptyOne>(
|
||||
PreferredConstructorDiscoverer<ClassWithMultipleConstructorsWithoutEmptyOne, P> discoverer = new PreferredConstructorDiscoverer<ClassWithMultipleConstructorsWithoutEmptyOne, P>(
|
||||
ClassWithMultipleConstructorsWithoutEmptyOne.class);
|
||||
assertThat(discoverer.getConstructor(), is(nullValue()));
|
||||
}
|
||||
@@ -74,20 +67,18 @@ public class PreferredConstructorDiscovererUnitTests {
|
||||
@Test
|
||||
public void usesConstructorWithAnnotationOverEveryOther() {
|
||||
|
||||
PreferredConstructorDiscoverer<ClassWithMultipleConstructorsAndAnnotation> discoverer =
|
||||
new PreferredConstructorDiscoverer<ClassWithMultipleConstructorsAndAnnotation>(
|
||||
ClassWithMultipleConstructorsAndAnnotation.class);
|
||||
PreferredConstructor<ClassWithMultipleConstructorsAndAnnotation> constructor =
|
||||
discoverer.getConstructor();
|
||||
PreferredConstructorDiscoverer<ClassWithMultipleConstructorsAndAnnotation, P> discoverer = new PreferredConstructorDiscoverer<ClassWithMultipleConstructorsAndAnnotation, P>(
|
||||
ClassWithMultipleConstructorsAndAnnotation.class);
|
||||
PreferredConstructor<ClassWithMultipleConstructorsAndAnnotation, P> constructor = discoverer.getConstructor();
|
||||
|
||||
assertThat(constructor, is(notNullValue()));
|
||||
assertThat(constructor.isNoArgConstructor(), is(false));
|
||||
assertThat(constructor.isExplicitlyAnnotated(), is(true));
|
||||
|
||||
assertThat(constructor.hasParameters(), is(true));
|
||||
Iterator<Parameter<?>> parameters = constructor.getParameters().iterator();
|
||||
Iterator<Parameter<?, P>> parameters = constructor.getParameters().iterator();
|
||||
|
||||
Parameter<?> parameter = parameters.next();
|
||||
Parameter<?, P> parameter = parameters.next();
|
||||
assertThat(parameter.getType().getType(), typeCompatibleWith(Long.class));
|
||||
assertThat(parameters.hasNext(), is(false));
|
||||
}
|
||||
@@ -107,7 +98,6 @@ public class PreferredConstructorDiscovererUnitTests {
|
||||
public ClassWithMultipleConstructorsAndEmptyOne(String value) {
|
||||
}
|
||||
|
||||
|
||||
public ClassWithMultipleConstructorsAndEmptyOne() {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user