DATACMNS-1101 - Use non-capturing lambdas in CustomConversions for conversion lookup.
This commit is contained in:
committed by
Oliver Gierke
parent
38d9b08132
commit
ce9aae49c8
@@ -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!");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user