Hacking - Explore Entity Metadata DSL
This commit is contained in:
@@ -19,6 +19,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.bson.UuidRepresentation;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -34,7 +35,10 @@ import org.springframework.data.mongodb.MongoManagedTypes;
|
||||
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
|
||||
import org.springframework.data.mongodb.core.convert.MongoCustomConversions.MongoConverterConfigurationAdapter;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MappingConfig;
|
||||
import org.springframework.data.mongodb.core.mapping.MappingConfig.MappingRuleCustomizer;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -87,10 +91,16 @@ public abstract class MongoConfigurationSupport {
|
||||
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
|
||||
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
|
||||
mappingContext.setAutoIndexCreation(autoIndexCreation());
|
||||
mappingContext.setMappingConfig(mappingConfig());
|
||||
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MappingConfig mappingConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return new instance of {@link MongoManagedTypes}.
|
||||
* @throws ClassNotFoundException
|
||||
|
||||
@@ -487,7 +487,22 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
&& instanceCreatorMetadata.hasParameters() ? getParameterProvider(context, entity, documentAccessor, evaluator)
|
||||
: NoOpParameterValueProvider.INSTANCE;
|
||||
|
||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
||||
EntityInstantiator instantiator = entity.getInstanceCreator();
|
||||
if(instantiator != null) {
|
||||
provider = new ParameterValueProvider() {
|
||||
@Nullable
|
||||
public Object getParameterValue(Parameter parameter) {
|
||||
String name = parameter.getName();
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException(String.format("Parameter %s does not have a name", parameter));
|
||||
} else {
|
||||
return documentAccessor.get(entity.getRequiredPersistentProperty(name));
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
instantiator = instantiators.getInstantiatorFor(entity);
|
||||
}
|
||||
S instance = instantiator.createInstance(entity, provider);
|
||||
|
||||
if (entity.requiresPropertyPopulation()) {
|
||||
|
||||
@@ -31,7 +31,9 @@ import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.mapping.model.EntityInstantiator;
|
||||
import org.springframework.data.mongodb.MongoCollectionUtils;
|
||||
import org.springframework.data.mongodb.core.mapping.MappingConfig.EntityConfig;
|
||||
import org.springframework.data.mongodb.util.encryption.EncryptionUtils;
|
||||
import org.springframework.data.spel.ExpressionDependencies;
|
||||
import org.springframework.data.util.Lazy;
|
||||
@@ -72,6 +74,11 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
private final @Nullable Expression collationExpression;
|
||||
|
||||
private final ShardKey shardKey;
|
||||
private EntityConfig entityConfig;
|
||||
|
||||
public BasicMongoPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
this(typeInformation, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicMongoPersistentEntity} with the given {@link TypeInformation}. Will default the
|
||||
@@ -79,12 +86,18 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
*
|
||||
* @param typeInformation must not be {@literal null}.
|
||||
*/
|
||||
public BasicMongoPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
public BasicMongoPersistentEntity(TypeInformation<T> typeInformation, EntityConfig<T> config) {
|
||||
|
||||
super(typeInformation, MongoPersistentPropertyComparator.INSTANCE);
|
||||
|
||||
this.entityConfig = config;
|
||||
|
||||
Class<?> rawType = typeInformation.getType();
|
||||
String fallback = MongoCollectionUtils.getPreferredCollectionName(rawType);
|
||||
if (config != null) {
|
||||
fallback = config.collectionNameOrDefault(() -> MongoCollectionUtils.getPreferredCollectionName(rawType));
|
||||
|
||||
}
|
||||
|
||||
if (this.isAnnotationPresent(Document.class)) {
|
||||
Document document = this.getRequiredAnnotation(Document.class);
|
||||
@@ -249,6 +262,12 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
|
||||
Assert.notNull(property, "MongoPersistentProperty must not be null");
|
||||
|
||||
if (entityConfig != null) {
|
||||
if (entityConfig.isIdProperty(property)) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
if (!property.isIdProperty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -340,6 +359,11 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityInstantiator getInstanceCreator() {
|
||||
return this.entityConfig != null ? this.entityConfig.getInstantiator() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> getEncryptionKeyIds() {
|
||||
|
||||
@@ -398,9 +422,9 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
|
||||
if (persistentProperty.isDbReference() && persistentProperty.getDBRef().lazy()) {
|
||||
if (persistentProperty.isArray() || Modifier.isFinal(persistentProperty.getActualType().getModifiers())) {
|
||||
throw new MappingException(String.format(
|
||||
"Invalid lazy DBRef property for %s; Found %s which must not be an array nor a final class",
|
||||
persistentProperty.getField(), persistentProperty.getActualType()));
|
||||
throw new MappingException(
|
||||
String.format("Invalid lazy DBRef property for %s; Found %s which must not be an array nor a final class",
|
||||
persistentProperty.getField(), persistentProperty.getActualType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.mongodb.core.mapping.MappingConfig.PropertyConfig;
|
||||
import org.springframework.data.mongodb.util.encryption.EncryptionUtils;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
@@ -73,6 +74,12 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
||||
}
|
||||
|
||||
private final FieldNamingStrategy fieldNamingStrategy;
|
||||
PropertyConfig<?, ?> propertyConfig;
|
||||
|
||||
public BasicMongoPersistentProperty(Property property, MongoPersistentEntity<?> owner,
|
||||
SimpleTypeHolder simpleTypeHolder, @Nullable FieldNamingStrategy fieldNamingStrategy) {
|
||||
this(property, owner, simpleTypeHolder, fieldNamingStrategy, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicMongoPersistentProperty}.
|
||||
@@ -83,11 +90,12 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
||||
* @param fieldNamingStrategy can be {@literal null}.
|
||||
*/
|
||||
public BasicMongoPersistentProperty(Property property, MongoPersistentEntity<?> owner,
|
||||
SimpleTypeHolder simpleTypeHolder, @Nullable FieldNamingStrategy fieldNamingStrategy) {
|
||||
SimpleTypeHolder simpleTypeHolder, @Nullable FieldNamingStrategy fieldNamingStrategy, @Nullable PropertyConfig<?,?> propertyConfig) {
|
||||
|
||||
super(property, owner, simpleTypeHolder);
|
||||
this.fieldNamingStrategy = fieldNamingStrategy == null ? PropertyNameFieldNamingStrategy.INSTANCE
|
||||
: fieldNamingStrategy;
|
||||
this.propertyConfig = propertyConfig;
|
||||
|
||||
if (isIdProperty() && hasExplicitFieldName()) {
|
||||
|
||||
@@ -115,6 +123,10 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
||||
return true;
|
||||
}
|
||||
|
||||
if(propertyConfig != null && propertyConfig.isId()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We need to support a wider range of ID types than just the ones that can be converted to an ObjectId
|
||||
// but still we need to check if there happens to be an explicit name set
|
||||
return SUPPORTED_ID_PROPERTY_NAMES.contains(getName()) && !hasExplicitFieldName();
|
||||
@@ -132,6 +144,10 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
||||
*/
|
||||
public String getFieldName() {
|
||||
|
||||
if(propertyConfig != null && StringUtils.hasText(propertyConfig.getTargetName())) {
|
||||
return propertyConfig.getTargetName();
|
||||
}
|
||||
|
||||
if (isIdProperty()) {
|
||||
|
||||
if (getOwner().getIdProperty() == null) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core.mapping;
|
||||
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.mongodb.core.mapping.MappingConfig.PropertyConfig;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
@@ -47,8 +48,8 @@ public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty
|
||||
* @param fieldNamingStrategy can be {@literal null}.
|
||||
*/
|
||||
public CachingMongoPersistentProperty(Property property, MongoPersistentEntity<?> owner,
|
||||
SimpleTypeHolder simpleTypeHolder, @Nullable FieldNamingStrategy fieldNamingStrategy) {
|
||||
super(property, owner, simpleTypeHolder, fieldNamingStrategy);
|
||||
SimpleTypeHolder simpleTypeHolder, @Nullable FieldNamingStrategy fieldNamingStrategy, PropertyConfig config) {
|
||||
super(property, owner, simpleTypeHolder, fieldNamingStrategy, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright 2023 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.core.mapping;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.data.mapping.Parameter;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.SimplePropertyHandler;
|
||||
import org.springframework.data.mapping.model.EntityInstantiator;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.MethodInvocationRecorder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2023/06
|
||||
*/
|
||||
public class MappingConfig {
|
||||
|
||||
private final Map<Class, EntityConfig<?>> entityConfigMap;
|
||||
|
||||
MappingConfig(Map<Class, EntityConfig<?>> entityConfigMap) {
|
||||
this.entityConfigMap = entityConfigMap;
|
||||
}
|
||||
|
||||
public static MappingConfig none() {
|
||||
return new MappingConfig(Collections.emptyMap());
|
||||
}
|
||||
|
||||
public static MappingConfig mappingRules(Consumer<MappingRuleCustomizer> customizer) {
|
||||
MappingConfig mappingConfig = new MappingConfig(new HashMap<>());
|
||||
customizer.accept(new MappingRuleCustomizer() {
|
||||
@Override
|
||||
public <T> MappingRuleCustomizer add(Class<T> type, Consumer<EntityConfig<T>> cfg) {
|
||||
|
||||
EntityConfig<T> entityConfig = (EntityConfig<T>) mappingConfig.entityConfigMap.computeIfAbsent(type,
|
||||
(it) -> EntityConfig.configure(it));
|
||||
cfg.accept(entityConfig);
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return mappingConfig;
|
||||
}
|
||||
|
||||
public interface MappingRuleCustomizer {
|
||||
<T> MappingRuleCustomizer add(Class<T> type, Consumer<EntityConfig<T>> cfg);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> EntityConfig<T> getEntityConfig(Class<T> type) {
|
||||
return (EntityConfig<T>) entityConfigMap.get(type);
|
||||
}
|
||||
|
||||
public static class EntityConfig<T> {
|
||||
|
||||
private final Class<T> type;
|
||||
|
||||
@Nullable private Supplier<String> collectionName;
|
||||
Map<String, PropertyConfig<T, ?>> propertyConfigMap = new HashMap<>();
|
||||
EntityInstantiator instantiator;
|
||||
|
||||
public EntityConfig(Class<T> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static <T, P> EntityConfig<T> configure(Class<T> type) {
|
||||
return new EntityConfig<>(type);
|
||||
}
|
||||
|
||||
public <P> EntityConfig<T> define(String name, Consumer<PropertyConfig<T, P>> cfg) {
|
||||
|
||||
PropertyConfig<T, P> config = (PropertyConfig<T, P>) propertyConfigMap.computeIfAbsent(name,
|
||||
(key) -> new PropertyConfig<>(this.type, key));
|
||||
cfg.accept(config);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <P> EntityConfig<T> define(Function<T, P> property, Consumer<PropertyConfig<T, P>> cfg) {
|
||||
|
||||
String propertyName = MethodInvocationRecorder.forProxyOf(type).record(property).getPropertyPath()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Cannot obtain property name"));
|
||||
|
||||
return define(propertyName, cfg);
|
||||
}
|
||||
|
||||
public EntityConfig<T> namespace(String name) {
|
||||
return namespace(() -> name);
|
||||
}
|
||||
|
||||
public EntityConfig<T> namespace(Supplier<String> name) {
|
||||
this.collectionName = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean isIdProperty(PersistentProperty<?> property) {
|
||||
PropertyConfig<T, ?> propertyConfig = propertyConfigMap.get(property.getName());
|
||||
if (propertyConfig == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return propertyConfig.isId();
|
||||
}
|
||||
|
||||
String collectionNameOrDefault(Supplier<String> fallback) {
|
||||
return collectionName != null ? collectionName.get() : fallback.get();
|
||||
}
|
||||
|
||||
public EntityInstantiator getInstantiator() {
|
||||
return instantiator;
|
||||
}
|
||||
|
||||
public EntityConfig<T> entityCreator(Function<Arguments<T>, T> createFunction) {
|
||||
|
||||
instantiator = new EntityInstantiator() {
|
||||
|
||||
@Override
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(
|
||||
E entity, ParameterValueProvider<P> provider) {
|
||||
Map<String, Object> targetMap = new HashMap<>();
|
||||
|
||||
|
||||
PropertyValueProvider pvv = provider instanceof PropertyValueProvider pvp ? pvp : new PropertyValueProvider<P>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T getPropertyValue(P property) {
|
||||
Parameter parameter = new Parameter<>(property.getName(), (TypeInformation) property.getTypeInformation(),
|
||||
new Annotation[] {}, null);
|
||||
return (T) provider.getParameterValue(parameter);
|
||||
}
|
||||
};
|
||||
|
||||
entity.doWithProperties((SimplePropertyHandler) property -> {
|
||||
targetMap.put(property.getName(), pvv.getPropertyValue(property));
|
||||
});
|
||||
|
||||
return (T) createFunction.apply(new Arguments() {
|
||||
|
||||
private Map<Function, String> resolvedName = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Object get(String arg) {
|
||||
return targetMap.get(arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getType() {
|
||||
return entity.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Function property) {
|
||||
|
||||
String name = resolvedName.computeIfAbsent(property, key -> (String) MethodInvocationRecorder.forProxyOf(getType()).record(property).getPropertyPath().orElse(""));
|
||||
return get(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
public interface Arguments<T> {
|
||||
|
||||
<V> V get(String arg);
|
||||
|
||||
default <V> V get(Function<T, V> property) {
|
||||
String propertyName = MethodInvocationRecorder.forProxyOf(getType()).record(property).getPropertyPath()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Cannot obtain property name"));
|
||||
|
||||
return get(propertyName);
|
||||
}
|
||||
|
||||
Class<T> getType();
|
||||
}
|
||||
}
|
||||
|
||||
public static class PropertyConfig<T, P> {
|
||||
|
||||
private final Class<T> owingType;
|
||||
private final String propertyName;
|
||||
private String fieldName;
|
||||
private boolean isId;
|
||||
private boolean isTransient;
|
||||
|
||||
public PropertyConfig(Class<T> owingType, String propertyName) {
|
||||
this.owingType = owingType;
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
public PropertyConfig<T, P> useAsId() {
|
||||
this.isId = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isId() {
|
||||
return isId;
|
||||
}
|
||||
|
||||
public PropertyConfig<T, P> setTransient() {
|
||||
this.isTransient = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PropertyConfig<T, P> mappedName(String fieldName) {
|
||||
this.fieldName = fieldName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTargetName() {
|
||||
return this.fieldName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mongodb.core.mapping;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -26,6 +27,7 @@ import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.mongodb.core.mapping.MappingConfig.MappingRuleCustomizer;
|
||||
import org.springframework.data.util.NullableWrapperConverters;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -45,6 +47,7 @@ public class MongoMappingContext extends AbstractMappingContext<MongoPersistentE
|
||||
|
||||
private FieldNamingStrategy fieldNamingStrategy = DEFAULT_NAMING_STRATEGY;
|
||||
private boolean autoIndexCreation = false;
|
||||
private MappingConfig mappingConfig;
|
||||
|
||||
@Nullable
|
||||
private ApplicationContext applicationContext;
|
||||
@@ -67,6 +70,14 @@ public class MongoMappingContext extends AbstractMappingContext<MongoPersistentE
|
||||
this.fieldNamingStrategy = fieldNamingStrategy == null ? DEFAULT_NAMING_STRATEGY : fieldNamingStrategy;
|
||||
}
|
||||
|
||||
public void setMappingConfig(MappingConfig mappingConfig) {
|
||||
this.mappingConfig = mappingConfig;
|
||||
}
|
||||
|
||||
public void mappingRules(Consumer<MappingRuleCustomizer> customizer) {
|
||||
setMappingConfig(MappingConfig.mappingRules(customizer));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
|
||||
|
||||
@@ -80,12 +91,12 @@ public class MongoMappingContext extends AbstractMappingContext<MongoPersistentE
|
||||
@Override
|
||||
public MongoPersistentProperty createPersistentProperty(Property property, MongoPersistentEntity<?> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
return new CachingMongoPersistentProperty(property, owner, simpleTypeHolder, fieldNamingStrategy);
|
||||
return new CachingMongoPersistentProperty(property, owner, simpleTypeHolder, fieldNamingStrategy, mappingConfig != null ? mappingConfig.getEntityConfig(owner.getType()).propertyConfigMap.get(property.getName()) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> BasicMongoPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
return new BasicMongoPersistentEntity<>(typeInformation);
|
||||
return new BasicMongoPersistentEntity<>(typeInformation, mappingConfig != null ? mappingConfig.getEntityConfig(typeInformation.getType()) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core.mapping;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.model.EntityInstantiator;
|
||||
import org.springframework.data.mapping.model.MutablePersistentEntity;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -111,4 +112,8 @@ public interface MongoPersistentEntity<T> extends MutablePersistentEntity<T, Mon
|
||||
*/
|
||||
@Nullable
|
||||
Collection<Object> getEncryptionKeyIds();
|
||||
|
||||
default EntityInstantiator getInstanceCreator() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2023 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.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.mongodb.core.mapping.MappingConfig.*;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
|
||||
import com.mongodb.client.MongoClients;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2023/06
|
||||
*/
|
||||
public class MongoTemplateMappingConfigTests {
|
||||
|
||||
@Test
|
||||
void testProgrammaticMetadata() {
|
||||
|
||||
SimpleMongoClientDatabaseFactory dbFactory = new SimpleMongoClientDatabaseFactory(MongoClients.create(),
|
||||
"test-manual-config");
|
||||
|
||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
mappingContext.mappingRules(rules -> {
|
||||
rules.add(Sample.class, cfg -> {
|
||||
cfg.namespace("my-sample");
|
||||
cfg.entityCreator(args -> {
|
||||
return new Sample(args.get(Sample::getName));
|
||||
});
|
||||
cfg.define(Sample::getName, PropertyConfig::useAsId);
|
||||
cfg.define(Sample::getValue, property -> property.mappedName("va-l-ue"));
|
||||
});
|
||||
});
|
||||
mappingContext.afterPropertiesSet();
|
||||
|
||||
MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(dbFactory, mappingContext);
|
||||
mappingMongoConverter.afterPropertiesSet();
|
||||
|
||||
MongoTemplate template = new MongoTemplate(dbFactory, mappingMongoConverter);
|
||||
template.dropCollection(Sample.class);
|
||||
|
||||
Sample sample = new Sample("s1");
|
||||
sample.value = "val";
|
||||
template.save(sample);
|
||||
|
||||
Document dbValue = template.execute("my-sample", collection -> {
|
||||
return collection.find(new Document()).first();
|
||||
});
|
||||
|
||||
System.out.println("dbValue: " + dbValue);
|
||||
assertThat(dbValue).containsEntry("_id", sample.name).containsEntry("va-l-ue", sample.value);
|
||||
|
||||
List<Sample> entries = template.find(Query.query(Criteria.where("name").is(sample.name)), Sample.class);
|
||||
entries.forEach(System.out::println);
|
||||
|
||||
assertThat(entries).containsExactly(sample);
|
||||
}
|
||||
|
||||
@Data
|
||||
@org.springframework.data.mongodb.core.mapping.Document(collection = "my-sample")
|
||||
static class Sample {
|
||||
|
||||
Sample(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Id final String name;
|
||||
|
||||
@Field(name = "va-l-ue") String value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.mapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.mongodb.core.mapping.MappingConfig.EntityConfig.*;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -26,18 +27,21 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mongodb.core.mapping.MappingConfig.EntityConfig;
|
||||
import org.springframework.data.mongodb.core.mapping.MappingConfig.PropertyConfig;
|
||||
import org.springframework.data.mongodb.core.query.Collation;
|
||||
import org.springframework.data.spel.ExtensionAwareEvaluationContextProvider;
|
||||
import org.springframework.data.spel.spi.EvaluationContextExtension;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link BasicMongoPersistentEntity}.
|
||||
@@ -301,6 +305,31 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
return new BasicMongoPersistentEntity<>(ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
@Data
|
||||
class Sample {
|
||||
|
||||
String name;
|
||||
String value;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProgrammaticMetadata() {
|
||||
|
||||
doReturn("value").when(propertyMock).getName();
|
||||
|
||||
EntityConfig<Sample> entityConfig = configure(Sample.class) //
|
||||
.namespace("my-collection") //
|
||||
.define(Sample::getValue, PropertyConfig::useAsId)
|
||||
.define(Sample::getName, property -> property.mappedName("n-a-m-e"));
|
||||
|
||||
BasicMongoPersistentEntity<Sample> entity = new BasicMongoPersistentEntity<>(TypeInformation.of(Sample.class), entityConfig);
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
|
||||
MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||
assertThat(idProperty).isSameAs(propertyMock);
|
||||
assertThat(entity.getCollection()).isEqualTo("my-collection");
|
||||
}
|
||||
|
||||
@Document("contacts")
|
||||
class Contact {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user