From 64caad04a37c7e7bd588f48bf981ea1d36d9d4bf Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 14 Apr 2014 21:49:25 +0200 Subject: [PATCH] DATACMNS-485 - Fixed false negative type alias detection in MappingContextTypeInformationMapper. MappingContextTypeInformationMapper now considers the raw type only for type alias conflict detection. --- .../MappingContextTypeInformationMapper.java | 26 ++++++++++++-- ...ContextTypeInformationMapperUnitTests.java | 35 +++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/springframework/data/convert/MappingContextTypeInformationMapper.java b/src/main/java/org/springframework/data/convert/MappingContextTypeInformationMapper.java index b3adb5a26..15fcde8f5 100644 --- a/src/main/java/org/springframework/data/convert/MappingContextTypeInformationMapper.java +++ b/src/main/java/org/springframework/data/convert/MappingContextTypeInformationMapper.java @@ -21,6 +21,7 @@ import java.util.Map.Entry; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; @@ -90,12 +91,31 @@ public class MappingContextTypeInformationMapper implements TypeInformationMappe return; } - if (typeMap.containsValue(alias)) { + TypeInformation toStore = ClassTypeInformation.from(key.getType()); + Object existingAlias = typeMap.get(toStore); + + // Reject second alias for same type + + if (existingAlias != null && !alias.equals(existingAlias)) { throw new IllegalArgumentException(String.format( - "Detected mapping ambiguity! String %s cannot be mapped to more than one type!", alias)); + "Trying to register alias '%s', but found already registered alias '%s' for type %s!", alias, existingAlias, + toStore)); } - typeMap.put(key, alias); + // Reject second type for same alias + + if (typeMap.containsValue(alias)) { + + for (Entry, Object> entry : typeMap.entrySet()) { + if (entry.getValue().equals(alias) && !entry.getKey().equals(toStore)) { + throw new IllegalArgumentException(String.format( + "Detected existing type mapping of %s to alias '%s' but attempted to bind the same alias to %s!", + toStore, alias, entry.getKey())); + } + } + } + + typeMap.put(toStore, alias); } /* diff --git a/src/test/java/org/springframework/data/convert/MappingContextTypeInformationMapperUnitTests.java b/src/test/java/org/springframework/data/convert/MappingContextTypeInformationMapperUnitTests.java index 549fc5520..85350f413 100644 --- a/src/test/java/org/springframework/data/convert/MappingContextTypeInformationMapperUnitTests.java +++ b/src/test/java/org/springframework/data/convert/MappingContextTypeInformationMapperUnitTests.java @@ -27,6 +27,7 @@ import org.springframework.data.annotation.TypeAlias; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.context.SampleMappingContext; import org.springframework.data.mapping.context.SamplePersistentProperty; +import org.springframework.data.util.AnnotatedTypeScanner; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; @@ -98,8 +99,42 @@ public class MappingContextTypeInformationMapperUnitTests { assertThat(mapper.resolveTypeFrom("foo"), is((TypeInformation) from(Entity.class))); } + /** + * @see DATACMNS-485 + */ + @Test + @SuppressWarnings("unchecked") + public void createsTypeMapperForGenericTypesWithDifferentBindings() { + + AnnotatedTypeScanner scanner = new AnnotatedTypeScanner(TypeAlias.class); + + SampleMappingContext context = new SampleMappingContext(); + context.setInitialEntitySet(scanner.findTypes(getClass().getPackage().getName())); + context.initialize(); + + new MappingContextTypeInformationMapper(context); + } + @TypeAlias("foo") static class Entity { } + + @TypeAlias("genericType") + static class GenericType { + + } + + @TypeAlias("concreteWrapper") + static class ConcreteWrapper { + + GenericType stringGeneric; + GenericType integerGeneric; + } + + @TypeAlias("genericWrapper") + static class GenericWrapper { + + GenericType genericGeneric; + } }