Browse Source
Separated ConfigurableTypeInformationMapper from MappingContextTypeInformationMapper. The latter now lazily picks up the alias information if the cached values do not contain aliases. Polished JavaDocs and clarified meaning of null values.1.3.x
10 changed files with 281 additions and 93 deletions
@ -0,0 +1,125 @@
@@ -0,0 +1,125 @@
|
||||
/* |
||||
* Copyright 2011-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 java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.Map.Entry; |
||||
|
||||
import org.springframework.data.mapping.PersistentEntity; |
||||
import org.springframework.data.mapping.context.MappingContext; |
||||
import org.springframework.data.util.TypeInformation; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* {@link TypeInformationMapper} implementation that can be either set up using a {@link MappingContext} or manually set |
||||
* up {@link Map} of {@link String} aliases to types. If a {@link MappingContext} is used the {@link Map} will be build |
||||
* inspecting the {@link PersistentEntity} instances for type alias information. |
||||
* |
||||
* @author Oliver Gierke |
||||
*/ |
||||
public class MappingContextTypeInformationMapper implements TypeInformationMapper { |
||||
|
||||
private final Map<TypeInformation<?>, Object> typeMap; |
||||
private final MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext; |
||||
|
||||
/** |
||||
* Creates a {@link MappingContextTypeInformationMapper} from the given {@link MappingContext}. Inspects all |
||||
* {@link PersistentEntity} instances for alias information and builds a {@link Map} of aliases to types from it. |
||||
* |
||||
* @param mappingContext must not be {@literal null}. |
||||
*/ |
||||
public MappingContextTypeInformationMapper(MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext) { |
||||
|
||||
Assert.notNull(mappingContext); |
||||
|
||||
this.typeMap = new HashMap<TypeInformation<?>, Object>(); |
||||
this.mappingContext = mappingContext; |
||||
|
||||
for (PersistentEntity<?, ?> entity : mappingContext.getPersistentEntities()) { |
||||
safelyAddToCache(entity.getTypeInformation(), entity.getTypeAlias()); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* (non-Javadoc) |
||||
* @see org.springframework.data.convert.TypeInformationMapper#createAliasFor(org.springframework.data.util.TypeInformation) |
||||
*/ |
||||
public Object createAliasFor(TypeInformation<?> type) { |
||||
|
||||
Object key = typeMap.get(type); |
||||
|
||||
if (key != null) { |
||||
return key; |
||||
} |
||||
|
||||
PersistentEntity<?, ?> entity = mappingContext.getPersistentEntity(type); |
||||
|
||||
if (entity == null) { |
||||
return null; |
||||
} |
||||
|
||||
Object alias = entity.getTypeAlias(); |
||||
safelyAddToCache(type, alias); |
||||
|
||||
return alias; |
||||
} |
||||
|
||||
/** |
||||
* Adds the given alias to the cache in a {@literal null}-safe manner. |
||||
* |
||||
* @param key must not be {@literal null}. |
||||
* @param alias can be {@literal null}. |
||||
*/ |
||||
private void safelyAddToCache(TypeInformation<?> key, Object alias) { |
||||
|
||||
if (alias == null) { |
||||
return; |
||||
} |
||||
|
||||
if (typeMap.containsValue(alias)) { |
||||
throw new IllegalArgumentException(String.format( |
||||
"Detected mapping ambiguity! String %s cannot be mapped to more than one type!", alias)); |
||||
} |
||||
|
||||
typeMap.put(key, alias); |
||||
} |
||||
|
||||
/* |
||||
* (non-Javadoc) |
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(java.lang.Object) |
||||
*/ |
||||
public TypeInformation<?> resolveTypeFrom(Object alias) { |
||||
|
||||
if (alias == null) { |
||||
return null; |
||||
} |
||||
|
||||
for (Entry<TypeInformation<?>, Object> entry : typeMap.entrySet()) { |
||||
if (entry.getValue().equals(alias)) { |
||||
return entry.getKey(); |
||||
} |
||||
} |
||||
|
||||
for (PersistentEntity<?, ?> entity : mappingContext.getPersistentEntities()) { |
||||
if (alias.equals(entity.getTypeAlias())) { |
||||
return entity.getTypeInformation(); |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
} |
||||
@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
|
||||
/* |
||||
* 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.Matchers.*; |
||||
import static org.junit.Assert.*; |
||||
import static org.springframework.data.util.ClassTypeInformation.*; |
||||
|
||||
import java.util.Collections; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.springframework.data.annotation.TypeAlias; |
||||
import org.springframework.data.mapping.MappingMetadataTests; |
||||
import org.springframework.data.mapping.MappingMetadataTests.SampleMappingContext; |
||||
import org.springframework.data.mapping.MappingMetadataTests.SampleProperty; |
||||
import org.springframework.data.mapping.PersistentEntity; |
||||
import org.springframework.data.util.ClassTypeInformation; |
||||
import org.springframework.data.util.TypeInformation; |
||||
|
||||
/** |
||||
* Unit tests for {@link MappingContextTypeInformationMapper}. |
||||
* |
||||
* @author Oliver Gierke |
||||
*/ |
||||
public class MappingContextTypeInformationMapperUnitTests { |
||||
|
||||
SampleMappingContext mappingContext; |
||||
TypeInformationMapper mapper; |
||||
|
||||
@Before |
||||
public void setUp() { |
||||
mappingContext = new MappingMetadataTests.SampleMappingContext(); |
||||
} |
||||
|
||||
@Test(expected = IllegalArgumentException.class) |
||||
public void rejectsNullMappingContext() { |
||||
new MappingContextTypeInformationMapper(null); |
||||
} |
||||
|
||||
@Test |
||||
public void extractsAliasInfoFromMappingContext() { |
||||
|
||||
mappingContext.setInitialEntitySet(Collections.singleton(Entity.class)); |
||||
mappingContext.initialize(); |
||||
|
||||
mapper = new MappingContextTypeInformationMapper(mappingContext); |
||||
|
||||
assertThat(mapper.createAliasFor(ClassTypeInformation.from(Entity.class)), is((Object) "foo")); |
||||
} |
||||
|
||||
@Test |
||||
public void extractsAliasForUnknownType() { |
||||
|
||||
SampleMappingContext mappingContext = new MappingMetadataTests.SampleMappingContext(); |
||||
mappingContext.initialize(); |
||||
|
||||
mapper = new MappingContextTypeInformationMapper(mappingContext); |
||||
|
||||
assertThat(mapper.createAliasFor(from(Entity.class)), is((Object) "foo")); |
||||
} |
||||
|
||||
@Test |
||||
public void doesNotReturnTypeAliasForSimpleType() { |
||||
|
||||
SampleMappingContext mappingContext = new MappingMetadataTests.SampleMappingContext(); |
||||
mappingContext.initialize(); |
||||
|
||||
mapper = new MappingContextTypeInformationMapper(mappingContext); |
||||
assertThat(mapper.createAliasFor(from(String.class)), is(nullValue())); |
||||
} |
||||
|
||||
@Test |
||||
@SuppressWarnings("rawtypes") |
||||
public void detectsTypeForUnknownEntity() { |
||||
|
||||
SampleMappingContext mappingContext = new MappingMetadataTests.SampleMappingContext(); |
||||
mappingContext.initialize(); |
||||
|
||||
mapper = new MappingContextTypeInformationMapper(mappingContext); |
||||
assertThat(mapper.resolveTypeFrom("foo"), is(nullValue())); |
||||
|
||||
PersistentEntity<?, SampleProperty> entity = mappingContext.getPersistentEntity(Entity.class); |
||||
|
||||
assertThat(entity, is(notNullValue())); |
||||
assertThat(mapper.resolveTypeFrom("foo"), is((TypeInformation) from(Entity.class))); |
||||
} |
||||
|
||||
@TypeAlias("foo") |
||||
static class Entity { |
||||
|
||||
} |
||||
} |
||||
Loading…
Reference in new issue