switch to commons branch
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -26,7 +26,7 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>2.4.0-SNAPSHOT</springdata.commons>
|
||||
<springdata.commons>2.4.0-BUILD-TIME-DOMAIN-TYPE-METADATA-SNAPSHOT</springdata.commons>
|
||||
<mongo>4.1.0</mongo>
|
||||
<mongo.reactivestreams>${mongo}</mongo.reactivestreams>
|
||||
<jmh.version>1.19</jmh.version>
|
||||
|
||||
@@ -1,339 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2020 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
|
||||
*
|
||||
* https://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.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Value object to encapsulate the constructor to be used when mapping persistent data to objects.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Myeonghyeon Lee
|
||||
*/
|
||||
public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final Constructor<T> constructor;
|
||||
private final List<Parameter<Object, P>> parameters;
|
||||
private final Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new ConcurrentHashMap<>();
|
||||
|
||||
public PreferredConstructor() {
|
||||
this.constructor = null;
|
||||
this.parameters = Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructor} from the given {@link Constructor} and {@link Parameter}s.
|
||||
*
|
||||
* @param constructor must not be {@literal null}.
|
||||
* @param parameters must not be {@literal null}.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public PreferredConstructor(Constructor<T> constructor, Parameter<Object, P>... parameters) {
|
||||
|
||||
Assert.notNull(constructor, "Constructor must not be null!");
|
||||
Assert.notNull(parameters, "Parameters must not be null!");
|
||||
|
||||
ReflectionUtils.makeAccessible(constructor);
|
||||
this.constructor = constructor;
|
||||
this.parameters = Arrays.asList(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link Constructor}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Constructor<T> getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Parameter}s of the constructor.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<Parameter<Object, P>> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor has {@link Parameter}s.
|
||||
*
|
||||
* @see #isNoArgConstructor()
|
||||
* @return
|
||||
*/
|
||||
public boolean hasParameters() {
|
||||
return !parameters.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor does not have any arguments.
|
||||
*
|
||||
* @see #hasParameters()
|
||||
* @return
|
||||
*/
|
||||
public boolean isNoArgConstructor() {
|
||||
return parameters.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor was explicitly selected (by {@link PersistenceConstructor}).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isExplicitlyAnnotated() {
|
||||
return constructor.isAnnotationPresent(PersistenceConstructor.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is referenced in a constructor argument of the
|
||||
* {@link PersistentEntity} backing this {@link PreferredConstructor}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @return {@literal true} if the {@link PersistentProperty} is used in the constructor.
|
||||
*/
|
||||
public boolean isConstructorParameter(PersistentProperty<?> property) {
|
||||
|
||||
Assert.notNull(property, "Property must not be null!");
|
||||
|
||||
Boolean cached = isPropertyParameterCache.get(property);
|
||||
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
boolean result = false;
|
||||
for (Parameter<?, P> parameter : parameters) {
|
||||
if (parameter.maps(property)) {
|
||||
isPropertyParameterCache.put(property, true);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link Parameter} is one referring to an enclosing class. That is in case the class this
|
||||
* {@link PreferredConstructor} belongs to is a member class actually. If that's the case the compiler creates a first
|
||||
* constructor argument of the enclosing class type.
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return {@literal true} if the {@link PersistentProperty} maps to the enclosing class.
|
||||
*/
|
||||
public boolean isEnclosingClassParameter(Parameter<?, P> parameter) {
|
||||
|
||||
Assert.notNull(parameter, "Parameter must not be null!");
|
||||
|
||||
if (parameters.isEmpty() || !parameter.isEnclosingClassParameter()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parameters.get(0).equals(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Value object to represent constructor parameters.
|
||||
*
|
||||
* @param <T> the type of the parameter
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public static class Parameter<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final @Nullable String name;
|
||||
private final TypeInformation<T> type;
|
||||
private final String key;
|
||||
private final @Nullable PersistentEntity<T, P> entity;
|
||||
|
||||
private final Lazy<Boolean> enclosingClassCache;
|
||||
private final Lazy<Boolean> hasSpelExpression;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Parameter} with the given name, {@link TypeInformation} as well as an array of
|
||||
* {@link Annotation}s. Will inspect the annotations for an {@link Value} annotation to lookup a key or an SpEL
|
||||
* expression to be evaluated.
|
||||
*
|
||||
* @param name the name of the parameter, can be {@literal null}
|
||||
* @param type must not be {@literal null}
|
||||
* @param annotations must not be {@literal null} but can be empty
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public Parameter(@Nullable String name, TypeInformation<T> type, Annotation[] annotations,
|
||||
@Nullable PersistentEntity<T, P> entity) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.notNull(annotations, "Annotations must not be null!");
|
||||
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.key = getValue(annotations);
|
||||
this.entity = entity;
|
||||
|
||||
this.enclosingClassCache = Lazy.of(() -> {
|
||||
|
||||
if (entity == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
Class<T> owningType = entity.getType();
|
||||
return owningType.isMemberClass() && type.getType().equals(owningType.getEnclosingClass());
|
||||
});
|
||||
|
||||
this.hasSpelExpression = Lazy.of(() -> StringUtils.hasText(getSpelExpression()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getValue(Annotation[] annotations) {
|
||||
|
||||
return Arrays.stream(annotations)//
|
||||
.filter(it -> it.annotationType() == Value.class)//
|
||||
.findFirst().map(it -> ((Value) it).value())//
|
||||
.filter(StringUtils::hasText).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the parameter.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} of the parameter.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public TypeInformation<T> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw resolved type of the parameter.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<T> getRawType() {
|
||||
return type.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key to be used when looking up a source data structure to populate the actual parameter value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getSpelExpression() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor parameter is equipped with a SpEL expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasSpelExpression() {
|
||||
return this.hasSpelExpression.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof Parameter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Parameter<?, ?> parameter = (Parameter<?, ?>) o;
|
||||
|
||||
if (!ObjectUtils.nullSafeEquals(name, parameter.name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ObjectUtils.nullSafeEquals(type, parameter.type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ObjectUtils.nullSafeEquals(key, parameter.key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ObjectUtils.nullSafeEquals(entity, parameter.entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = ObjectUtils.nullSafeHashCode(name);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(type);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(key);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(entity);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link Parameter} maps the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
boolean maps(PersistentProperty<?> property) {
|
||||
|
||||
PersistentEntity<T, P> entity = this.entity;
|
||||
String name = this.name;
|
||||
|
||||
P referencedProperty = entity == null ? null : name == null ? null : entity.getPersistentProperty(name);
|
||||
|
||||
return property.equals(referencedProperty);
|
||||
}
|
||||
|
||||
private boolean isEnclosingClassParameter() {
|
||||
return enclosingClassCache.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.mapping;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public interface PreferredConstructorProvider<T> {
|
||||
|
||||
@Nullable
|
||||
<P extends PersistentProperty<P>> PreferredConstructor<T, P> getPreferredConstructor();
|
||||
|
||||
default <P extends PersistentProperty<P>> PreferredConstructor<T, P> getPreferredConstructorOrDefault(PreferredConstructor<T, P> fallback) {
|
||||
|
||||
PreferredConstructor<T, P> preferredConstructor = getPreferredConstructor();
|
||||
return preferredConstructor != null ? preferredConstructor : fallback;
|
||||
}
|
||||
}
|
||||
@@ -1,689 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2020 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
|
||||
*
|
||||
* https://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.context;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.core.KotlinDetector;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PersistentPropertyPaths;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.mapping.model.BeanWrapperPropertyAccessorFactory;
|
||||
import org.springframework.data.mapping.model.ClassGeneratingPropertyAccessorFactory;
|
||||
import org.springframework.data.mapping.model.EntityInstantiators;
|
||||
import org.springframework.data.mapping.model.InstantiationAwarePropertyAccessorFactory;
|
||||
import org.springframework.data.mapping.model.MutablePersistentEntity;
|
||||
import org.springframework.data.mapping.model.PersistentPropertyAccessorFactory;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.mapping.model.StaticPropertyAccessorFactory;
|
||||
import org.springframework.data.spel.EvaluationContextProvider;
|
||||
import org.springframework.data.spel.ExtensionAwareEvaluationContextProvider;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.DomainTypeInformation;
|
||||
import org.springframework.data.util.KotlinReflectionUtils;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.FieldCallback;
|
||||
import org.springframework.util.ReflectionUtils.FieldFilter;
|
||||
|
||||
/**
|
||||
* Base class to build mapping metadata and thus create instances of {@link PersistentEntity} and
|
||||
* {@link PersistentProperty}.
|
||||
* <p>
|
||||
* The implementation uses a {@link ReentrantReadWriteLock} to make sure {@link PersistentEntity} are completely
|
||||
* populated before accessing them from outside.
|
||||
*
|
||||
* @param <E> the concrete {@link PersistentEntity} type the {@link MappingContext} implementation creates
|
||||
* @param <P> the concrete {@link PersistentProperty} type the {@link MappingContext} implementation creates
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @author Michael Hunger
|
||||
* @author Thomas Darimont
|
||||
* @author Tomasz Wysocki
|
||||
* @author Mark Paluch
|
||||
* @author Mikael Klamra
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?, P>, P extends PersistentProperty<P>>
|
||||
implements MappingContext<E, P>, ApplicationEventPublisherAware, ApplicationContextAware, InitializingBean {
|
||||
|
||||
private static final boolean IN_NATIVE_IMAGE = System.getProperty("org.graalvm.nativeimage.imagecode") != null;
|
||||
|
||||
private final Optional<E> NONE = Optional.empty();
|
||||
private final Map<TypeInformation<?>, Optional<E>> persistentEntities = new HashMap<>();
|
||||
private final PersistentPropertyAccessorFactory persistentPropertyAccessorFactory;
|
||||
private final PersistentPropertyPathFactory<E, P> persistentPropertyPathFactory;
|
||||
|
||||
private @Nullable ApplicationEventPublisher applicationEventPublisher;
|
||||
private EvaluationContextProvider evaluationContextProvider = EvaluationContextProvider.DEFAULT;
|
||||
|
||||
private Set<? extends Class<?>> initialEntitySet = new HashSet<>();
|
||||
private boolean strict = false;
|
||||
private SimpleTypeHolder simpleTypeHolder = SimpleTypeHolder.DEFAULT;
|
||||
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final Lock read = lock.readLock();
|
||||
private final Lock write = lock.writeLock();
|
||||
|
||||
protected AbstractMappingContext() {
|
||||
|
||||
this.persistentPropertyPathFactory = new PersistentPropertyPathFactory<>(this);
|
||||
|
||||
EntityInstantiators instantiators = new EntityInstantiators();
|
||||
PersistentPropertyAccessorFactory accessorFactory = IN_NATIVE_IMAGE ? BeanWrapperPropertyAccessorFactory.INSTANCE
|
||||
: new ClassGeneratingPropertyAccessorFactory();
|
||||
|
||||
this.persistentPropertyAccessorFactory = new InstantiationAwarePropertyAccessorFactory(accessorFactory,
|
||||
instantiators);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
|
||||
this.evaluationContextProvider = new ExtensionAwareEvaluationContextProvider(applicationContext);
|
||||
|
||||
if (applicationEventPublisher == null) {
|
||||
this.applicationEventPublisher = applicationContext;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Set} of types to populate the context initially.
|
||||
*
|
||||
* @param initialEntitySet
|
||||
*/
|
||||
public void setInitialEntitySet(Set<? extends Class<?>> initialEntitySet) {
|
||||
this.initialEntitySet = initialEntitySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether the {@link MappingContext} is in strict mode which means, that it will throw
|
||||
* {@link MappingException}s in case one tries to lookup a {@link PersistentEntity} not already in the context. This
|
||||
* defaults to {@literal false} so that unknown types will be transparently added to the MappingContext if not known
|
||||
* in advance.
|
||||
*
|
||||
* @param strict
|
||||
*/
|
||||
public void setStrict(boolean strict) {
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link SimpleTypeHolder} to be used by the {@link MappingContext}. Allows customization of what
|
||||
* types will be regarded as simple types and thus not recursively analyzed.
|
||||
*
|
||||
* @param simpleTypes must not be {@literal null}.
|
||||
*/
|
||||
public void setSimpleTypeHolder(SimpleTypeHolder simpleTypes) {
|
||||
|
||||
Assert.notNull(simpleTypes, "SimpleTypeHolder must not be null!");
|
||||
|
||||
this.simpleTypeHolder = simpleTypes;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntities()
|
||||
*/
|
||||
@Override
|
||||
public Collection<E> getPersistentEntities() {
|
||||
|
||||
try {
|
||||
|
||||
read.lock();
|
||||
|
||||
return persistentEntities.values().stream()//
|
||||
.flatMap(Optionals::toStream)//
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(java.lang.Class)
|
||||
*/
|
||||
@Nullable
|
||||
public E getPersistentEntity(Class<?> type) {
|
||||
return getPersistentEntity(ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#hasPersistentEntityFor(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPersistentEntityFor(Class<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
Optional<E> entity = persistentEntities.get(ClassTypeInformation.from(type));
|
||||
|
||||
return entity == null ? false : entity.isPresent();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public E getPersistentEntity(TypeInformation<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
try {
|
||||
|
||||
read.lock();
|
||||
|
||||
Optional<E> entity = persistentEntities.get(type);
|
||||
|
||||
if (entity != null) {
|
||||
return entity.orElse(null);
|
||||
}
|
||||
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
|
||||
if (!shouldCreatePersistentEntityFor(type)) {
|
||||
|
||||
try {
|
||||
write.lock();
|
||||
persistentEntities.put(type, NONE);
|
||||
} finally {
|
||||
write.unlock();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (strict) {
|
||||
throw new MappingException("Unknown persistent entity " + type);
|
||||
}
|
||||
|
||||
return addPersistentEntity(type).orElse(null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentEntity(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public E getPersistentEntity(P persistentProperty) {
|
||||
|
||||
Assert.notNull(persistentProperty, "PersistentProperty must not be null!");
|
||||
|
||||
if (!persistentProperty.isEntity()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeInformation<?> typeInfo = persistentProperty.getTypeInformation();
|
||||
return getPersistentEntity(typeInfo.getRequiredActualType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentPropertyPath(java.lang.Class, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public PersistentPropertyPath<P> getPersistentPropertyPath(PropertyPath propertyPath) {
|
||||
return persistentPropertyPathFactory.from(propertyPath);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentPropertyPath(java.lang.String, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public PersistentPropertyPath<P> getPersistentPropertyPath(String propertyPath, Class<?> type) {
|
||||
return persistentPropertyPathFactory.from(type, propertyPath);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#findPersistentPropertyPath(java.lang.Class, java.util.function.Predicate)
|
||||
*/
|
||||
@Override
|
||||
public <T> PersistentPropertyPaths<T, P> findPersistentPropertyPaths(Class<T> type, Predicate<? super P> predicate) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.notNull(predicate, "Selection predicate must not be null!");
|
||||
|
||||
return doFindPersistentPropertyPaths(type, predicate, it -> !it.isAssociation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually looks up the {@link PersistentPropertyPaths} for the given type, selection predicate and traversal guard.
|
||||
* Primary purpose is to allow sub-types to alter the default traversal guard, e.g. used by
|
||||
* {@link #findPersistentPropertyPaths(Class, Predicate)}.
|
||||
*
|
||||
* @param type will never be {@literal null}.
|
||||
* @param predicate will never be {@literal null}.
|
||||
* @param traversalGuard will never be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
* @see #findPersistentPropertyPaths(Class, Predicate)
|
||||
*/
|
||||
protected final <T> PersistentPropertyPaths<T, P> doFindPersistentPropertyPaths(Class<T> type,
|
||||
Predicate<? super P> predicate, Predicate<P> traversalGuard) {
|
||||
return persistentPropertyPathFactory.from(ClassTypeInformation.from(type), predicate, traversalGuard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given type to the {@link MappingContext}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected Optional<E> addPersistentEntity(Class<?> type) {
|
||||
return addPersistentEntity(ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@link TypeInformation} to the {@link MappingContext}.
|
||||
*
|
||||
* @param typeInformation must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected Optional<E> addPersistentEntity(TypeInformation<?> typeInformation) {
|
||||
|
||||
Assert.notNull(typeInformation, "TypeInformation must not be null!");
|
||||
|
||||
try {
|
||||
|
||||
read.lock();
|
||||
|
||||
Optional<E> persistentEntity = persistentEntities.get(typeInformation);
|
||||
|
||||
if (persistentEntity != null) {
|
||||
return persistentEntity;
|
||||
}
|
||||
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
|
||||
Class<?> type = typeInformation.getType();
|
||||
E entity = null;
|
||||
|
||||
try {
|
||||
|
||||
write.lock();
|
||||
|
||||
entity = createPersistentEntity(typeInformation);
|
||||
|
||||
entity.setEvaluationContextProvider(evaluationContextProvider);
|
||||
|
||||
// Eagerly cache the entity as we might have to find it during recursive lookups.
|
||||
persistentEntities.put(typeInformation, Optional.of(entity));
|
||||
|
||||
if (typeInformation instanceof DomainTypeInformation<?>) {
|
||||
|
||||
final E pEntity = entity;
|
||||
((DomainTypeInformation<?>) typeInformation).doWithFields((fieldName, field) -> {
|
||||
|
||||
System.out.println("Creating PersistentProperty for " + fieldName + " via static configuration.");
|
||||
P target = createPersistentProperty(
|
||||
Property.of(field.getTypeInformation(), fieldName, field.getAnnotations()), pEntity, simpleTypeHolder);
|
||||
pEntity.addPersistentProperty(target);
|
||||
|
||||
});
|
||||
pEntity.setPersistentPropertyAccessorFactory(StaticPropertyAccessorFactory.instance());
|
||||
return Optional.of(pEntity);
|
||||
}
|
||||
|
||||
PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(type);
|
||||
|
||||
final Map<String, PropertyDescriptor> descriptors = new HashMap<>();
|
||||
for (PropertyDescriptor descriptor : pds) {
|
||||
descriptors.put(descriptor.getName(), descriptor);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
PersistentPropertyCreator persistentPropertyCreator = new PersistentPropertyCreator(entity, descriptors);
|
||||
ReflectionUtils.doWithFields(type, persistentPropertyCreator, PersistentPropertyFilter.INSTANCE);
|
||||
persistentPropertyCreator.addPropertiesForRemainingDescriptors();
|
||||
|
||||
entity.verify();
|
||||
|
||||
if (persistentPropertyAccessorFactory.isSupported(entity)) {
|
||||
entity.setPersistentPropertyAccessorFactory(persistentPropertyAccessorFactory);
|
||||
}
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
persistentEntities.remove(typeInformation);
|
||||
throw e;
|
||||
}
|
||||
|
||||
} catch (BeansException e) {
|
||||
throw new MappingException(e.getMessage(), e);
|
||||
} finally {
|
||||
write.unlock();
|
||||
}
|
||||
|
||||
// Inform listeners
|
||||
if (applicationEventPublisher != null && entity != null) {
|
||||
applicationEventPublisher.publishEvent(new MappingContextEvent<>(this, entity));
|
||||
}
|
||||
|
||||
return Optional.of(entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentEntityAware#getManagedTypes()
|
||||
*/
|
||||
@Override
|
||||
public Collection<TypeInformation<?>> getManagedTypes() {
|
||||
|
||||
try {
|
||||
|
||||
read.lock();
|
||||
return Collections.unmodifiableSet(new HashSet<>(persistentEntities.keySet()));
|
||||
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the concrete {@link PersistentEntity} instance.
|
||||
*
|
||||
* @param <T>
|
||||
* @param typeInformation
|
||||
* @return
|
||||
*/
|
||||
protected abstract <T> E createPersistentEntity(TypeInformation<T> typeInformation);
|
||||
|
||||
/**
|
||||
* Creates the concrete instance of {@link PersistentProperty}.
|
||||
*
|
||||
* @param property
|
||||
* @param owner
|
||||
* @param simpleTypeHolder
|
||||
* @return
|
||||
*/
|
||||
protected abstract P createPersistentProperty(Property property, E owner, SimpleTypeHolder simpleTypeHolder);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the mapping context. Will add the types configured through {@link #setInitialEntitySet(Set)} to the
|
||||
* context.
|
||||
*/
|
||||
public void initialize() {
|
||||
initialEntitySet.forEach(this::addPersistentEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a {@link PersistentEntity} instance should be created for the given {@link TypeInformation}. By
|
||||
* default this will reject all types considered simple and non-supported Kotlin classes, but it might be necessary to
|
||||
* tweak that in case you have registered custom converters for top level types (which renders them to be considered
|
||||
* simple) but still need meta-information about them.
|
||||
* <p/>
|
||||
*
|
||||
* @param type will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
|
||||
|
||||
if (simpleTypeHolder.isSimpleType(type.getType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !KotlinDetector.isKotlinType(type.getType()) || KotlinReflectionUtils.isSupportedKotlinClass(type.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FieldCallback} to create {@link PersistentProperty} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private final class PersistentPropertyCreator implements FieldCallback {
|
||||
|
||||
private final E entity;
|
||||
private final Map<String, PropertyDescriptor> descriptors;
|
||||
private final Map<String, PropertyDescriptor> remainingDescriptors;
|
||||
|
||||
public PersistentPropertyCreator(E entity, Map<String, PropertyDescriptor> descriptors) {
|
||||
this(entity, descriptors, descriptors);
|
||||
}
|
||||
|
||||
private PersistentPropertyCreator(E entity, Map<String, PropertyDescriptor> descriptors,
|
||||
Map<String, PropertyDescriptor> remainingDescriptors) {
|
||||
this.entity = entity;
|
||||
this.descriptors = descriptors;
|
||||
this.remainingDescriptors = remainingDescriptors;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.util.ReflectionUtils.FieldCallback#doWith(java.lang.reflect.Field)
|
||||
*/
|
||||
public void doWith(Field field) {
|
||||
|
||||
String fieldName = field.getName();
|
||||
TypeInformation<?> type = entity.getTypeInformation();
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
|
||||
Property property = Optional.ofNullable(descriptors.get(fieldName))//
|
||||
.map(it -> Property.of(type, field, it))//
|
||||
.orElseGet(() -> Property.of(type, field));
|
||||
|
||||
createAndRegisterProperty(property);
|
||||
|
||||
this.remainingDescriptors.remove(fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@link PersistentProperty} instances for all suitable {@link PropertyDescriptor}s without a backing
|
||||
* {@link Field}.
|
||||
*
|
||||
* @see PersistentPropertyFilter
|
||||
*/
|
||||
public void addPropertiesForRemainingDescriptors() {
|
||||
|
||||
remainingDescriptors.values().stream() //
|
||||
.filter(Property::supportsStandalone) //
|
||||
.map(it -> Property.of(entity.getTypeInformation(), it)) //
|
||||
.filter(PersistentPropertyFilter.INSTANCE::matches) //
|
||||
.forEach(this::createAndRegisterProperty);
|
||||
}
|
||||
|
||||
private void createAndRegisterProperty(Property input) {
|
||||
|
||||
P property = createPersistentProperty(input, entity, simpleTypeHolder);
|
||||
|
||||
if (property.isTransient()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!input.isFieldBacked() && !property.usePropertyAccess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
entity.addPersistentProperty(property);
|
||||
|
||||
if (property.isAssociation()) {
|
||||
entity.addAssociation(property.getRequiredAssociation());
|
||||
}
|
||||
|
||||
if (entity.getType().equals(property.getRawType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
property.getPersistentEntityTypes().forEach(AbstractMappingContext.this::addPersistentEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter rejecting static fields as well as artificially introduced ones. See
|
||||
* {@link PersistentPropertyFilter#UNMAPPED_PROPERTIES} for details.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static enum PersistentPropertyFilter implements FieldFilter {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
private static final Streamable<PropertyMatch> UNMAPPED_PROPERTIES;
|
||||
|
||||
static {
|
||||
|
||||
Set<PropertyMatch> matches = new HashSet<>();
|
||||
matches.add(new PropertyMatch("class", null));
|
||||
matches.add(new PropertyMatch("this\\$.*", null));
|
||||
matches.add(new PropertyMatch("metaClass", "groovy.lang.MetaClass"));
|
||||
|
||||
UNMAPPED_PROPERTIES = Streamable.of(matches);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.util.ReflectionUtils.FieldFilter#matches(java.lang.reflect.Field)
|
||||
*/
|
||||
public boolean matches(Field field) {
|
||||
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !UNMAPPED_PROPERTIES.stream()//
|
||||
.anyMatch(it -> it.matches(field.getName(), field.getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PropertyDescriptor} is one to create a {@link PersistentProperty} for.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean matches(Property property) {
|
||||
|
||||
Assert.notNull(property, "Property must not be null!");
|
||||
|
||||
if (!property.hasAccessor()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !UNMAPPED_PROPERTIES.stream()//
|
||||
.anyMatch(it -> it.matches(property.getName(), property.getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Value object to help defining property exclusion based on name patterns and types.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class PropertyMatch {
|
||||
|
||||
private final @Nullable String namePattern;
|
||||
private final @Nullable String typeName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyMatch} for the given name pattern and type name. At least one of the parameters
|
||||
* must not be {@literal null}.
|
||||
*
|
||||
* @param namePattern a regex pattern to match field names, can be {@literal null}.
|
||||
* @param typeName the name of the type to exclude, can be {@literal null}.
|
||||
*/
|
||||
public PropertyMatch(@Nullable String namePattern, @Nullable String typeName) {
|
||||
|
||||
Assert.isTrue(!(namePattern == null && typeName == null), "Either name pattern or type name must be given!");
|
||||
|
||||
this.namePattern = namePattern;
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link Field} matches the defined {@link PropertyMatch}.
|
||||
*
|
||||
* @param name must not be {@literal null}.
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean matches(String name, Class<?> type) {
|
||||
|
||||
Assert.notNull(name, "Name must not be null!");
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
if (namePattern != null && !name.matches(namePattern)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeName != null && !type.getName().equals(typeName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 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.mapping.model;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public interface AccessorFunctionAware<S> {
|
||||
|
||||
default boolean hasSetFunctionFor(String fieldName) {
|
||||
return getSetFunctionFor(fieldName) != null;
|
||||
}
|
||||
|
||||
default boolean hasGetFunctionFor(String fieldName) {
|
||||
return getGetFunctionFor(fieldName) != null;
|
||||
}
|
||||
|
||||
BiFunction<S, Object, S> getSetFunctionFor(String fieldName);
|
||||
|
||||
Function<S, Object> getGetFunctionFor(String fieldName);
|
||||
}
|
||||
@@ -1,331 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2020 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
|
||||
*
|
||||
* https://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.model;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.data.annotation.AccessType;
|
||||
import org.springframework.data.annotation.AccessType.Type;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.data.util.StreamUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Special {@link PersistentProperty} that takes annotations at a property into account.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract class AnnotationBasedPersistentProperty<P extends PersistentProperty<P>>
|
||||
extends AbstractPersistentProperty<P> {
|
||||
|
||||
private static final String SPRING_DATA_PACKAGE = "org.springframework.data";
|
||||
|
||||
private final @Nullable String value;
|
||||
private final Map<Class<? extends Annotation>, Optional<? extends Annotation>> annotationCache = new ConcurrentHashMap<>();
|
||||
|
||||
private final Lazy<Boolean> usePropertyAccess = Lazy.of(() -> {
|
||||
|
||||
AccessType accessType = findPropertyOrOwnerAnnotation(AccessType.class);
|
||||
|
||||
return accessType != null && Type.PROPERTY.equals(accessType.value()) || super.usePropertyAccess();
|
||||
});
|
||||
|
||||
private final Lazy<Boolean> isTransient = Lazy.of(() -> super.isTransient() || isAnnotationPresent(Transient.class)
|
||||
|| isAnnotationPresent(Value.class) || isAnnotationPresent(Autowired.class));
|
||||
|
||||
private final Lazy<Boolean> isWritable = Lazy
|
||||
.of(() -> !isTransient() && !isAnnotationPresent(ReadOnlyProperty.class));
|
||||
private final Lazy<Boolean> isReference = Lazy.of(() -> !isTransient() && isAnnotationPresent(Reference.class));
|
||||
private final Lazy<Boolean> isId = Lazy.of(() -> isAnnotationPresent(Id.class));
|
||||
private final Lazy<Boolean> isVersion = Lazy.of(() -> isAnnotationPresent(Version.class));
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationBasedPersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @param owner must not be {@literal null}.
|
||||
*/
|
||||
public AnnotationBasedPersistentProperty(Property property, PersistentEntity<?, P> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
super(property, owner, simpleTypeHolder);
|
||||
|
||||
populateAnnotationCache(property);
|
||||
|
||||
Value value = findAnnotation(Value.class);
|
||||
|
||||
this.value = value == null ? null : value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the annotation cache by eagerly accessing the annotations directly annotated to the accessors (if
|
||||
* available) and the backing field. Annotations override annotations found on field.
|
||||
*
|
||||
* @param property
|
||||
* @throws MappingException in case we find an ambiguous mapping on the accessor methods
|
||||
*/
|
||||
private void populateAnnotationCache(Property property) {
|
||||
|
||||
property.getAnnotations().forEach(it -> {
|
||||
|
||||
System.out.println("registering static annotation "+it.annotationType()+" for field " + property.getName());
|
||||
annotationCache.put(it.annotationType(), Optional.of(it));
|
||||
});
|
||||
|
||||
Optionals.toStream(property.getGetter(), property.getSetter()).forEach(it -> {
|
||||
|
||||
for (Annotation annotation : it.getAnnotations()) {
|
||||
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
|
||||
validateAnnotation(annotation,
|
||||
"Ambiguous mapping! Annotation %s configured "
|
||||
+ "multiple times on accessor methods of property %s in class %s!",
|
||||
annotationType.getSimpleName(), getName(), getOwner().getType().getSimpleName());
|
||||
|
||||
annotationCache.put(annotationType,
|
||||
Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(it, annotationType)));
|
||||
}
|
||||
});
|
||||
|
||||
property.getField().ifPresent(it -> {
|
||||
|
||||
for (Annotation annotation : it.getAnnotations()) {
|
||||
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
|
||||
validateAnnotation(annotation,
|
||||
"Ambiguous mapping! Annotation %s configured " + "on field %s and one of its accessor methods in class %s!",
|
||||
annotationType.getSimpleName(), it.getName(), getOwner().getType().getSimpleName());
|
||||
|
||||
annotationCache.put(annotationType,
|
||||
Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(it, annotationType)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the given annotation candidate detected. Will be rejected if it's a Spring Data annotation and we already
|
||||
* found another one with a different configuration setup (i.e. other attribute values).
|
||||
*
|
||||
* @param candidate must not be {@literal null}.
|
||||
* @param message must not be {@literal null}.
|
||||
* @param arguments must not be {@literal null}.
|
||||
*/
|
||||
private void validateAnnotation(Annotation candidate, String message, Object... arguments) {
|
||||
|
||||
Class<? extends Annotation> annotationType = candidate.annotationType();
|
||||
|
||||
if (!annotationType.getName().startsWith(SPRING_DATA_PACKAGE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (annotationCache.containsKey(annotationType)
|
||||
&& !annotationCache.get(annotationType).equals(Optional.of(candidate))) {
|
||||
throw new MappingException(String.format(message, arguments));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects a potentially available {@link Value} annotation at the property and returns the {@link String} value of
|
||||
* it.
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#getSpelExpression()
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public String getSpelExpression() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers plain transient fields, fields annotated with {@link Transient}, {@link Value} or {@link Autowired} as
|
||||
* transient.
|
||||
*
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isTransient()
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
return isTransient.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isIdProperty()
|
||||
*/
|
||||
public boolean isIdProperty() {
|
||||
return isId.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isVersionProperty()
|
||||
*/
|
||||
public boolean isVersionProperty() {
|
||||
return isVersion.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers the property an {@link Association} if it is annotated with {@link Reference}.
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssociation() {
|
||||
return isReference.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#isWritable()
|
||||
*/
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return isWritable.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the annotation found for the current {@link AnnotationBasedPersistentProperty}. Will prefer getters or
|
||||
* setters annotations over ones found at the backing field as the former can be used to reconfigure the metadata in
|
||||
* subclasses.
|
||||
*
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return {@literal null} if annotation type not found on property.
|
||||
*/
|
||||
@Nullable
|
||||
public <A extends Annotation> A findAnnotation(Class<A> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null!");
|
||||
|
||||
return doFindAnnotation(annotationType).orElse(null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <A extends Annotation> Optional<A> doFindAnnotation(Class<A> annotationType) {
|
||||
|
||||
Optional<? extends Annotation> annotation = annotationCache.get(annotationType);
|
||||
|
||||
if (annotation != null) {
|
||||
return (Optional<A>) annotation;
|
||||
}
|
||||
|
||||
return (Optional<A>) annotationCache.computeIfAbsent(annotationType, type -> {
|
||||
|
||||
return getAccessors() //
|
||||
.map(it -> AnnotatedElementUtils.findMergedAnnotation(it, type)) //
|
||||
.flatMap(StreamUtils::fromNullable) //
|
||||
.findFirst();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#findPropertyOrOwnerAnnotation(java.lang.Class)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <A extends Annotation> A findPropertyOrOwnerAnnotation(Class<A> annotationType) {
|
||||
|
||||
A annotation = findAnnotation(annotationType);
|
||||
|
||||
return annotation != null ? annotation : getOwner().findAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the property carries the an annotation of the given type.
|
||||
*
|
||||
* @param annotationType the annotation type to look up.
|
||||
* @return
|
||||
*/
|
||||
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
|
||||
return doFindAnnotation(annotationType).isPresent();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#usePropertyAccess()
|
||||
*/
|
||||
@Override
|
||||
public boolean usePropertyAccess() {
|
||||
return usePropertyAccess.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getAssociationTargetType()
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Class<?> getAssociationTargetType() {
|
||||
|
||||
Reference reference = findAnnotation(Reference.class);
|
||||
|
||||
if (reference == null) {
|
||||
return isEntity() ? getActualType() : null;
|
||||
}
|
||||
|
||||
Class<?> targetType = reference.to();
|
||||
|
||||
return Class.class.equals(targetType) //
|
||||
? isEntity() ? getActualType() : null //
|
||||
: targetType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
if (annotationCache.isEmpty()) {
|
||||
populateAnnotationCache(getProperty());
|
||||
}
|
||||
|
||||
String builder = annotationCache.values().stream() //
|
||||
.flatMap(Optionals::toStream) //
|
||||
.map(Object::toString) //
|
||||
.collect(Collectors.joining(" "));
|
||||
|
||||
return builder + super.toString();
|
||||
}
|
||||
|
||||
private Stream<? extends AnnotatedElement> getAccessors() {
|
||||
|
||||
return Optionals.toStream(Optional.ofNullable(getGetter()), Optional.ofNullable(getSetter()),
|
||||
Optional.ofNullable(getField()));
|
||||
}
|
||||
}
|
||||
@@ -1,656 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2020 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
|
||||
*
|
||||
* https://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.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.data.annotation.Immutable;
|
||||
import org.springframework.data.annotation.TypeAlias;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.data.mapping.*;
|
||||
import org.springframework.data.spel.EvaluationContextProvider;
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.PersistableIsNewStrategy;
|
||||
import org.springframework.data.util.AnnotationAware;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Simple value object to capture information of {@link PersistentEntity}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @author Patryk Wasik
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implements MutablePersistentEntity<T, P> {
|
||||
|
||||
private static final String TYPE_MISMATCH = "Target bean of type %s is not of type of the persistent entity (%s)!";
|
||||
|
||||
private final @Nullable PreferredConstructor<T, P> constructor;
|
||||
private final TypeInformation<T> information;
|
||||
private final List<P> properties;
|
||||
private final List<P> persistentPropertiesCache;
|
||||
private final @Nullable Comparator<P> comparator;
|
||||
private final Set<Association<P>> associations;
|
||||
|
||||
private final Map<String, P> propertyCache;
|
||||
private final Map<Class<? extends Annotation>, Optional<Annotation>> annotationCache;
|
||||
private final MultiValueMap<Class<? extends Annotation>, P> propertyAnnotationCache;
|
||||
|
||||
private @Nullable P idProperty;
|
||||
private @Nullable P versionProperty;
|
||||
private PersistentPropertyAccessorFactory propertyAccessorFactory;
|
||||
private EvaluationContextProvider evaluationContextProvider = EvaluationContextProvider.DEFAULT;
|
||||
|
||||
private final Lazy<Alias> typeAlias;
|
||||
private final Lazy<IsNewStrategy> isNewStrategy;
|
||||
private final Lazy<Boolean> isImmutable;
|
||||
private final Lazy<Boolean> requiresPropertyPopulation;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicPersistentEntity} from the given {@link TypeInformation}.
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
*/
|
||||
public BasicPersistentEntity(TypeInformation<T> information) {
|
||||
this(information, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicPersistentEntity} for the given {@link TypeInformation} and {@link Comparator}. The given
|
||||
* {@link Comparator} will be used to define the order of the {@link PersistentProperty} instances added to the
|
||||
* entity.
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
* @param comparator can be {@literal null}.
|
||||
*/
|
||||
public BasicPersistentEntity(TypeInformation<T> information, @Nullable Comparator<P> comparator) {
|
||||
|
||||
Assert.notNull(information, "Information must not be null!");
|
||||
|
||||
this.information = information;
|
||||
this.properties = new ArrayList<>();
|
||||
this.persistentPropertiesCache = new ArrayList<>();
|
||||
this.comparator = comparator;
|
||||
|
||||
this.constructor = information instanceof PreferredConstructorProvider
|
||||
? ((PreferredConstructorProvider<T>) information).getPreferredConstructor()
|
||||
: PreferredConstructorDiscoverer.discover(this);
|
||||
|
||||
this.associations = comparator == null ? new HashSet<>() : new TreeSet<>(new AssociationComparator<>(comparator));
|
||||
|
||||
this.propertyCache = new HashMap<>(16, 1f);
|
||||
|
||||
this.annotationCache = new ConcurrentReferenceHashMap<>(16, ReferenceType.WEAK);
|
||||
if(information instanceof AnnotationAware) {
|
||||
for(Annotation annotation : ((AnnotationAware)information).getAnnotations()) {
|
||||
annotationCache.put(annotation.annotationType(), Optional.of(annotation));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.propertyAnnotationCache = CollectionUtils
|
||||
.toMultiValueMap(new ConcurrentReferenceHashMap<>(16, ReferenceType.WEAK));
|
||||
|
||||
this.propertyAccessorFactory = information instanceof PersistentPropertyAccessorFactoryProvider
|
||||
? ((PersistentPropertyAccessorFactoryProvider) information).getPersistentPropertyAccessorFactory()
|
||||
: BeanWrapperPropertyAccessorFactory.INSTANCE;
|
||||
|
||||
this.typeAlias = Lazy.of(() -> getAliasFromAnnotation(getType()));
|
||||
this.isNewStrategy = Lazy.of(() -> Persistable.class.isAssignableFrom(information.getType()) //
|
||||
? PersistableIsNewStrategy.INSTANCE
|
||||
: getFallbackIsNewStrategy());
|
||||
|
||||
this.isImmutable = Lazy.of(() -> isAnnotationPresent(Immutable.class));
|
||||
this.requiresPropertyPopulation = Lazy.of(() -> !isImmutable() && properties.stream() //
|
||||
.anyMatch(it -> !(isConstructorArgument(it) || it.isTransient())));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistenceConstructor()
|
||||
*/
|
||||
@Nullable
|
||||
public PreferredConstructor<T, P> getPersistenceConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isConstructorArgument(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isConstructorArgument(PersistentProperty<?> property) {
|
||||
return constructor != null && constructor.isConstructorParameter(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isIdProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isIdProperty(PersistentProperty<?> property) {
|
||||
return idProperty != null && idProperty.equals(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isVersionProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isVersionProperty(PersistentProperty<?> property) {
|
||||
return versionProperty != null && versionProperty.equals(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return getType().getName();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getIdProperty()
|
||||
*/
|
||||
@Nullable
|
||||
public P getIdProperty() {
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getVersionProperty()
|
||||
*/
|
||||
@Nullable
|
||||
public P getVersionProperty() {
|
||||
return versionProperty;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#hasIdProperty()
|
||||
*/
|
||||
public boolean hasIdProperty() {
|
||||
return idProperty != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#hasVersionProperty()
|
||||
*/
|
||||
public boolean hasVersionProperty() {
|
||||
return versionProperty != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MutablePersistentEntity#addPersistentProperty(P)
|
||||
*/
|
||||
public void addPersistentProperty(P property) {
|
||||
|
||||
Assert.notNull(property, "Property must not be null!");
|
||||
|
||||
if (properties.contains(property)) {
|
||||
return;
|
||||
}
|
||||
|
||||
properties.add(property);
|
||||
|
||||
if (!property.isTransient() && !property.isAssociation()) {
|
||||
persistentPropertiesCache.add(property);
|
||||
}
|
||||
|
||||
propertyCache.computeIfAbsent(property.getName(), key -> property);
|
||||
|
||||
P candidate = returnPropertyIfBetterIdPropertyCandidateOrNull(property);
|
||||
|
||||
if (candidate != null) {
|
||||
this.idProperty = candidate;
|
||||
}
|
||||
|
||||
if (property.isVersionProperty()) {
|
||||
|
||||
P versionProperty = this.versionProperty;
|
||||
|
||||
if (versionProperty != null) {
|
||||
|
||||
throw new MappingException(
|
||||
String.format(
|
||||
"Attempt to add version property %s but already have property %s registered "
|
||||
+ "as version. Check your mapping configuration!",
|
||||
property.getField(), versionProperty.getField()));
|
||||
}
|
||||
|
||||
this.versionProperty = property;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MutablePersistentEntity#setEvaluationContextProvider(org.springframework.data.spel.EvaluationContextProvider)
|
||||
*/
|
||||
@Override
|
||||
public void setEvaluationContextProvider(EvaluationContextProvider provider) {
|
||||
this.evaluationContextProvider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given property if it is a better candidate for the id property than the current id property.
|
||||
*
|
||||
* @param property the new id property candidate, will never be {@literal null}.
|
||||
* @return the given id property or {@literal null} if the given property is not an id property.
|
||||
*/
|
||||
@Nullable
|
||||
protected P returnPropertyIfBetterIdPropertyCandidateOrNull(P property) {
|
||||
|
||||
if (!property.isIdProperty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
P idProperty = this.idProperty;
|
||||
|
||||
if (idProperty != null) {
|
||||
throw new MappingException(String.format("Attempt to add id property %s but already have property %s registered "
|
||||
+ "as id. Check your mapping configuration!", property.getField(), idProperty.getField()));
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MutablePersistentEntity#addAssociation(org.springframework.data.mapping.model.Association)
|
||||
*/
|
||||
public void addAssociation(Association<P> association) {
|
||||
|
||||
Assert.notNull(association, "Association must not be null!");
|
||||
|
||||
associations.add(association);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public P getPersistentProperty(String name) {
|
||||
return propertyCache.get(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperties(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<P> getPersistentProperties(Class<? extends Annotation> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null!");
|
||||
return propertyAnnotationCache.computeIfAbsent(annotationType, this::doFindPersistentProperty);
|
||||
}
|
||||
|
||||
private List<P> doFindPersistentProperty(Class<? extends Annotation> annotationType) {
|
||||
|
||||
List<P> annotatedProperties = properties.stream() //
|
||||
.filter(it -> it.isAnnotationPresent(annotationType)) //
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!annotatedProperties.isEmpty()) {
|
||||
return annotatedProperties;
|
||||
}
|
||||
|
||||
return associations.stream() //
|
||||
.map(Association::getInverse) //
|
||||
.filter(it -> it.isAnnotationPresent(annotationType)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getType()
|
||||
*/
|
||||
public Class<T> getType() {
|
||||
return information.getType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getTypeAlias()
|
||||
*/
|
||||
public Alias getTypeAlias() {
|
||||
return typeAlias.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getTypeInformation()
|
||||
*/
|
||||
public TypeInformation<T> getTypeInformation() {
|
||||
return information;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#doWithProperties(org.springframework.data.mapping.PropertyHandler)
|
||||
*/
|
||||
public void doWithProperties(PropertyHandler<P> handler) {
|
||||
|
||||
Assert.notNull(handler, "PropertyHandler must not be null!");
|
||||
|
||||
for (P property : persistentPropertiesCache) {
|
||||
handler.doWithPersistentProperty(property);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#doWithProperties(org.springframework.data.mapping.PropertyHandler.Simple)
|
||||
*/
|
||||
@Override
|
||||
public void doWithProperties(SimplePropertyHandler handler) {
|
||||
|
||||
Assert.notNull(handler, "Handler must not be null!");
|
||||
|
||||
for (PersistentProperty<?> property : persistentPropertiesCache) {
|
||||
handler.doWithPersistentProperty(property);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#doWithAssociations(org.springframework.data.mapping.AssociationHandler)
|
||||
*/
|
||||
public void doWithAssociations(AssociationHandler<P> handler) {
|
||||
|
||||
Assert.notNull(handler, "Handler must not be null!");
|
||||
|
||||
for (Association<P> association : associations) {
|
||||
handler.doWithAssociation(association);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#doWithAssociations(org.springframework.data.mapping.SimpleAssociationHandler)
|
||||
*/
|
||||
public void doWithAssociations(SimpleAssociationHandler handler) {
|
||||
|
||||
Assert.notNull(handler, "Handler must not be null!");
|
||||
|
||||
for (Association<? extends PersistentProperty<?>> association : associations) {
|
||||
handler.doWithAssociation(association);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#findAnnotation(java.lang.Class)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <A extends Annotation> A findAnnotation(Class<A> annotationType) {
|
||||
return doFindAnnotation(annotationType).orElse(null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isAnnotationPresent(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <A extends Annotation> boolean isAnnotationPresent(Class<A> annotationType) {
|
||||
return doFindAnnotation(annotationType).isPresent();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <A extends Annotation> Optional<A> doFindAnnotation(Class<A> annotationType) {
|
||||
|
||||
return (Optional<A>) annotationCache.computeIfAbsent(annotationType,
|
||||
it -> Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(getType(), it)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MutablePersistentEntity#verify()
|
||||
*/
|
||||
public void verify() {
|
||||
|
||||
if (comparator != null) {
|
||||
properties.sort(comparator);
|
||||
persistentPropertiesCache.sort(comparator);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MutablePersistentEntity#setPersistentPropertyAccessorFactory(org.springframework.data.mapping.model.PersistentPropertyAccessorFactory)
|
||||
*/
|
||||
@Override
|
||||
public void setPersistentPropertyAccessorFactory(PersistentPropertyAccessorFactory factory) {
|
||||
this.propertyAccessorFactory = factory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPropertyAccessor(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public <B> PersistentPropertyAccessor<B> getPropertyAccessor(B bean) {
|
||||
|
||||
verifyBeanType(bean);
|
||||
|
||||
return propertyAccessorFactory.getPropertyAccessor(this, bean);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPropertyPathAccessor(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public <B> PersistentPropertyPathAccessor<B> getPropertyPathAccessor(B bean) {
|
||||
return new SimplePersistentPropertyPathAccessor<>(getPropertyAccessor(bean));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getIdentifierAccessor(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public IdentifierAccessor getIdentifierAccessor(Object bean) {
|
||||
|
||||
verifyBeanType(bean);
|
||||
|
||||
if (Persistable.class.isAssignableFrom(getType())) {
|
||||
return new PersistableIdentifierAccessor((Persistable<?>) bean);
|
||||
}
|
||||
|
||||
return hasIdProperty() ? new IdPropertyIdentifierAccessor(this, bean) : new AbsentIdentifierAccessor(bean);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isNew(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean isNew(Object bean) {
|
||||
|
||||
verifyBeanType(bean);
|
||||
|
||||
return isNewStrategy.get().isNew(bean);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isImmutable()
|
||||
*/
|
||||
@Override
|
||||
public boolean isImmutable() {
|
||||
return isImmutable.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#requiresPropertyPopulation()
|
||||
*/
|
||||
@Override
|
||||
public boolean requiresPropertyPopulation() {
|
||||
return requiresPropertyPopulation.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
@Override
|
||||
public Iterator<P> iterator() {
|
||||
|
||||
Iterator<P> iterator = properties.iterator();
|
||||
|
||||
return new Iterator<P>() {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public P next() {
|
||||
return iterator.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected EvaluationContext getEvaluationContext(Object rootObject) {
|
||||
return evaluationContextProvider.getEvaluationContext(rootObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default {@link IsNewStrategy} to be used. Will be a {@link PersistentEntityIsNewStrategy} by default.
|
||||
* Note, that this strategy only gets used if the entity doesn't implement {@link Persistable} as this indicates the
|
||||
* user wants to be in control over whether an entity is new or not.
|
||||
*
|
||||
* @return
|
||||
* @since 2.1
|
||||
*/
|
||||
protected IsNewStrategy getFallbackIsNewStrategy() {
|
||||
return PersistentEntityIsNewStrategy.of(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the given bean type to no be {@literal null} and of the type of the current {@link PersistentEntity}.
|
||||
*
|
||||
* @param bean must not be {@literal null}.
|
||||
*/
|
||||
private void verifyBeanType(Object bean) {
|
||||
|
||||
Assert.notNull(bean, "Target bean must not be null!");
|
||||
Assert.isInstanceOf(getType(), bean,
|
||||
() -> String.format(TYPE_MISMATCH, bean.getClass().getName(), getType().getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the {@link Alias} to be used for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static Alias getAliasFromAnnotation(Class<?> type) {
|
||||
|
||||
Optional<String> typeAliasValue = Optional
|
||||
.ofNullable(AnnotatedElementUtils.findMergedAnnotation(type, TypeAlias.class))//
|
||||
.map(TypeAlias::value)//
|
||||
.filter(StringUtils::hasText);
|
||||
|
||||
return Alias.ofNullable(typeAliasValue.orElse(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* A null-object implementation of {@link IdentifierAccessor} to be able to return an accessor for entities that do
|
||||
* not have an identifier property.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class AbsentIdentifierAccessor extends TargetAwareIdentifierAccessor {
|
||||
|
||||
public AbsentIdentifierAccessor(Object target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.IdentifierAccessor#getIdentifier()
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getIdentifier() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple {@link Comparator} adaptor to delegate ordering to the inverse properties of the association.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static final class AssociationComparator<P extends PersistentProperty<P>>
|
||||
implements Comparator<Association<P>>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4508054194886854513L;
|
||||
private final Comparator<P> delegate;
|
||||
|
||||
AssociationComparator(Comparator<P> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public int compare(@Nullable Association<P> left, @Nullable Association<P> right) {
|
||||
|
||||
if (left == null) {
|
||||
throw new IllegalArgumentException("Left argument must not be null!");
|
||||
}
|
||||
|
||||
if (right == null) {
|
||||
throw new IllegalArgumentException("Right argument must not be null!");
|
||||
}
|
||||
|
||||
return delegate.compare(left.getInverse(), right.getInverse());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple value object allowing access to {@link EntityInstantiator} instances for a given type falling back to a
|
||||
* default one.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 2.3
|
||||
*/
|
||||
public class EntityInstantiators {
|
||||
|
||||
private final EntityInstantiator fallback;
|
||||
private final Map<Class<?>, EntityInstantiator> customInstantiators;
|
||||
|
||||
/**
|
||||
* Creates a new {@link EntityInstantiators} using the default fallback instantiator and no custom ones.
|
||||
*/
|
||||
public EntityInstantiators() {
|
||||
this(Collections.emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link EntityInstantiators} using the given {@link EntityInstantiator} as fallback.
|
||||
*
|
||||
* @param fallback must not be {@literal null}.
|
||||
*/
|
||||
public EntityInstantiators(EntityInstantiator fallback) {
|
||||
this(fallback, Collections.emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link EntityInstantiators} using the default fallback instantiator and the given custom ones.
|
||||
*
|
||||
* @param customInstantiators must not be {@literal null}.
|
||||
*/
|
||||
public EntityInstantiators(Map<Class<?>, EntityInstantiator> customInstantiators) {
|
||||
this(new KotlinClassGeneratingEntityInstantiator(), customInstantiators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link EntityInstantiator} using the given fallback {@link EntityInstantiator} and the given custom
|
||||
* ones.
|
||||
*
|
||||
* @param defaultInstantiator must not be {@literal null}.
|
||||
* @param customInstantiators must not be {@literal null}.
|
||||
*/
|
||||
public EntityInstantiators(EntityInstantiator defaultInstantiator,
|
||||
Map<Class<?>, EntityInstantiator> customInstantiators) {
|
||||
|
||||
Assert.notNull(defaultInstantiator, "DefaultInstantiator must not be null!");
|
||||
Assert.notNull(customInstantiators, "CustomInstantiators must not be null!");
|
||||
|
||||
this.fallback = defaultInstantiator;
|
||||
this.customInstantiators = customInstantiators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link EntityInstantiator} to be used to create the given {@link PersistentEntity}.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public EntityInstantiator getInstantiatorFor(PersistentEntity<?, ?> entity) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null!");
|
||||
Class<?> type = entity.getType();
|
||||
|
||||
if (!customInstantiators.containsKey(type)) {
|
||||
|
||||
if (entity.getTypeInformation() instanceof EntiyInstantiatorAware) {
|
||||
return ((EntiyInstantiatorAware) entity.getTypeInformation()).getEntiyInstantiatorOrDefault(fallback);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
EntityInstantiator instantiator = customInstantiators.get(entity.getType());
|
||||
return instantiator == null ? fallback : instantiator;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 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.mapping.model;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public interface EntiyInstantiatorAware {
|
||||
|
||||
@Nullable
|
||||
EntityInstantiator getEntityInstantiator();
|
||||
|
||||
default EntityInstantiator getEntiyInstantiatorOrDefault(EntityInstantiator fallback) {
|
||||
|
||||
EntityInstantiator entityInstantiator = getEntityInstantiator();
|
||||
return entityInstantiator != null ? entityInstantiator : fallback;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.mapping.model;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public interface PersistentPropertyAccessorFactoryProvider {
|
||||
|
||||
@Nullable
|
||||
PersistentPropertyAccessorFactory getPersistentPropertyAccessorFactory();
|
||||
|
||||
default PersistentPropertyAccessorFactory getPersistentPropertyAccessorFactoryOrDefault(
|
||||
PersistentPropertyAccessorFactory fallback) {
|
||||
|
||||
PersistentPropertyAccessorFactory factory = getPersistentPropertyAccessorFactory();
|
||||
return factory != null ? factory : fallback;
|
||||
}
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016-2020 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
|
||||
*
|
||||
* https://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.model;
|
||||
|
||||
import java.beans.FeatureDescriptor;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Value object to abstract the concept of a property backed by a {@link Field} and / or a {@link PropertyDescriptor}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class Property {
|
||||
|
||||
private @Nullable TypeInformation<?> typeInformation;
|
||||
private List<Annotation> annotations;
|
||||
|
||||
private final Optional<Field> field;
|
||||
private final Optional<PropertyDescriptor> descriptor;
|
||||
|
||||
private final Class<?> rawType;
|
||||
private final Lazy<Integer> hashCode;
|
||||
private final Optional<Method> getter;
|
||||
private final Optional<Method> setter;
|
||||
|
||||
private final Lazy<String> name;
|
||||
private final Lazy<String> toString;
|
||||
private final Lazy<Optional<Method>> wither;
|
||||
|
||||
private Property(String name, TypeInformation<?> typeInformation, List<Annotation> annotations) {
|
||||
|
||||
this.annotations = annotations;
|
||||
this.typeInformation = typeInformation;
|
||||
this.field = Optional.empty();
|
||||
this.descriptor = Optional.empty();
|
||||
|
||||
this.rawType = typeInformation.getType();
|
||||
this.hashCode = Lazy.of( () -> typeInformation.hashCode() + name.hashCode());
|
||||
this.getter = Optional.empty();
|
||||
this.setter = Optional.empty();
|
||||
this.name = Lazy.of(name);
|
||||
this.toString = Lazy.of(() -> typeInformation.toString() + name);
|
||||
this.wither = Lazy.of(() -> findWither(typeInformation, getName(), getType()));
|
||||
}
|
||||
|
||||
private Property(TypeInformation<?> type, Optional<Field> field, Optional<PropertyDescriptor> descriptor) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.isTrue(Optionals.isAnyPresent(field, descriptor), "Either field or descriptor has to be given!");
|
||||
|
||||
this.annotations = Collections.emptyList();
|
||||
this.field = field;
|
||||
this.descriptor = descriptor;
|
||||
|
||||
this.rawType = withFieldOrDescriptor( //
|
||||
it -> type.getRequiredProperty(it.getName()).getType(), //
|
||||
it -> type.getRequiredProperty(it.getName()).getType() //
|
||||
);
|
||||
this.hashCode = Lazy.of(() -> withFieldOrDescriptor(Object::hashCode));
|
||||
this.name = Lazy.of(() -> withFieldOrDescriptor(Field::getName, FeatureDescriptor::getName));
|
||||
this.toString = Lazy.of(() -> withFieldOrDescriptor(Object::toString,
|
||||
it -> String.format("%s.%s", type.getType().getName(), it.getDisplayName())));
|
||||
|
||||
this.getter = descriptor.map(PropertyDescriptor::getReadMethod)//
|
||||
.filter(it -> getType() != null)//
|
||||
.filter(it -> getType().isAssignableFrom(type.getReturnType(it).getType()));
|
||||
|
||||
this.setter = descriptor.map(PropertyDescriptor::getWriteMethod)//
|
||||
.filter(it -> getType() != null)//
|
||||
.filter(it -> type.getParameterTypes(it).get(0).getType().isAssignableFrom(getType()));
|
||||
|
||||
this.wither = Lazy.of(() -> findWither(type, getName(), getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Property} backed by the given field.
|
||||
*
|
||||
* @param type the owning type, must not be {@literal null}.
|
||||
* @param field must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Property of(TypeInformation<?> type, Field field) {
|
||||
|
||||
Assert.notNull(field, "Field must not be null!");
|
||||
|
||||
return new Property(type, Optional.of(field), Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Property} backed by the given {@link Field} and {@link PropertyDescriptor}.
|
||||
*
|
||||
* @param type the owning type, must not be {@literal null}.
|
||||
* @param field must not be {@literal null}.
|
||||
* @param descriptor must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Property of(TypeInformation<?> type, Field field, PropertyDescriptor descriptor) {
|
||||
|
||||
Assert.notNull(field, "Field must not be null!");
|
||||
Assert.notNull(descriptor, "PropertyDescriptor must not be null!");
|
||||
|
||||
return new Property(type, Optional.of(field), Optional.of(descriptor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Property} backed by the given {@link Field} and {@link PropertyDescriptor}.
|
||||
*
|
||||
* @param type the owning type, must not be {@literal null}.
|
||||
* @param field must not be {@literal null}.
|
||||
* @param descriptor must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Property of(TypeInformation<?> type, String name) {
|
||||
return new Property(name, type, Collections.emptyList());
|
||||
}
|
||||
|
||||
public static Property of(TypeInformation<?> type, String name, List<Annotation> annotations) {
|
||||
return new Property(name, type, annotations != null ? annotations : Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Property} for the given {@link PropertyDescriptor}. The creation might fail if the given
|
||||
* property is not representing a proper property.
|
||||
*
|
||||
* @param type the owning type, must not be {@literal null}.
|
||||
* @param descriptor must not be {@literal null}.
|
||||
* @return
|
||||
* @see #supportsStandalone(PropertyDescriptor)
|
||||
*/
|
||||
public static Property of(TypeInformation<?> type, PropertyDescriptor descriptor) {
|
||||
|
||||
Assert.notNull(descriptor, "PropertyDescriptor must not be null!");
|
||||
|
||||
return new Property(type, Optional.empty(), Optional.of(descriptor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PropertyDescriptor} is supported in for standalone creation of a {@link Property}
|
||||
* instance.
|
||||
*
|
||||
* @param descriptor
|
||||
* @return
|
||||
*/
|
||||
public static boolean supportsStandalone(PropertyDescriptor descriptor) {
|
||||
|
||||
Assert.notNull(descriptor, "PropertyDescriptor must not be null!");
|
||||
|
||||
return descriptor.getPropertyType() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the property is backed by a field.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isFieldBacked() {
|
||||
return field.isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the getter of the property if available and if it matches the type of the property.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public Optional<Method> getGetter() {
|
||||
return getter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setter of the property if available and if its first (only) parameter matches the type of the property.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public Optional<Method> getSetter() {
|
||||
return setter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wither of the property if available and if its first (only) parameter matches the type of the property.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public Optional<Method> getWither() {
|
||||
return wither.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field of the property if available and if its first (only) parameter matches the type of the property.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public Optional<Field> getField() {
|
||||
return this.field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the property exposes a getter or a setter.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasAccessor() {
|
||||
return getGetter().isPresent() || getSetter().isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the property.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the property.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return rawType;
|
||||
}
|
||||
|
||||
public List<Annotation> getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Property)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Property that = (Property) obj;
|
||||
if(this.typeInformation != null && that.typeInformation != null) {
|
||||
if(this.typeInformation != that.typeInformation) {
|
||||
return false;
|
||||
}
|
||||
if(!this.name.get().equals(that.name.get())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return this.field.isPresent() ? this.field.equals(that.field) : this.descriptor.equals(that.descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the backing {@link Field} or {@link PropertyDescriptor} using the given {@link Function}.
|
||||
*
|
||||
* @param function must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private <T> T withFieldOrDescriptor(Function<Object, T> function) {
|
||||
return withFieldOrDescriptor(function, function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the backing {@link Field} or {@link PropertyDescriptor} using the given functions.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @param descriptor must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private <T> T withFieldOrDescriptor(Function<? super Field, T> field,
|
||||
Function<? super PropertyDescriptor, T> descriptor) {
|
||||
|
||||
return Optionals.firstNonEmpty(//
|
||||
() -> this.field.map(field), //
|
||||
() -> this.descriptor.map(descriptor))//
|
||||
.orElseThrow(() -> new IllegalStateException("Should not occur! Either field or descriptor has to be given"));
|
||||
}
|
||||
|
||||
private static Optional<Method> findWither(TypeInformation<?> owner, String propertyName, Class<?> rawType) {
|
||||
|
||||
AtomicReference<Method> resultHolder = new AtomicReference<>();
|
||||
String methodName = String.format("with%s", StringUtils.capitalize(propertyName));
|
||||
|
||||
ReflectionUtils.doWithMethods(owner.getType(), it -> {
|
||||
|
||||
if (owner.isAssignableFrom(owner.getReturnType(it))) {
|
||||
resultHolder.set(it);
|
||||
}
|
||||
}, it -> isMethodWithSingleParameterOfType(it, methodName, rawType));
|
||||
|
||||
Method method = resultHolder.get();
|
||||
return method != null ? Optional.of(method) : Optional.empty();
|
||||
}
|
||||
|
||||
private static boolean isMethodWithSingleParameterOfType(Method method, String name, Class<?> type) {
|
||||
|
||||
return method.getParameterCount() == 1 //
|
||||
&& method.getName().equals(name) //
|
||||
&& method.getParameterTypes()[0].equals(type);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 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.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public class StaticPropertyAccessorFactory implements PersistentPropertyAccessorFactory {
|
||||
|
||||
private static final StaticPropertyAccessorFactory INSTANCE = new StaticPropertyAccessorFactory();
|
||||
|
||||
public static StaticPropertyAccessorFactory instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PersistentPropertyAccessorFactory#getPropertyAccessor(org.springframework.data.mapping.PersistentEntity, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public <T> PersistentPropertyAccessor<T> getPropertyAccessor(PersistentEntity<?, ?> entity, T bean) {
|
||||
|
||||
System.out.println("Obtaining static property acessor for entity " + entity.getName());
|
||||
return new StaticPropertyAccessor<>((AccessorFunctionAware<T>) entity.getTypeInformation(), bean);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PersistentPropertyAccessorFactory#isSupported(org.springframework.data.mapping.PersistentEntity)
|
||||
*/
|
||||
@Override
|
||||
public boolean isSupported(PersistentEntity<?, ?> entity) {
|
||||
|
||||
boolean isStaticTypedEntity = entity.getTypeInformation() instanceof AccessorFunctionAware;
|
||||
System.out.println(entity.getName() + " isStaticTypedEntity: " + isStaticTypedEntity);
|
||||
return isStaticTypedEntity;
|
||||
}
|
||||
|
||||
static class StaticPropertyAccessor<T> implements PersistentPropertyAccessor<T> {
|
||||
|
||||
T bean;
|
||||
AccessorFunctionAware<T> accessorFunctionAware;
|
||||
|
||||
public StaticPropertyAccessor(AccessorFunctionAware<T> accessorFunctionAware, T bean) {
|
||||
this.bean = bean;
|
||||
this.accessorFunctionAware = accessorFunctionAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(PersistentProperty<?> property, @Nullable Object value) {
|
||||
|
||||
if (!accessorFunctionAware.hasSetFunctionFor(property.getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.bean = accessorFunctionAware.getSetFunctionFor(property.getName()).apply(bean, value);
|
||||
System.out.println(
|
||||
"setting value " + value + " via setter function for " + property.getName() + " resulting in " + bean);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getProperty(PersistentProperty<?> property) {
|
||||
|
||||
if (!accessorFunctionAware.hasGetFunctionFor(property.getName())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object value = accessorFunctionAware.getGetFunctionFor(property.getName()).apply(bean);
|
||||
System.out.println("obtaining value " + value + " from getter function for " + property.getName());
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBean() {
|
||||
return this.bean;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 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.util;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.model.EntityInstantiator;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public class AddressTypeInformation extends DomainTypeInformation<Address> {
|
||||
|
||||
private static final AddressTypeInformation INSTANCE = new AddressTypeInformation();
|
||||
|
||||
private AddressTypeInformation() {
|
||||
super(Address.class);
|
||||
}
|
||||
|
||||
public static AddressTypeInformation instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void computeFields() {
|
||||
|
||||
addField(Field.<Address> string("city").getter(Address::getCity));
|
||||
addField(Field.<Address> string("street").getter(Address::getStreet));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityInstantiator computeEntityInstantiator() {
|
||||
return new EntityInstantiator() {
|
||||
|
||||
@Override
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
String city = (String) provider
|
||||
.getParameterValue(new Parameter("city", new StringTypeInformation(), new Annotation[] {}, entity));
|
||||
String street = (String) provider
|
||||
.getParameterValue(new Parameter("street", new StringTypeInformation(), new Annotation[] {}, entity));
|
||||
|
||||
T address = (T) new Address(city, street);
|
||||
System.out.println("Created new Address instance via constructor using values (" + city + ", " + street
|
||||
+ ") resulting in " + address);
|
||||
return address;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PreferredConstructor computePreferredConstructor() {
|
||||
return StaticPreferredConstructor.of("city", "street");
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.util;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public interface AnnotationAware {
|
||||
|
||||
List<Annotation> getAnnotations();
|
||||
|
||||
boolean hasAnnotation(Class<?> annotationType);
|
||||
|
||||
<T extends Annotation> List<T> findAnnotation(Class<T> annotation);
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2020 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
|
||||
*
|
||||
* https://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.util;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;
|
||||
|
||||
/**
|
||||
* {@link TypeInformation} for a plain {@link Class}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
|
||||
|
||||
public static final ClassTypeInformation<Collection> COLLECTION = new ClassTypeInformation(Collection.class);
|
||||
public static final ClassTypeInformation<List> LIST = new ClassTypeInformation(List.class);
|
||||
public static final ClassTypeInformation<Set> SET = new ClassTypeInformation(Set.class);
|
||||
public static final ClassTypeInformation<Map> MAP = new ClassTypeInformation(Map.class);
|
||||
public static final ClassTypeInformation<Object> OBJECT = new ClassTypeInformation(Object.class);
|
||||
|
||||
// cannot use reference hash map cause static type information might not be referenced from outside and get discarded
|
||||
private static final Map<Class<?>, ClassTypeInformation<?>> cache = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
Arrays.asList(COLLECTION, LIST, SET, MAP, OBJECT).forEach(it -> cache.put(it.getType(), it));
|
||||
}
|
||||
|
||||
private final Class<S> type;
|
||||
|
||||
public static void warmCache(ClassTypeInformation<?>... typeInformations) {
|
||||
for(ClassTypeInformation<?> information : typeInformations) {
|
||||
cache.put(information.getType(), information);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple factory method to easily create new instances of {@link ClassTypeInformation}.
|
||||
*
|
||||
* @param <S>
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static <S> ClassTypeInformation<S> from(Class<S> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
return (ClassTypeInformation<S>) cache.computeIfAbsent(type, ClassTypeInformation::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TypeInformation} from the given method's return type.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static <S> TypeInformation<S> fromReturnTypeOf(Method method) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null!");
|
||||
return (TypeInformation<S>) ClassTypeInformation.from(method.getDeclaringClass())
|
||||
.createInfo(method.getGenericReturnType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link ClassTypeInformation} for the given type.
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
ClassTypeInformation(Class<S> type) {
|
||||
super(ProxyUtils.getUserClass(type), getTypeVariableMap(type));
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
ClassTypeInformation(Class<S> type, TypeInformation<?> componentType, TypeInformation<?> keyType) {
|
||||
super(type, componentType, keyType);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Little helper to allow us to create a generified map, actually just to satisfy the compiler.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static Map<TypeVariable<?>, Type> getTypeVariableMap(Class<?> type) {
|
||||
return getTypeVariableMap(type, new HashSet<>());
|
||||
}
|
||||
|
||||
private static Map<TypeVariable<?>, Type> getTypeVariableMap(Class<?> type, Collection<Type> visited) {
|
||||
|
||||
if (visited.contains(type)) {
|
||||
return Collections.emptyMap();
|
||||
} else {
|
||||
visited.add(type);
|
||||
}
|
||||
|
||||
Map<TypeVariable, Type> source = GenericTypeResolver.getTypeVariableMap(type);
|
||||
Map<TypeVariable<?>, Type> map = new HashMap<>(source.size());
|
||||
|
||||
for (Entry<TypeVariable, Type> entry : source.entrySet()) {
|
||||
|
||||
Type value = entry.getValue();
|
||||
map.put(entry.getKey(), entry.getValue());
|
||||
|
||||
if (value instanceof Class) {
|
||||
|
||||
for (Entry<TypeVariable<?>, Type> nestedEntry : getTypeVariableMap((Class<?>) value, visited).entrySet()) {
|
||||
if (!map.containsKey(nestedEntry.getKey())) {
|
||||
map.put(nestedEntry.getKey(), nestedEntry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#getType()
|
||||
*/
|
||||
@Override
|
||||
public Class<S> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#getRawTypeInformation()
|
||||
*/
|
||||
@Override
|
||||
public ClassTypeInformation<?> getRawTypeInformation() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#isAssignableFrom(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssignableFrom(TypeInformation<?> target) {
|
||||
return getType().isAssignableFrom(target.getType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#specialize(org.springframework.data.util.ClassTypeInformation)
|
||||
*/
|
||||
@Override
|
||||
public TypeInformation<? extends S> specialize(ClassTypeInformation<?> type) {
|
||||
return (TypeInformation<? extends S>) type;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.getName();
|
||||
}
|
||||
}
|
||||
@@ -1,343 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 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.util;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructorProvider;
|
||||
import org.springframework.data.mapping.model.AccessorFunctionAware;
|
||||
import org.springframework.data.mapping.model.EntityInstantiator;
|
||||
import org.springframework.data.mapping.model.EntiyInstantiatorAware;
|
||||
import org.springframework.data.mapping.model.PersistentPropertyAccessorFactory;
|
||||
import org.springframework.data.mapping.model.PersistentPropertyAccessorFactoryProvider;
|
||||
import org.springframework.data.mapping.model.StaticPropertyAccessorFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public class DomainTypeInformation<S> extends ClassTypeInformation<S>
|
||||
implements AnnotationAware, EntiyInstantiatorAware, PreferredConstructorProvider<S>,
|
||||
PersistentPropertyAccessorFactoryProvider, AccessorFunctionAware<S> {
|
||||
|
||||
private final Class<S> type;
|
||||
|
||||
@Nullable private final TypeInformation<?> componentType;
|
||||
@Nullable private final TypeInformation<?> keyType;
|
||||
|
||||
private DomainTypeInformation<?> superTypeInformation;
|
||||
private List<TypeInformation<?>> typeArguments;
|
||||
private MultiValueMap<Class<? extends Annotation>, Annotation> annotations;
|
||||
|
||||
private final Fields fields;
|
||||
|
||||
private EntityInstantiator instantiator;
|
||||
private PreferredConstructor<S, ?> preferredConstructor;
|
||||
|
||||
public DomainTypeInformation(Class<S> type) {
|
||||
this(type, null, null);
|
||||
}
|
||||
|
||||
public DomainTypeInformation(Class<S> type, @Nullable TypeInformation<?> componentType,
|
||||
@Nullable TypeInformation<?> keyType) {
|
||||
|
||||
super(type, componentType, keyType);
|
||||
this.type = type;
|
||||
this.componentType = componentType;
|
||||
this.keyType = keyType;
|
||||
this.typeArguments = computeTypeArguments();
|
||||
this.instantiator = computeEntityInstantiator();
|
||||
this.preferredConstructor = computePreferredConstructor();
|
||||
this.annotations = new LinkedMultiValueMap<>();
|
||||
this.fields = new Fields(type);
|
||||
|
||||
computeFields();
|
||||
computeAnnotations();
|
||||
}
|
||||
|
||||
protected void addField(Field<?, S> field) {
|
||||
this.fields.add(field);
|
||||
}
|
||||
|
||||
protected List<TypeInformation<?>> computeTypeArguments() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected EntityInstantiator computeEntityInstantiator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected PreferredConstructor<S, ?> computePreferredConstructor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreferredConstructor<S, ?> getPreferredConstructor() {
|
||||
return preferredConstructor;
|
||||
}
|
||||
|
||||
protected void computeFields() {
|
||||
//
|
||||
}
|
||||
|
||||
protected void computeAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
protected void addAnnotation(Annotation annotation) {
|
||||
this.annotations.add(annotation.annotationType(), annotation);
|
||||
}
|
||||
|
||||
public void doWithFields(BiConsumer<String, Field<?, S>> consumer) {
|
||||
fields.doWithFields(consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInformation<?>> getParameterTypes(Constructor<?> constructor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeInformation<?> getProperty(String property) {
|
||||
|
||||
if (!fields.hasField(property)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fields.getField(property).getTypeInformation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollectionLike() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeInformation<?> getMapValueType() {
|
||||
return componentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<S> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassTypeInformation<?> getRawTypeInformation() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeInformation<?> getActualType() {
|
||||
return componentType != null ? componentType : this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeInformation<?> getReturnType(Method method) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInformation<?>> getParameterTypes(Method method) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeInformation<?> getSuperTypeInformation(Class<?> superType) {
|
||||
return superTypeInformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssignableFrom(TypeInformation<?> target) {
|
||||
return this.type.isAssignableFrom(target.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInformation<?>> getTypeArguments() {
|
||||
return typeArguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeInformation<? extends S> specialize(ClassTypeInformation<?> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
if (!super.equals(o))
|
||||
return false;
|
||||
|
||||
DomainTypeInformation<?> that = (DomainTypeInformation<?>) o;
|
||||
|
||||
if (!ObjectUtils.nullSafeEquals(type, that.type)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(componentType, that.componentType)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(keyType, that.keyType)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(superTypeInformation, that.superTypeInformation)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(typeArguments, that.typeArguments)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(fields, that.fields)) {
|
||||
return false;
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(instantiator, that.instantiator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(type);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(componentType);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(keyType);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(superTypeInformation);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(typeArguments);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(fields);
|
||||
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(instantiator);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public EntityInstantiator getEntityInstantiator() {
|
||||
return instantiator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Annotation> getAnnotations() {
|
||||
|
||||
List<Annotation> all = new ArrayList<>();
|
||||
annotations.values().forEach(all::addAll);
|
||||
return all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnnotation(Class<?> annotationType) {
|
||||
return annotations.containsKey(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> List<T> findAnnotation(Class<T> annotation) {
|
||||
return (List<T>) annotations.getOrDefault(annotation, Collections.emptyList());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PersistentPropertyAccessorFactory getPersistentPropertyAccessorFactory() {
|
||||
return StaticPropertyAccessorFactory.instance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiFunction<S, Object, S> getSetFunctionFor(String fieldName) {
|
||||
|
||||
Field<Object, S> entityField = fields.getField(fieldName);
|
||||
if (entityField == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return entityField.getSetter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<S, Object> getGetFunctionFor(String fieldName) {
|
||||
|
||||
Field<Object, S> entityField = fields.getField(fieldName);
|
||||
if (entityField == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return entityField.getGetter();
|
||||
}
|
||||
|
||||
public static class StaticPreferredConstructor extends PreferredConstructor {
|
||||
|
||||
private List<String> args;
|
||||
|
||||
public StaticPreferredConstructor(List<String> args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public static StaticPreferredConstructor of(String... args) {
|
||||
return new StaticPreferredConstructor(Arrays.asList(args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstructorParameter(PersistentProperty property) {
|
||||
|
||||
if (args.contains(property.getName())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.isConstructorParameter(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasParameters() {
|
||||
return !args.isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 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.util;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public class Field<T, O> implements AnnotationAware {
|
||||
|
||||
@Nullable Class<O> owner;
|
||||
String propertyName;
|
||||
|
||||
TypeInformation<T> typeInformation;
|
||||
@Nullable TypeInformation<?> componentType;
|
||||
@Nullable TypeInformation<?> keyType;
|
||||
|
||||
MultiValueMap<Class<? extends Annotation>, Annotation> annotations;
|
||||
|
||||
@Nullable Function<O, T> getterFunction;
|
||||
@Nullable BiFunction<O, T, O> setterFunction;
|
||||
|
||||
public Field(String propertyName, TypeInformation<T> propertyTypeInformation) {
|
||||
|
||||
this.propertyName = propertyName;
|
||||
this.typeInformation = propertyTypeInformation;
|
||||
this.annotations = new LinkedMultiValueMap<>();
|
||||
}
|
||||
|
||||
public static <T, O> Field<T, O> simple(Class<T> type, String propertyName) {
|
||||
|
||||
if (type == String.class) {
|
||||
return (Field<T, O>) string(propertyName);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown simple type: " + type);
|
||||
}
|
||||
|
||||
public static <S> Field<String, S> string(String propertyName) {
|
||||
return new Field<>(propertyName, StringTypeInformation.instance());
|
||||
}
|
||||
|
||||
public static <S> Field<Long, S> int64(String propertyName) {
|
||||
return new Field<>(propertyName, DomainTypeInformation.from(Long.class));
|
||||
}
|
||||
|
||||
public static <S> Field<Integer, S> int32(String propertyName) {
|
||||
return new Field<>(propertyName, DomainTypeInformation.from(Integer.class));
|
||||
}
|
||||
|
||||
public static <S, T> Field<T, S> type(String propertyName, TypeInformation<T> type) {
|
||||
return new Field<>(propertyName, type);
|
||||
}
|
||||
|
||||
public Field<T, O> annotation(Annotation annotation) {
|
||||
|
||||
annotations.add(annotation.annotationType(), annotation);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Field<T, O> wither(BiFunction<O, T, O> setterFunction) {
|
||||
|
||||
this.setterFunction = setterFunction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Field<T, O> setter(BiConsumer<O, T> setterFunction) {
|
||||
|
||||
return wither((o, t) -> {
|
||||
|
||||
setterFunction.accept(o, t);
|
||||
return o;
|
||||
});
|
||||
}
|
||||
|
||||
public Field<T, O> getter(Function<O, T> getterFunction) {
|
||||
|
||||
this.getterFunction = getterFunction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Field<T, O> valueType(TypeInformation<?> valueTypeInformation) {
|
||||
this.componentType = valueTypeInformation;
|
||||
return this;
|
||||
}
|
||||
|
||||
Field<T, O> owner(Class<O> owner) {
|
||||
|
||||
this.owner = owner;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TypeInformation<?> getValueType() {
|
||||
return componentType != null ? componentType : typeInformation;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public TypeInformation<T> getTypeInformation() {
|
||||
return typeInformation;
|
||||
}
|
||||
|
||||
public boolean hasSetter() {
|
||||
return setterFunction != null;
|
||||
}
|
||||
|
||||
public boolean hasGetter() {
|
||||
return getterFunction != null;
|
||||
}
|
||||
|
||||
public BiFunction<O, T, O> getSetter() {
|
||||
return setterFunction;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Function<O, T> getGetter() {
|
||||
return getterFunction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Annotation> getAnnotations() {
|
||||
List<Annotation> all = new ArrayList<>();
|
||||
annotations.values().forEach(all::addAll);
|
||||
return all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnnotation(Class<?> annotationType) {
|
||||
return annotations.containsKey(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> List<T> findAnnotation(Class<T> annotation) {
|
||||
return (List<T>) annotations.getOrDefault(annotation, Collections.emptyList());
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 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.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public class Fields<O> implements Iterable<Field<?, O>> {
|
||||
|
||||
private final Class<O> owner;
|
||||
private final Map<String, Field<?, O>> fields;
|
||||
|
||||
public Fields(Class<O> owner) {
|
||||
|
||||
this.owner = owner;
|
||||
this.fields = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public Fields<O> add(Field<?, O> field) {
|
||||
|
||||
this.fields.put(field.getFieldName(), field.owner(owner));
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasField(String fieldName) {
|
||||
return this.fields.containsKey(fieldName);
|
||||
}
|
||||
|
||||
public <S> Field<S, O> getField(String fieldName) {
|
||||
return (Field<S, O>) this.fields.get(fieldName);
|
||||
}
|
||||
|
||||
public void doWithFields(BiConsumer<String, Field<?, O>> consumer) {
|
||||
fields.forEach(consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Field<?, O>> iterator() {
|
||||
return fields.values().iterator();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 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.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public class ListTypeInformation<S> extends DomainTypeInformation<List<S>> {
|
||||
|
||||
public ListTypeInformation(TypeInformation<S> componentType) {
|
||||
super((Class) List.class, componentType, null);
|
||||
}
|
||||
|
||||
public static <S> ListTypeInformation<S> listOf(TypeInformation<S> componentType) {
|
||||
return new ListTypeInformation<>(componentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollectionLike() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 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.util;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public class StaticTypeInformationProvider {
|
||||
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 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.util;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public class StringTypeInformation extends DomainTypeInformation<String> {
|
||||
|
||||
private static final StringTypeInformation INSTANCE = new StringTypeInformation();
|
||||
|
||||
public StringTypeInformation() {
|
||||
super(String.class);
|
||||
}
|
||||
|
||||
public static TypeInformation<String> instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
@@ -1,672 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2020 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
|
||||
*
|
||||
* https://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.util;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Basic {@link TypeDiscoverer} that contains basic functionality to discover property types.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
private static final Class<?>[] MAP_TYPES;
|
||||
|
||||
static {
|
||||
|
||||
ClassLoader classLoader = TypeDiscoverer.class.getClassLoader();
|
||||
|
||||
Set<Class<?>> mapTypes = new HashSet<>();
|
||||
mapTypes.add(Map.class);
|
||||
|
||||
try {
|
||||
mapTypes.add(ClassUtils.forName("io.vavr.collection.Map", classLoader));
|
||||
} catch (ClassNotFoundException o_O) {}
|
||||
|
||||
MAP_TYPES = mapTypes.toArray(new Class[0]);
|
||||
}
|
||||
|
||||
private final Type type;
|
||||
private final Map<TypeVariable<?>, Type> typeVariableMap;
|
||||
private final Map<String, Optional<TypeInformation<?>>> fieldTypes = new ConcurrentHashMap<>();
|
||||
private final int hashCode;
|
||||
|
||||
private final Lazy<Class<S>> resolvedType;
|
||||
private final Lazy<TypeInformation<?>> componentType;
|
||||
private final Lazy<TypeInformation<?>> valueType;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypeDiscoverer} for the given type, type variable map and parent.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param typeVariableMap must not be {@literal null}.
|
||||
*/
|
||||
protected TypeDiscoverer(Type type, Map<TypeVariable<?>, Type> typeVariableMap) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.notNull(typeVariableMap, "TypeVariableMap must not be null!");
|
||||
|
||||
this.type = type;
|
||||
this.resolvedType = Lazy.of(() -> resolveType(type));
|
||||
this.componentType = Lazy.of(this::doGetComponentType);
|
||||
this.valueType = Lazy.of(this::doGetMapValueType);
|
||||
this.typeVariableMap = typeVariableMap;
|
||||
this.hashCode = 17 + 31 * type.hashCode() + 31 * typeVariableMap.hashCode();
|
||||
}
|
||||
|
||||
protected TypeDiscoverer(Class<?> type, TypeInformation<?> componentType, TypeInformation<?> keyType) {
|
||||
|
||||
this.type = null;
|
||||
this.typeVariableMap = Collections.emptyMap();
|
||||
this.hashCode = 17 + 31 * type.hashCode();
|
||||
this.resolvedType = Lazy.of((Class<S>) type);
|
||||
this.componentType = componentType == null ? Lazy.empty() : Lazy.of(componentType);
|
||||
this.valueType = keyType == null ? Lazy.empty() : Lazy.of(keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type variable map.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected Map<TypeVariable<?>, Type> getTypeVariableMap() {
|
||||
return typeVariableMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link TypeInformation} for the given {@link Type}.
|
||||
*
|
||||
* @param fieldType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
protected TypeInformation<?> createInfo(Type fieldType) {
|
||||
|
||||
Assert.notNull(fieldType, "Field type must not be null!");
|
||||
|
||||
if (fieldType.equals(this.type)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (fieldType instanceof Class) {
|
||||
return ClassTypeInformation.from((Class<?>) fieldType);
|
||||
}
|
||||
|
||||
if (fieldType instanceof ParameterizedType) {
|
||||
|
||||
ParameterizedType parameterizedType = (ParameterizedType) fieldType;
|
||||
return new ParameterizedTypeInformation(parameterizedType, this);
|
||||
}
|
||||
|
||||
if (fieldType instanceof TypeVariable) {
|
||||
|
||||
TypeVariable<?> variable = (TypeVariable<?>) fieldType;
|
||||
return new TypeVariableTypeInformation(variable, this);
|
||||
}
|
||||
|
||||
if (fieldType instanceof GenericArrayType) {
|
||||
return new GenericArrayTypeInformation((GenericArrayType) fieldType, this);
|
||||
}
|
||||
|
||||
if (fieldType instanceof WildcardType) {
|
||||
|
||||
WildcardType wildcardType = (WildcardType) fieldType;
|
||||
Type[] bounds = wildcardType.getLowerBounds();
|
||||
|
||||
if (bounds.length > 0) {
|
||||
return createInfo(bounds[0]);
|
||||
}
|
||||
|
||||
bounds = wildcardType.getUpperBounds();
|
||||
|
||||
if (bounds.length > 0) {
|
||||
return createInfo(bounds[0]);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given type into a plain {@link Class}.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
protected Class<S> resolveType(Type type) {
|
||||
|
||||
Map<TypeVariable, Type> map = new HashMap<>();
|
||||
map.putAll(getTypeVariableMap());
|
||||
|
||||
return (Class<S>) GenericTypeResolver.resolveType(type, map);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getParameterTypes(java.lang.reflect.Constructor)
|
||||
*/
|
||||
public List<TypeInformation<?>> getParameterTypes(Constructor<?> constructor) {
|
||||
|
||||
Assert.notNull(constructor, "Constructor must not be null!");
|
||||
|
||||
Type[] types = constructor.getGenericParameterTypes();
|
||||
List<TypeInformation<?>> result = new ArrayList<>(types.length);
|
||||
|
||||
for (Type parameterType : types) {
|
||||
result.add(createInfo(parameterType));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getProperty(java.lang.String)
|
||||
*/
|
||||
@Nullable
|
||||
public TypeInformation<?> getProperty(String fieldname) {
|
||||
|
||||
int separatorIndex = fieldname.indexOf('.');
|
||||
|
||||
if (separatorIndex == -1) {
|
||||
return fieldTypes.computeIfAbsent(fieldname, this::getPropertyInformation).orElse(null);
|
||||
}
|
||||
|
||||
String head = fieldname.substring(0, separatorIndex);
|
||||
TypeInformation<?> info = getProperty(head);
|
||||
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return info.getProperty(fieldname.substring(separatorIndex + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} for the given atomic field. Will inspect fields first and return the type of a
|
||||
* field if available. Otherwise it will fall back to a {@link PropertyDescriptor}.
|
||||
*
|
||||
* @see #getGenericType(PropertyDescriptor)
|
||||
* @param fieldname
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
private Optional<TypeInformation<?>> getPropertyInformation(String fieldname) {
|
||||
|
||||
Class<?> rawType = getType();
|
||||
Field field = ReflectionUtils.findField(rawType, fieldname);
|
||||
|
||||
if (field != null) {
|
||||
return Optional.of(createInfo(field.getGenericType()));
|
||||
}
|
||||
|
||||
return findPropertyDescriptor(rawType, fieldname).map(it -> createInfo(getGenericType(it)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the {@link PropertyDescriptor} for the property with the given name on the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param fieldname must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
private static Optional<PropertyDescriptor> findPropertyDescriptor(Class<?> type, String fieldname) {
|
||||
|
||||
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(type, fieldname);
|
||||
|
||||
if (descriptor != null) {
|
||||
return Optional.of(descriptor);
|
||||
}
|
||||
|
||||
List<Class<?>> superTypes = new ArrayList<>();
|
||||
superTypes.addAll(Arrays.asList(type.getInterfaces()));
|
||||
superTypes.add(type.getSuperclass());
|
||||
|
||||
return Streamable.of(type.getInterfaces()).stream()//
|
||||
.flatMap(it -> Optionals.toStream(findPropertyDescriptor(it, fieldname)))//
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the generic type for the given {@link PropertyDescriptor}. Will inspect its read method followed by the
|
||||
* first parameter of the write method.
|
||||
*
|
||||
* @param descriptor must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
private static Type getGenericType(PropertyDescriptor descriptor) {
|
||||
|
||||
Method method = descriptor.getReadMethod();
|
||||
|
||||
if (method != null) {
|
||||
return method.getGenericReturnType();
|
||||
}
|
||||
|
||||
method = descriptor.getWriteMethod();
|
||||
|
||||
if (method == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type[] parameterTypes = method.getGenericParameterTypes();
|
||||
return parameterTypes.length == 0 ? null : parameterTypes[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getType()
|
||||
*/
|
||||
public Class<S> getType() {
|
||||
return resolvedType.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getRawTypeInformation()
|
||||
*/
|
||||
@Override
|
||||
public ClassTypeInformation<?> getRawTypeInformation() {
|
||||
return ClassTypeInformation.from(getType()).getRawTypeInformation();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getActualType()
|
||||
*/
|
||||
@Nullable
|
||||
public TypeInformation<?> getActualType() {
|
||||
|
||||
if (isMap()) {
|
||||
return getMapValueType();
|
||||
}
|
||||
|
||||
if (isCollectionLike()) {
|
||||
return getComponentType();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#isMap()
|
||||
*/
|
||||
public boolean isMap() {
|
||||
|
||||
Class<S> type = getType();
|
||||
|
||||
for (Class<?> mapType : MAP_TYPES) {
|
||||
if (mapType.isAssignableFrom(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getMapValueType()
|
||||
*/
|
||||
@Nullable
|
||||
public TypeInformation<?> getMapValueType() {
|
||||
return valueType.orElse(null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected TypeInformation<?> doGetMapValueType() {
|
||||
return isMap() ? getTypeArgument(getBaseType(MAP_TYPES), 1)
|
||||
: getTypeArguments().stream().skip(1).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#isCollectionLike()
|
||||
*/
|
||||
public boolean isCollectionLike() {
|
||||
|
||||
Class<?> rawType = getType();
|
||||
|
||||
return rawType.isArray() //
|
||||
|| Iterable.class.equals(rawType) //
|
||||
|| Collection.class.isAssignableFrom(rawType) //
|
||||
|| Streamable.class.isAssignableFrom(rawType);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getComponentType()
|
||||
*/
|
||||
@Nullable
|
||||
public final TypeInformation<?> getComponentType() {
|
||||
return componentType.orElse(null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected TypeInformation<?> doGetComponentType() {
|
||||
|
||||
Class<S> rawType = getType();
|
||||
|
||||
if (rawType.isArray()) {
|
||||
return createInfo(rawType.getComponentType());
|
||||
}
|
||||
|
||||
if (isMap()) {
|
||||
return getTypeArgument(getBaseType(MAP_TYPES), 0);
|
||||
}
|
||||
|
||||
if (Iterable.class.isAssignableFrom(rawType)) {
|
||||
return getTypeArgument(Iterable.class, 0);
|
||||
}
|
||||
|
||||
List<TypeInformation<?>> arguments = getTypeArguments();
|
||||
|
||||
return arguments.size() > 0 ? arguments.get(0) : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getReturnType(java.lang.reflect.Method)
|
||||
*/
|
||||
public TypeInformation<?> getReturnType(Method method) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null!");
|
||||
return createInfo(method.getGenericReturnType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getMethodParameterTypes(java.lang.reflect.Method)
|
||||
*/
|
||||
public List<TypeInformation<?>> getParameterTypes(Method method) {
|
||||
|
||||
Assert.notNull(method, "Method most not be null!");
|
||||
|
||||
return Streamable.of(method.getGenericParameterTypes()).stream()//
|
||||
.map(this::createInfo)//
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getSuperTypeInformation(java.lang.Class)
|
||||
*/
|
||||
@Nullable
|
||||
public TypeInformation<?> getSuperTypeInformation(Class<?> superType) {
|
||||
|
||||
Class<?> rawType = getType();
|
||||
|
||||
if (!superType.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (getType().equals(superType)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
List<Type> candidates = new ArrayList<>();
|
||||
Type genericSuperclass = rawType.getGenericSuperclass();
|
||||
|
||||
if (genericSuperclass != null) {
|
||||
candidates.add(genericSuperclass);
|
||||
}
|
||||
|
||||
candidates.addAll(Arrays.asList(rawType.getGenericInterfaces()));
|
||||
|
||||
for (Type candidate : candidates) {
|
||||
|
||||
TypeInformation<?> candidateInfo = createInfo(candidate);
|
||||
|
||||
if (superType.equals(candidateInfo.getType())) {
|
||||
return candidateInfo;
|
||||
} else {
|
||||
|
||||
TypeInformation<?> nestedSuperType = candidateInfo.getSuperTypeInformation(superType);
|
||||
|
||||
if (nestedSuperType != null) {
|
||||
return nestedSuperType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getTypeParameters()
|
||||
*/
|
||||
public List<TypeInformation<?>> getTypeArguments() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#isAssignableFrom(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public boolean isAssignableFrom(TypeInformation<?> target) {
|
||||
|
||||
TypeInformation<?> superTypeInformation = target.getSuperTypeInformation(getType());
|
||||
|
||||
return superTypeInformation == null ? false : superTypeInformation.equals(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#specialize(org.springframework.data.util.ClassTypeInformation)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public TypeInformation<? extends S> specialize(ClassTypeInformation<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.isTrue(getType().isAssignableFrom(type.getType()),
|
||||
() -> String.format("%s must be assignable from %s", getType(), type.getType()));
|
||||
|
||||
List<TypeInformation<?>> typeArguments = getTypeArguments();
|
||||
|
||||
return (TypeInformation<? extends S>) (typeArguments.isEmpty() //
|
||||
? type //
|
||||
: type.createInfo(new SyntheticParamterizedType(type, getTypeArguments())));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TypeInformation<?> getTypeArgument(Class<?> bound, int index) {
|
||||
|
||||
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(getType(), bound);
|
||||
|
||||
if (arguments != null) {
|
||||
return createInfo(arguments[index]);
|
||||
}
|
||||
|
||||
return getSuperTypeInformation(bound) instanceof ParameterizedTypeInformation //
|
||||
? ClassTypeInformation.OBJECT //
|
||||
: null;
|
||||
}
|
||||
|
||||
private Class<?> getBaseType(Class<?>[] candidates) {
|
||||
|
||||
Class<S> type = getType();
|
||||
|
||||
for (Class<?> candidate : candidates) {
|
||||
if (candidate.isAssignableFrom(type)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Type %s not contained in candidates %s!", type, candidates));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeDiscoverer<?> that = (TypeDiscoverer<?>) obj;
|
||||
|
||||
if (!this.type.equals(that.type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.typeVariableMap.isEmpty() && that.typeVariableMap.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.typeVariableMap.equals(that.typeVariableMap);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* A synthetic {@link ParameterizedType}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.11
|
||||
*/
|
||||
private static class SyntheticParamterizedType implements ParameterizedType {
|
||||
|
||||
private final ClassTypeInformation<?> typeInformation;
|
||||
private final List<TypeInformation<?>> typeParameters;
|
||||
|
||||
public SyntheticParamterizedType(ClassTypeInformation<?> typeInformation, List<TypeInformation<?>> typeParameters) {
|
||||
this.typeInformation = typeInformation;
|
||||
this.typeParameters = typeParameters;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.reflect.ParameterizedType#getRawType()
|
||||
*/
|
||||
@Override
|
||||
public Type getRawType() {
|
||||
return typeInformation.getType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.reflect.ParameterizedType#getOwnerType()
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Type getOwnerType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.reflect.ParameterizedType#getActualTypeArguments()
|
||||
*/
|
||||
@Override
|
||||
public Type[] getActualTypeArguments() {
|
||||
|
||||
Type[] result = new Type[typeParameters.size()];
|
||||
|
||||
for (int i = 0; i < typeParameters.size(); i++) {
|
||||
result[i] = typeParameters.get(i).getType();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.ParentTypeAwareTypeInformation#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof SyntheticParamterizedType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SyntheticParamterizedType that = (SyntheticParamterizedType) o;
|
||||
|
||||
if (!ObjectUtils.nullSafeEquals(typeInformation, that.typeInformation)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ObjectUtils.nullSafeEquals(typeParameters, that.typeParameters);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = ObjectUtils.nullSafeHashCode(typeInformation);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(typeParameters);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
@@ -21,7 +5,7 @@
|
||||
* 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
|
||||
* https://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,
|
||||
@@ -29,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
package org.springframework.data.mongodb.buildtimetypeinfo;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -55,14 +39,6 @@ public class Address {
|
||||
return street;
|
||||
}
|
||||
|
||||
// public void setCity(String city) {
|
||||
// this.city = city;
|
||||
// }
|
||||
//
|
||||
// public void setStreet(String street) {
|
||||
// this.street = street;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Address{" + "city='" + city + '\'' + ", street='" + street + '\'' + '}';
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*
|
||||
* https://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.mongodb.buildtimetypeinfo;
|
||||
|
||||
import org.springframework.data.mapping.model.DomainTypeConstructor;
|
||||
import org.springframework.data.mapping.model.DomainTypeInformation;
|
||||
import org.springframework.data.mapping.model.Field;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
*/
|
||||
public class AddressTypeInformation extends DomainTypeInformation<Address> {
|
||||
|
||||
private static final AddressTypeInformation INSTANCE = new AddressTypeInformation();
|
||||
|
||||
private AddressTypeInformation() {
|
||||
|
||||
super(Address.class);
|
||||
|
||||
// CONSTRUCTOR
|
||||
setConstructor(computePreferredConstructor());
|
||||
|
||||
// FIELDS
|
||||
addField(Field.<Address> string("city").getter(Address::getCity));
|
||||
addField(Field.<Address> string("street").getter(Address::getStreet));
|
||||
}
|
||||
|
||||
public static AddressTypeInformation instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private DomainTypeConstructor<Address> computePreferredConstructor() {
|
||||
return DomainTypeConstructor.<Address> builder().args("city", "street")
|
||||
.newInstanceFunction(args -> new Address((String) args[0], (String) args[1]));
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
@@ -21,7 +5,7 @@
|
||||
* 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
|
||||
* https://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,
|
||||
@@ -29,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
package org.springframework.data.mongodb.buildtimetypeinfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2020. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
@@ -21,7 +5,7 @@
|
||||
* 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
|
||||
* https://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,
|
||||
@@ -29,18 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
package org.springframework.data.mongodb.buildtimetypeinfo;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.model.EntityInstantiator;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.DomainTypeConstructor;
|
||||
import org.springframework.data.mapping.model.DomainTypeInformation;
|
||||
import org.springframework.data.mapping.model.Field;
|
||||
import org.springframework.data.mapping.model.ListTypeInformation;
|
||||
import org.springframework.data.mapping.model.StringTypeInformation;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.FieldType;
|
||||
|
||||
@@ -53,23 +35,18 @@ public class PersonTypeInformation extends DomainTypeInformation<Person> {
|
||||
private static final PersonTypeInformation INSTANCE = new PersonTypeInformation();
|
||||
|
||||
private PersonTypeInformation() {
|
||||
|
||||
super(Person.class);
|
||||
}
|
||||
|
||||
public static PersonTypeInformation instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
// CONSTRUCTOR
|
||||
setConstructor(computePreferredConstructor());
|
||||
|
||||
@Override
|
||||
protected void computeFields() {
|
||||
// ANNOTATIONS
|
||||
addAnnotation(computeAtDocumentAnnotation());
|
||||
|
||||
// FIELDS
|
||||
addField(
|
||||
Field.<Person> int64("id").getter(Person::getId).wither((bean, id) -> bean.withId(id)).annotation(new Id() {
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Id.class;
|
||||
}
|
||||
}));
|
||||
Field.<Person> int64("id").annotatedWithAtId().getter(Person::getId).wither((bean, id) -> bean.withId(id)));
|
||||
addField(Field.<Person> string("firstname").getter(Person::getFirstname).annotation(atFieldOnFirstname()));
|
||||
addField(Field.<Person> string("lastname").getter(Person::getLastname));
|
||||
addField(Field.<Person> int32("age").getter(Person::getAge).setter(Person::setAge));
|
||||
@@ -77,11 +54,20 @@ public class PersonTypeInformation extends DomainTypeInformation<Person> {
|
||||
.setter(Person::setAddress));
|
||||
addField(Field.<Person, List<String>> type("nicknames", new ListTypeInformation<>(StringTypeInformation.instance()))
|
||||
.getter(Person::getNicknames).setter(Person::setNicknames));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void computeAnnotations() {
|
||||
addAnnotation(new Document() {
|
||||
public static PersonTypeInformation instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private DomainTypeConstructor<Person> computePreferredConstructor() {
|
||||
return DomainTypeConstructor.<Person> builder().args("firstname", "lastname")
|
||||
.newInstanceFunction((args) -> new Person((String) args[0], (String) args[1]));
|
||||
}
|
||||
|
||||
private Document computeAtDocumentAnnotation() {
|
||||
return new Document() {
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Document.class;
|
||||
@@ -106,37 +92,10 @@ public class PersonTypeInformation extends DomainTypeInformation<Person> {
|
||||
public String collation() {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityInstantiator computeEntityInstantiator() {
|
||||
|
||||
return new EntityInstantiator() {
|
||||
|
||||
@Override
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
String firstname = (String) provider.getParameterValue(
|
||||
new Parameter("firstname", StringTypeInformation.instance(), new Annotation[] {}, entity));
|
||||
String lastname = (String) provider.getParameterValue(
|
||||
new Parameter("lastname", StringTypeInformation.instance(), new Annotation[] {}, entity));
|
||||
|
||||
T person = (T) new Person(firstname, lastname);
|
||||
System.out.println("Created new Person instance via constructor using values (" + firstname + ", " + lastname
|
||||
+ ") resulting in " + person);
|
||||
return person;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PreferredConstructor computePreferredConstructor() {
|
||||
return StaticPreferredConstructor.of("firstname", "lastname");
|
||||
}
|
||||
|
||||
Annotation atFieldOnFirstname() {
|
||||
private Annotation atFieldOnFirstname() {
|
||||
|
||||
return new org.springframework.data.mongodb.core.mapping.Field() {
|
||||
|
||||
@@ -80,12 +80,10 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.core.mapping.PersonPojoStringId;
|
||||
import org.springframework.data.mongodb.core.mapping.TextScore;
|
||||
import org.springframework.data.mongodb.core.mapping.event.AfterConvertCallback;
|
||||
import org.springframework.data.util.AddressTypeInformation;
|
||||
import org.springframework.data.mongodb.buildtimetypeinfo.AddressTypeInformation;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Person;
|
||||
import org.springframework.data.util.PersonTypeInformation;
|
||||
import org.springframework.data.mongodb.buildtimetypeinfo.PersonTypeInformation;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.StopWatch;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
@@ -2192,13 +2190,13 @@ public class MappingMongoConverterUnitTests {
|
||||
//
|
||||
// MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
// mappingContext.setInitialEntitySet(new LinkedHashSet<>(
|
||||
// Arrays.asList(org.springframework.data.util.Person.class, org.springframework.data.util.Address.class)));
|
||||
// Arrays.asList(org.springframework.data.mongodb.xxx.Person.class, org.springframework.data.mongodb.xxx.Address.class)));
|
||||
// mappingContext.initialize();
|
||||
//
|
||||
// MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext);
|
||||
//
|
||||
// org.springframework.data.util.Person source = new org.springframework.data.util.Person("spring", "data");
|
||||
// source.setAddress(new org.springframework.data.util.Address("the city", "never sleeps"));
|
||||
// org.springframework.data.mongodb.xxx.Person source = new org.springframework.data.mongodb.xxx.Person("spring", "data");
|
||||
// source.setAddress(new org.springframework.data.mongodb.xxx.Address("the city", "never sleeps"));
|
||||
// source.setAge(10);
|
||||
// source = source.withId(9876);
|
||||
// source.setNicknames(Arrays.asList("tick", "trick", "track"));
|
||||
@@ -2218,7 +2216,7 @@ public class MappingMongoConverterUnitTests {
|
||||
//
|
||||
// stopWatch.start("read");
|
||||
// for (org.bson.Document sourceDoc : sources) {
|
||||
// assertThat(converter.read(org.springframework.data.util.Person.class, sourceDoc)).isEqualTo(source);
|
||||
// assertThat(converter.read(org.springframework.data.mongodb.xxx.Person.class, sourceDoc)).isEqualTo(source);
|
||||
// }
|
||||
// stopWatch.stop();
|
||||
//
|
||||
@@ -2231,14 +2229,14 @@ public class MappingMongoConverterUnitTests {
|
||||
// ClassTypeInformation.warmCache(new PersonTypeInformation(), new AddressTypeInformation());
|
||||
//
|
||||
// MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
// mappingContext.setInitialEntitySet(new LinkedHashSet<>(Arrays.asList(org.springframework.data.util.Person.class,
|
||||
// org.springframework.data.util.Address.class)));
|
||||
// mappingContext.setInitialEntitySet(new LinkedHashSet<>(Arrays.asList(org.springframework.data.mongodb.xxx.Person.class,
|
||||
// org.springframework.data.mongodb.xxx.Address.class)));
|
||||
// mappingContext.initialize();
|
||||
//
|
||||
// MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext);
|
||||
//
|
||||
// org.springframework.data.util.Person source = new org.springframework.data.util.Person("spring", "data");
|
||||
// source.setAddress(new org.springframework.data.util.Address("the city", "never sleeps"));
|
||||
// org.springframework.data.mongodb.xxx.Person source = new org.springframework.data.mongodb.xxx.Person("spring", "data");
|
||||
// source.setAddress(new org.springframework.data.mongodb.xxx.Address("the city", "never sleeps"));
|
||||
// source.setAge(10);
|
||||
// source.setId(9876);
|
||||
// source.setNicknames(Arrays.asList("tick", "trick", "track"));
|
||||
@@ -2252,11 +2250,11 @@ public class MappingMongoConverterUnitTests {
|
||||
|
||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
mappingContext.setInitialEntitySet(new LinkedHashSet<>(
|
||||
Arrays.asList(org.springframework.data.util.Person.class, org.springframework.data.util.Address.class)));
|
||||
Arrays.asList(org.springframework.data.mongodb.buildtimetypeinfo.Person.class, org.springframework.data.mongodb.buildtimetypeinfo.Address.class)));
|
||||
mappingContext.initialize();
|
||||
|
||||
org.springframework.data.util.Person source = new org.springframework.data.util.Person("spring", "data");
|
||||
source.setAddress(new org.springframework.data.util.Address("the city", "never sleeps"));
|
||||
org.springframework.data.mongodb.buildtimetypeinfo.Person source = new org.springframework.data.mongodb.buildtimetypeinfo.Person("spring", "data");
|
||||
source.setAddress(new org.springframework.data.mongodb.buildtimetypeinfo.Address("the city", "never sleeps"));
|
||||
source.setAge(10);
|
||||
source = source.withId(9876);
|
||||
source.setNicknames(Arrays.asList("tick", "trick", "track"));
|
||||
@@ -2277,13 +2275,13 @@ public class MappingMongoConverterUnitTests {
|
||||
new org.bson.Document("city", "the city").append("street", "never sleeps"));
|
||||
assertThat(targetDocument).containsEntry("nicknames", Arrays.asList("tick", "trick", "track"));
|
||||
|
||||
org.springframework.data.util.Person targetEntity = converter.read(org.springframework.data.util.Person.class,
|
||||
org.springframework.data.mongodb.buildtimetypeinfo.Person targetEntity = converter.read(org.springframework.data.mongodb.buildtimetypeinfo.Person.class,
|
||||
targetDocument);
|
||||
System.out.println();
|
||||
System.out.println("targetEntity: " + targetEntity);
|
||||
assertThat(targetEntity).isEqualTo(source);
|
||||
|
||||
BasicMongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(org.springframework.data.util.Person.class);
|
||||
BasicMongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(org.springframework.data.mongodb.buildtimetypeinfo.Person.class);
|
||||
assertThat(entity.getCollection()).isEqualTo("star-wars");
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,11 @@ import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.util.AddressTypeInformation;
|
||||
import org.springframework.data.mongodb.buildtimetypeinfo.Address;
|
||||
import org.springframework.data.mongodb.buildtimetypeinfo.AddressTypeInformation;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Person;
|
||||
import org.springframework.data.util.PersonTypeInformation;
|
||||
import org.springframework.data.mongodb.buildtimetypeinfo.Person;
|
||||
import org.springframework.data.mongodb.buildtimetypeinfo.PersonTypeInformation;
|
||||
|
||||
import com.mongodb.client.MongoClients;
|
||||
|
||||
@@ -76,7 +77,7 @@ public class StaticMetadataTests {
|
||||
|
||||
mappingContext = new MongoMappingContext();
|
||||
mappingContext.setInitialEntitySet(new LinkedHashSet<>(
|
||||
Arrays.asList(org.springframework.data.util.Person.class, org.springframework.data.util.Address.class)));
|
||||
Arrays.asList(Person.class, Address.class)));
|
||||
mappingContext.initialize();
|
||||
|
||||
mongoConverter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext);
|
||||
@@ -85,7 +86,7 @@ public class StaticMetadataTests {
|
||||
template = new MongoTemplate(new SimpleMongoClientDatabaseFactory(MongoClients.create(), "sem"), mongoConverter);
|
||||
|
||||
luke = new Person("luke", "skywalker");
|
||||
luke.setAddress(new org.springframework.data.util.Address("Mos Eisley", "WB154"));
|
||||
luke.setAddress(new Address("Mos Eisley", "WB154"));
|
||||
luke.setAge(22);
|
||||
luke = luke.withId(9876);
|
||||
luke.setNicknames(Arrays.asList("jedi", "wormie"));
|
||||
|
||||
Reference in New Issue
Block a user