DATACMNS-1101 - Use non-capturing lambdas in CustomConversions for conversion lookup.

This commit is contained in:
Mark Paluch
2017-06-27 17:12:43 +02:00
committed by Oliver Gierke
parent 38d9b08132
commit ce9aae49c8
4 changed files with 54 additions and 35 deletions

View File

@@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.converter.Converter;
@@ -69,8 +70,8 @@ public class CustomConversions {
DEFAULT_CONVERTERS = Collections.unmodifiableList(defaults);
}
private final Set<ConvertiblePair> readingPairs;
private final Set<ConvertiblePair> writingPairs;
private final Set<ConvertiblePair> readingPairs = new LinkedHashSet<>();
private final Set<ConvertiblePair> writingPairs = new LinkedHashSet<>();
private final Set<Class<?>> customSimpleTypes;
private final SimpleTypeHolder simpleTypeHolder;
@@ -80,6 +81,15 @@ public class CustomConversions {
private final Map<ConvertiblePair, Optional<Class<?>>> customWriteTargetTypes;
private final Map<Class<?>, Optional<Class<?>>> rawWriteTargetTypes;
private final Function<ConvertiblePair, Optional<Class<?>>> getCustomReadTarget = it -> getCustomTarget(
it.getSourceType(), Optional.of(it.getTargetType()), readingPairs);
private final Function<Class<?>, Optional<Class<?>>> getCustomWriteTargetForSource = it -> getCustomTarget(it,
Optional.empty(), writingPairs);
private final Function<ConvertiblePair, Optional<Class<?>>> getCustomWriteTarget = it -> getCustomTarget(
it.getSourceType(), Optional.of(it.getTargetType()), writingPairs);
/**
* Creates a new {@link CustomConversions} instance registering the given converters.
*
@@ -91,8 +101,6 @@ public class CustomConversions {
Assert.notNull(storeConversions, "StoreConversions must not be null!");
Assert.notNull(converters, "List of converters must not be null!");
this.readingPairs = new LinkedHashSet<>();
this.writingPairs = new LinkedHashSet<>();
this.customSimpleTypes = new HashSet<>();
this.customReadTargetTypes = new ConcurrentHashMap<>();
this.customWriteTargetTypes = new ConcurrentHashMap<>();
@@ -229,8 +237,7 @@ public class CustomConversions {
Assert.notNull(sourceType, "Source type must not be null!");
return rawWriteTargetTypes.computeIfAbsent(sourceType,
it -> getCustomTarget(sourceType, Optional.empty(), writingPairs));
return rawWriteTargetTypes.computeIfAbsent(sourceType, getCustomWriteTargetForSource);
}
/**
@@ -248,7 +255,7 @@ public class CustomConversions {
Assert.notNull(requestedTargetType, "Target type must not be null!");
return customWriteTargetTypes.computeIfAbsent(new ConvertiblePair(sourceType, requestedTargetType),
it -> getCustomTarget(sourceType, Optional.of(requestedTargetType), writingPairs));
getCustomWriteTarget);
}
/**
@@ -307,8 +314,7 @@ public class CustomConversions {
*/
private Optional<Class<?>> getCustomReadTarget(Class<?> sourceType, Class<?> targetType) {
return customReadTargetTypes.computeIfAbsent(new ConvertiblePair(sourceType, targetType),
it -> getCustomTarget(sourceType, Optional.of(targetType), readingPairs));
return customReadTargetTypes.computeIfAbsent(new ConvertiblePair(sourceType, targetType), getCustomReadTarget);
}
/**
@@ -320,7 +326,7 @@ public class CustomConversions {
* @param pairs must not be {@literal null}.
* @return
*/
private static Optional<Class<?>> getCustomTarget(Class<?> sourceType, Optional<Class<?>> targetType,
private Optional<Class<?>> getCustomTarget(Class<?> sourceType, Optional<Class<?>> targetType,
Collection<ConvertiblePair> pairs) {
Assert.notNull(sourceType, "Source Class must not be null!");

View File

@@ -21,12 +21,12 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import org.springframework.data.mapping.Alias;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.Optionals;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
@@ -43,6 +43,8 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
private final List<? extends TypeInformationMapper> mappers;
private final Map<Alias, Optional<TypeInformation<?>>> typeCache;
private final Function<Alias, Optional<TypeInformation<?>>> getAlias;
/**
* Creates a new {@link DefaultTypeMapper} using the given {@link TypeAliasAccessor}. It will use a
* {@link SimpleTypeInformationMapper} to calculate type aliases.
@@ -89,6 +91,17 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
this.mappers = Collections.unmodifiableList(mappers);
this.accessor = accessor;
this.typeCache = new ConcurrentHashMap<>();
this.getAlias = key -> {
for (TypeInformationMapper mapper : mappers) {
TypeInformation<?> typeInformation = mapper.resolveTypeFrom(key);
if (typeInformation != null) {
return Optional.of(typeInformation);
}
}
return Optional.empty();
};
}
/*
@@ -110,18 +123,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
* @return
*/
private TypeInformation<?> getFromCacheOrCreate(Alias alias) {
return typeCache.computeIfAbsent(alias, key -> {
for (TypeInformationMapper mapper : mappers) {
TypeInformation<?> typeInformation = mapper.resolveTypeFrom(alias);
if (typeInformation != null) {
return Optional.of(typeInformation);
}
}
return Optional.empty();
}).orElse(null);
return typeCache.computeIfAbsent(alias, getAlias).orElse(null);
}
/*
@@ -194,7 +196,10 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
Assert.notNull(info, "TypeInformation must not be null!");
getAliasFor(info).getValue().ifPresent(it -> accessor.writeTypeTo(sink, it));
Alias alias = getAliasFor(info);
if (alias.isPresent()) {
accessor.writeTypeTo(sink, alias.getValue().get());
}
}
/**
@@ -208,6 +213,14 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
Assert.notNull(info, "TypeInformation must not be null!");
return Optionals.firstNonEmpty(mappers, it -> it.createAliasFor(info), Alias.NONE);
for (TypeInformationMapper mapper : mappers) {
Alias alias = mapper.createAliasFor(info);
if (alias.isPresent()) {
return alias;
}
}
return Alias.NONE;
}
}

View File

@@ -30,8 +30,6 @@ import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.mapping.*;
@@ -52,9 +50,7 @@ import org.springframework.util.StringUtils;
*/
public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implements MutablePersistentEntity<T, P> {
private static final Logger LOGGER = LoggerFactory.getLogger(BasicPersistentEntity.class);
private static final String TYPE_MISMATCH = "Target bean of type %s is not of type of the persistent entity (%s)!";
private static final String NULL_ASSOCIATION = "%s.addAssociation(…) was called with a null association! Usually indicates a problem in a Spring Data MappingContext implementation. Be sure to file a bug at https://jira.spring.io!";
private final PreferredConstructor<T, P> constructor;
private final TypeInformation<T> information;
@@ -438,8 +434,10 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
public PersistentPropertyAccessor getPropertyAccessor(Object bean) {
Assert.notNull(bean, "Target bean must not be null!");
Assert.isTrue(getType().isInstance(bean),
() -> String.format(TYPE_MISMATCH, bean.getClass().getName(), getType().getName()));
if (!getType().isInstance(bean)) { // prevent capturing lambda
throw new IllegalArgumentException(String.format(TYPE_MISMATCH, bean.getClass().getName(), getType().getName()));
}
return propertyAccessorFactory.getPropertyAccessor(this, bean);
}
@@ -452,8 +450,10 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
public IdentifierAccessor getIdentifierAccessor(Object bean) {
Assert.notNull(bean, "Target bean must not be null!");
Assert.isTrue(getType().isInstance(bean),
() -> String.format(TYPE_MISMATCH, bean.getClass().getName(), getType().getName()));
if (!getType().isInstance(bean)) { // prevent capturing lambda
throw new IllegalArgumentException(String.format(TYPE_MISMATCH, bean.getClass().getName(), getType().getName()));
}
return hasIdProperty() ? new IdPropertyIdentifierAccessor(this, bean) : new AbsentIdentifierAccessor(bean);
}