diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractMappingContext.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractMappingContext.java index ac3f3f500..bec397368 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractMappingContext.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractMappingContext.java @@ -65,15 +65,7 @@ public abstract class AbstractMappingContext> customSimpleTypes = new ArrayList>(); private Set> initialEntitySet = new HashSet>(); private boolean strict = false; - - /** - * Sets types to be considered simple. That means these types will not be mapped recusively. - * - * @param customSimpleTypes the customSimpleTypes to set - */ - public void setCustomSimpleTypes(List> customSimpleTypes) { - this.customSimpleTypes = customSimpleTypes; - } + private SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder(); /* * (non-Javadoc) @@ -103,6 +95,10 @@ public abstract class AbstractMappingContext getTypeInformationIfNotSimpleType(TypeInformation information) { - return information == null || MappingBeanHelper.isSimpleType(information.getType()) ? null : information; + return information == null || simpleTypeHolder.isSimpleType(information.getType()) ? null : information; } public List getEntityValidators(E entity) { @@ -282,7 +278,7 @@ public abstract class AbstractMappingContext E createPersistentEntity(TypeInformation typeInformation); - protected abstract P createPersistentProperty(Field field, PropertyDescriptor descriptor, E owner); + protected abstract P createPersistentProperty(Field field, PropertyDescriptor descriptor, E owner, SimpleTypeHolder simpleTypeHolder); public void afterPropertiesSet() { diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractPersistentProperty.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractPersistentProperty.java index 91f20c2b5..eb1dd0c8c 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractPersistentProperty.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractPersistentProperty.java @@ -28,6 +28,7 @@ import org.springframework.data.mapping.model.Association; import org.springframework.data.mapping.model.PersistentEntity; import org.springframework.data.mapping.model.PersistentProperty; import org.springframework.data.util.TypeInformation; +import org.springframework.util.Assert; /** * Simple impementation of {@link PersistentProperty}. @@ -44,8 +45,12 @@ public abstract class AbstractPersistentProperty

protected final Field field; protected final Association

association; protected final PersistentEntity owner; + private final SimpleTypeHolder simpleTypeHolder; - public AbstractPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity owner) { + public AbstractPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { + + Assert.notNull(simpleTypeHolder); + this.name = field.getName(); this.rawType = field.getType(); this.information = owner.getTypeInformation().getProperty(this.name); @@ -53,6 +58,7 @@ public abstract class AbstractPersistentProperty

this.field = field; this.association = isAssociation() ? createAssociation() : null; this.owner = owner; + this.simpleTypeHolder = simpleTypeHolder; } protected abstract Association

createAssociation(); @@ -127,9 +133,9 @@ public abstract class AbstractPersistentProperty

public boolean isComplexType() { if (isCollection() || isArray()) { - return !MappingBeanHelper.isSimpleType(getComponentType()); + return !simpleTypeHolder.isSimpleType(getComponentType()); } else { - return !MappingBeanHelper.isSimpleType(getType()); + return !simpleTypeHolder.isSimpleType(getType()); } } diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AnnotationBasedPersistentProperty.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AnnotationBasedPersistentProperty.java index a0f15f2ed..c00703843 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AnnotationBasedPersistentProperty.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AnnotationBasedPersistentProperty.java @@ -45,10 +45,9 @@ public abstract class AnnotationBasedPersistentProperty

owner) { + public AnnotationBasedPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { - super(field, propertyDescriptor, owner); + super(field, propertyDescriptor, owner, simpleTypeHolder); this.value = field.getAnnotation(Value.class); field.isAnnotationPresent(Autowired.class); } diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/MappingBeanHelper.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/MappingBeanHelper.java deleted file mode 100644 index 723ce71aa..000000000 --- a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/MappingBeanHelper.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2011 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. - * 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.mapping; - -import java.util.Collections; -import java.util.Date; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Helper class to set and retrieve bean values. - * - * @author Jon Brisbin - * @author Oliver Gierke - */ -public abstract class MappingBeanHelper { - - private static final Set> simpleTypes = Collections.newSetFromMap(new ConcurrentHashMap, Boolean>()); - - static { - simpleTypes.add(boolean.class); - simpleTypes.add(boolean[].class); - simpleTypes.add(long.class); - simpleTypes.add(long[].class); - simpleTypes.add(short.class); - simpleTypes.add(short[].class); - simpleTypes.add(int.class); - simpleTypes.add(int[].class); - simpleTypes.add(byte.class); - simpleTypes.add(byte[].class); - simpleTypes.add(float.class); - simpleTypes.add(float[].class); - simpleTypes.add(double.class); - simpleTypes.add(double[].class); - simpleTypes.add(char.class); - simpleTypes.add(char[].class); - simpleTypes.add(Boolean.class); - simpleTypes.add(Long.class); - simpleTypes.add(Short.class); - simpleTypes.add(Integer.class); - simpleTypes.add(Byte.class); - simpleTypes.add(Float.class); - simpleTypes.add(Double.class); - simpleTypes.add(Character.class); - simpleTypes.add(String.class); - simpleTypes.add(Date.class); - simpleTypes.add(Locale.class); - simpleTypes.add(Class.class); - simpleTypes.add(Number.class); - } - - /** - * Returns the set of types considered to be simple. - * - * @return - */ - public static Set> getSimpleTypes() { - return simpleTypes; - } - - /** - * Returns whether the given type is considered a simple one. - * - * @param type - * @return - */ - public static boolean isSimpleType(Class type) { - for (Class clazz : simpleTypes) { - if (type == clazz || clazz.isAssignableFrom(type)) { - return true; - } - } - return type.isEnum(); - } -} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/SimpleTypeHolder.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/SimpleTypeHolder.java new file mode 100644 index 000000000..05089eb82 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/SimpleTypeHolder.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2011 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. + * 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.mapping; + +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +import org.springframework.util.Assert; + +/** + * Simple container to hold a set of types to be considered simple types. + * + * @author Oliver Gierke + */ +public class SimpleTypeHolder { + + private static final Set> DEFAULTS = new HashSet>(); + + static { + DEFAULTS.add(boolean.class); + DEFAULTS.add(boolean[].class); + DEFAULTS.add(long.class); + DEFAULTS.add(long[].class); + DEFAULTS.add(short.class); + DEFAULTS.add(short[].class); + DEFAULTS.add(int.class); + DEFAULTS.add(int[].class); + DEFAULTS.add(byte.class); + DEFAULTS.add(byte[].class); + DEFAULTS.add(float.class); + DEFAULTS.add(float[].class); + DEFAULTS.add(double.class); + DEFAULTS.add(double[].class); + DEFAULTS.add(char.class); + DEFAULTS.add(char[].class); + DEFAULTS.add(Boolean.class); + DEFAULTS.add(Long.class); + DEFAULTS.add(Short.class); + DEFAULTS.add(Integer.class); + DEFAULTS.add(Byte.class); + DEFAULTS.add(Float.class); + DEFAULTS.add(Double.class); + DEFAULTS.add(Character.class); + DEFAULTS.add(String.class); + DEFAULTS.add(Date.class); + DEFAULTS.add(Locale.class); + DEFAULTS.add(Class.class); + DEFAULTS.add(Number.class); + } + + private final Set> simpleTypes; + + /** + * Creates a new {@link SimpleTypeHolder} containing the default types. + * + * @see #SimpleTypeHolder(Set, boolean) + */ + @SuppressWarnings("unchecked") + public SimpleTypeHolder() { + this(Collections.EMPTY_SET, true); + } + + /** + * Creates a new {@link SimpleTypeHolder} to carry the given custom simple types. Registration of default simple types + * can be deactivated by passing {@literal false} for {@code registerDefaults}. + * + * @param customSimpleTypes + * @param registerDefaults + */ + public SimpleTypeHolder(Set> customSimpleTypes, boolean registerDefaults) { + + Assert.notNull(customSimpleTypes); + this.simpleTypes = new HashSet>(customSimpleTypes); + + if (registerDefaults) { + this.simpleTypes.addAll(DEFAULTS); + } + } + + /** + * Copy constructor to create a new {@link SimpleTypeHolder} that carries the given additional custom simple types. + * + * @param customSimpleTypes must not be {@literal null} + * @param source must not be {@literal null} + */ + public SimpleTypeHolder(Set> customSimpleTypes, SimpleTypeHolder source) { + + Assert.notNull(customSimpleTypes); + Assert.notNull(source); + + this.simpleTypes = new HashSet>(customSimpleTypes); + this.simpleTypes.addAll(source.simpleTypes); + } + + /** + * Returns whether the given type is considered a simple one. + * + * @param type + * @return + */ + public boolean isSimpleType(Class type) { + for (Class clazz : simpleTypes) { + if (type == clazz || clazz.isAssignableFrom(type)) { + return true; + } + } + return type.isEnum(); + } +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java index 5ccade0f6..734f69835 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java @@ -73,8 +73,9 @@ public class MappingMetadataTests { @Override protected SampleProperty createPersistentProperty(Field field, PropertyDescriptor descriptor, - MutablePersistentEntity owner) { - return new SamplePropertyImpl(field, descriptor, owner); + MutablePersistentEntity owner, + SimpleTypeHolder simpleTypeHolder) { + return new SamplePropertyImpl(field, descriptor, owner, simpleTypeHolder); } } @@ -82,9 +83,10 @@ public class MappingMetadataTests { public SamplePropertyImpl(Field field, PropertyDescriptor propertyDescriptor, - PersistentEntity owner) { + PersistentEntity owner, + SimpleTypeHolder simpleTypeHolder) { - super(field, propertyDescriptor, owner); + super(field, propertyDescriptor, owner, simpleTypeHolder); } @Override diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/SimpleTypeHolderUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/SimpleTypeHolderUnitTests.java new file mode 100644 index 000000000..54605f225 --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/SimpleTypeHolderUnitTests.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011 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. + * 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.mapping; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import java.util.Collections; +import java.util.HashSet; + +import org.junit.Test; + +/** + * Unit tests for {@link SimpleTypeHolder}. + * + * @author Oliver Gierke + */ +public class SimpleTypeHolderUnitTests { + + @Test(expected = IllegalArgumentException.class) + public void rejectsNullCustomTypes() { + new SimpleTypeHolder(null, false); + } + + @Test(expected = IllegalArgumentException.class) + public void rejectsNullOriginal() { + new SimpleTypeHolder(new HashSet>(), null); + } + + @Test + public void addsDefaultTypes() { + + SimpleTypeHolder holder = new SimpleTypeHolder(); + + assertThat(holder.isSimpleType(String.class), is(true)); + } + + @Test + public void doesNotAddDefaultConvertersIfConfigured() { + + SimpleTypeHolder holder = new SimpleTypeHolder(new HashSet>(), false); + + assertThat(holder.isSimpleType(String.class), is(false)); + } + + @Test + public void addsCustomTypesToSimpleOnes() { + + SimpleTypeHolder holder = new SimpleTypeHolder(Collections.singleton(SimpleTypeHolder.class), true); + + assertThat(holder.isSimpleType(SimpleTypeHolder.class), is(true)); + assertThat(holder.isSimpleType(SimpleTypeHolderUnitTests.class), is(false)); + } + + @Test + public void createsHolderFromAnotherOneCorrectly() { + + SimpleTypeHolder holder = new SimpleTypeHolder(Collections.singleton(SimpleTypeHolder.class), true); + SimpleTypeHolder second = new SimpleTypeHolder(Collections.singleton(SimpleTypeHolderUnitTests.class), holder); + + assertThat(holder.isSimpleType(SimpleTypeHolder.class), is(true)); + assertThat(holder.isSimpleType(SimpleTypeHolderUnitTests.class), is(false)); + assertThat(second.isSimpleType(SimpleTypeHolder.class), is(true)); + assertThat(second.isSimpleType(SimpleTypeHolderUnitTests.class), is(true)); + } +}