Browse Source

extract some interfaces

labs/build-time-domain-type-information
Christoph Strobl 5 years ago
parent
commit
326a10f1bb
  1. 1
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/PreferredConstructor.java
  2. 34
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/PreferredConstructorProvider.java
  3. 22
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java
  4. 54
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/AccessorFunctionProvider.java
  5. 22
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java
  6. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/EntityInstantiators.java
  7. 50
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/EntiyInstantiatorProvider.java
  8. 35
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/PersistentPropertyAccessorFactoryProvider.java
  9. 38
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/StaticPropertyAccessorFactory.java
  10. 44
      spring-data-mongodb/src/main/java/org/springframework/data/util/AddressTypeInformation.java
  11. 32
      spring-data-mongodb/src/main/java/org/springframework/data/util/AnnotationProvider.java
  12. 5
      spring-data-mongodb/src/main/java/org/springframework/data/util/ClassTypeInformation.java
  13. 179
      spring-data-mongodb/src/main/java/org/springframework/data/util/Field.java
  14. 76
      spring-data-mongodb/src/main/java/org/springframework/data/util/Fields.java
  15. 10
      spring-data-mongodb/src/main/java/org/springframework/data/util/ListTypeInformation.java
  16. 15
      spring-data-mongodb/src/main/java/org/springframework/data/util/Person.java
  17. 123
      spring-data-mongodb/src/main/java/org/springframework/data/util/PersonTypeInformation.java
  18. 159
      spring-data-mongodb/src/main/java/org/springframework/data/util/StaticTypeInformation.java
  19. 5
      spring-data-mongodb/src/main/java/org/springframework/data/util/StringTypeInformation.java
  20. 104
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java
  21. 109
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/staticmetadata/StaticMetadataTests.java

1
spring-data-mongodb/src/main/java/org/springframework/data/mapping/PreferredConstructor.java

@ -52,7 +52,6 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> { @@ -52,7 +52,6 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
public PreferredConstructor() {
this.constructor = null;
this.parameters = Collections.emptyList();
}
/**

34
spring-data-mongodb/src/main/java/org/springframework/data/mapping/PreferredConstructorProvider.java

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
/*
* 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;
}
}

22
spring-data-mongodb/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java

@ -16,16 +16,13 @@ @@ -16,16 +16,13 @@
package org.springframework.data.mapping.context;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
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.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.locks.Lock;
@ -379,18 +376,17 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<? @@ -379,18 +376,17 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
if (typeInformation instanceof StaticTypeInformation<?>) {
// ((StaticTypeInformation<?>)typeInformation).doWithProperties()
final E pEntity = entity;
((StaticTypeInformation<?>) typeInformation).doWithFields((fieldName, field) -> {
Map<String, TypeInformation<?>> properties = ((StaticTypeInformation<?>) typeInformation).getProperties();
Map<String, List<Annotation>> annotations = ((StaticTypeInformation<?>) typeInformation).getPropertyAnnotations();
for (Entry<String, TypeInformation<?>> entry : properties.entrySet()) {
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);
P target = createPersistentProperty(Property.of(entry.getValue(), entry.getKey(), annotations.get(entry.getKey())), entity, simpleTypeHolder);
entity.addPersistentProperty(target);
}
entity.setPersistentPropertyAccessorFactory(new StaticPropertyAccessorFactory());
return Optional.of(entity);
});
pEntity.setPersistentPropertyAccessorFactory(StaticPropertyAccessorFactory.instance());
return Optional.of(pEntity);
}
PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(type);

54
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/AccessorFunctionProvider.java

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
/*
* 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 AccessorFunctionProvider<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);
}

22
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java

@ -37,8 +37,8 @@ import org.springframework.data.mapping.*; @@ -37,8 +37,8 @@ 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.AnnotationProvider;
import org.springframework.data.util.Lazy;
import org.springframework.data.util.StaticTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.EvaluationContext;
import org.springframework.lang.Nullable;
@ -109,14 +109,30 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -109,14 +109,30 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
this.properties = new ArrayList<>();
this.persistentPropertiesCache = new ArrayList<>();
this.comparator = comparator;
this.constructor = information instanceof StaticTypeInformation ? ((StaticTypeInformation)information).getPreferredConstructor() : PreferredConstructorDiscoverer.discover(this);
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 AnnotationProvider) {
for(Annotation annotation : ((AnnotationProvider)information).getAnnotations()) {
annotationCache.put(annotation.annotationType(), Optional.of(annotation));
}
}
this.propertyAnnotationCache = CollectionUtils
.toMultiValueMap(new ConcurrentReferenceHashMap<>(16, ReferenceType.WEAK));
this.propertyAccessorFactory = BeanWrapperPropertyAccessorFactory.INSTANCE;
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

6
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/EntityInstantiators.java

@ -19,7 +19,6 @@ import java.util.Collections; @@ -19,7 +19,6 @@ import java.util.Collections;
import java.util.Map;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.util.StaticTypeInformation;
import org.springframework.util.Assert;
/**
@ -92,9 +91,8 @@ public class EntityInstantiators { @@ -92,9 +91,8 @@ public class EntityInstantiators {
if (!customInstantiators.containsKey(type)) {
if(entity.getTypeInformation() instanceof StaticTypeInformation) {
EntityInstantiator instantiator = ((StaticTypeInformation)entity.getTypeInformation()).getInstantiator();
return instantiator != null ? instantiator : fallback;
if (entity.getTypeInformation() instanceof EntiyInstantiatorProvider) {
return ((EntiyInstantiatorProvider) entity.getTypeInformation()).getEntiyInstantiatorOrDefault(fallback);
}
return fallback;
}

50
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/EntiyInstantiatorProvider.java

@ -0,0 +1,50 @@ @@ -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
*
* 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 EntiyInstantiatorProvider {
@Nullable
EntityInstantiator getEntityInstantiator();
default EntityInstantiator getEntiyInstantiatorOrDefault(EntityInstantiator fallback) {
EntityInstantiator entityInstantiator = getEntityInstantiator();
return entityInstantiator != null ? entityInstantiator : fallback;
}
}

35
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/PersistentPropertyAccessorFactoryProvider.java

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
/*
* 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;
}
}

38
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/StaticPropertyAccessorFactory.java

@ -31,13 +31,9 @@ @@ -31,13 +31,9 @@
*/
package org.springframework.data.mapping.model;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.util.StaticTypeInformation;
import org.springframework.lang.Nullable;
/**
@ -46,13 +42,21 @@ import org.springframework.lang.Nullable; @@ -46,13 +42,21 @@ import org.springframework.lang.Nullable;
*/
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) {
return new StaticPropertyAccessor<>((StaticTypeInformation<T>) entity.getTypeInformation(), bean);
System.out.println("Obtaining static property acessor for entity " + entity.getName());
return new StaticPropertyAccessor<>((AccessorFunctionProvider<T>) entity.getTypeInformation(), bean);
}
/*
@ -62,7 +66,7 @@ public class StaticPropertyAccessorFactory implements PersistentPropertyAccessor @@ -62,7 +66,7 @@ public class StaticPropertyAccessorFactory implements PersistentPropertyAccessor
@Override
public boolean isSupported(PersistentEntity<?, ?> entity) {
boolean isStaticTypedEntity = entity.getTypeInformation() instanceof StaticTypeInformation;
boolean isStaticTypedEntity = entity.getTypeInformation() instanceof AccessorFunctionProvider;
System.out.println(entity.getName() + " isStaticTypedEntity: " + isStaticTypedEntity);
return isStaticTypedEntity;
}
@ -70,32 +74,36 @@ public class StaticPropertyAccessorFactory implements PersistentPropertyAccessor @@ -70,32 +74,36 @@ public class StaticPropertyAccessorFactory implements PersistentPropertyAccessor
static class StaticPropertyAccessor<T> implements PersistentPropertyAccessor<T> {
T bean;
StaticTypeInformation<T> typeInformation;
AccessorFunctionProvider<T> accessorFunctionProvider;
public StaticPropertyAccessor(StaticTypeInformation<T> typeInformation, T bean) {
public StaticPropertyAccessor(AccessorFunctionProvider<T> accessorFunctionProvider, T bean) {
this.bean = bean;
this.typeInformation = typeInformation;
this.accessorFunctionProvider = accessorFunctionProvider;
}
@Override
public void setProperty(PersistentProperty<?> property, @Nullable Object value) {
BiFunction<T, Object, T> setFunction = typeInformation.getSetter().get(property.getName());
if (setFunction == null) {
if (!accessorFunctionProvider.hasSetFunctionFor(property.getName())) {
return;
}
this.bean = setFunction.apply(bean, value);
this.bean = accessorFunctionProvider.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) {
Function<T, Object> getFunction = typeInformation.getGetter().get(property.getName());
if (getFunction == null) {
if (!accessorFunctionProvider.hasGetFunctionFor(property.getName())) {
return null;
}
return getFunction.apply(bean);
Object value = accessorFunctionProvider.getGetFunctionFor(property.getName()).apply(bean);
System.out.println("obtaining value " + value + " from getter function for " + property.getName());
return value;
}
@Override

44
spring-data-mongodb/src/main/java/org/springframework/data/util/AddressTypeInformation.java

@ -32,10 +32,6 @@ @@ -32,10 +32,6 @@
package org.springframework.data.util;
import java.lang.annotation.Annotation;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
@ -50,40 +46,21 @@ import org.springframework.data.mapping.model.ParameterValueProvider; @@ -50,40 +46,21 @@ import org.springframework.data.mapping.model.ParameterValueProvider;
*/
public class AddressTypeInformation extends StaticTypeInformation<Address> {
public AddressTypeInformation() {
private static final AddressTypeInformation INSTANCE = new AddressTypeInformation();
private AddressTypeInformation() {
super(Address.class);
}
@Override
protected Map<String, TypeInformation<?>> computePropertiesMap() {
Map<String, TypeInformation<?>> properties = new LinkedHashMap<>();
properties.put("city", new StringTypeInformation());
properties.put("street", new StringTypeInformation());
return properties;
public static AddressTypeInformation instance() {
return INSTANCE;
}
@Override
protected Map<String, Function<Address, Object>> computeGetter() {
Map<String, Function<Address, Object>> getters = new LinkedHashMap<>();
getters.put("city", Address::getCity);
getters.put("street", Address::getStreet);
protected void computeFields() {
return getters;
}
@Override
protected Map<String, BiFunction<Address, Object, Address>> computeSetter() {
Map<String, BiFunction<Address, Object, Address>> setter = new LinkedHashMap<>();
// setter.put("city", (bean, id) -> {
// bean.setCity((String) id);
// return bean;
// });
// setter.put("street", (bean, id) -> {
// bean.setStreet((String) id);
// return bean;
// });
return setter;
addField(Field.<Address> string("city").getter(Address::getCity));
addField(Field.<Address> string("street").getter(Address::getStreet));
}
@Override
@ -99,7 +76,10 @@ public class AddressTypeInformation extends StaticTypeInformation<Address> { @@ -99,7 +76,10 @@ public class AddressTypeInformation extends StaticTypeInformation<Address> {
String street = (String) provider
.getParameterValue(new Parameter("street", new StringTypeInformation(), new Annotation[] {}, entity));
return (T) new Address(city, street);
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;
}
};
}

32
spring-data-mongodb/src/main/java/org/springframework/data/util/AnnotationProvider.java

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
/*
* 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 AnnotationProvider {
List<Annotation> getAnnotations();
boolean hasAnnotation(Class<?> annotationType);
<T extends Annotation> List<T> findAnnotation(Class<T> annotation);
}

5
spring-data-mongodb/src/main/java/org/springframework/data/util/ClassTypeInformation.java

@ -27,6 +27,7 @@ import java.util.List; @@ -27,6 +27,7 @@ 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;
@ -48,8 +49,8 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> { @@ -48,8 +49,8 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
public static final ClassTypeInformation<Map> MAP = new ClassTypeInformation(Map.class);
public static final ClassTypeInformation<Object> OBJECT = new ClassTypeInformation(Object.class);
private static final Map<Class<?>, ClassTypeInformation<?>> cache = new ConcurrentReferenceHashMap<>(64,
ReferenceType.WEAK);
// 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));

179
spring-data-mongodb/src/main/java/org/springframework/data/util/Field.java

@ -0,0 +1,179 @@ @@ -0,0 +1,179 @@
/*
* 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 AnnotationProvider {
@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, StaticTypeInformation.from(Long.class));
}
public static <S> Field<Integer, S> int32(String propertyName) {
return new Field<>(propertyName, StaticTypeInformation.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());
}
}

76
spring-data-mongodb/src/main/java/org/springframework/data/util/Fields.java

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
/*
* 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();
}
}

10
spring-data-mongodb/src/main/java/org/springframework/data/util/ListTypeInformation.java

@ -37,10 +37,14 @@ import java.util.List; @@ -37,10 +37,14 @@ import java.util.List;
* @author Christoph Strobl
* @since 2020/10
*/
public class ListTypeInformation extends StaticTypeInformation<List> {
public class ListTypeInformation<S> extends StaticTypeInformation<List<S>> {
public ListTypeInformation(TypeInformation<?> componentType) {
super(List.class, componentType, null);
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

15
spring-data-mongodb/src/main/java/org/springframework/data/util/Person.java

@ -52,6 +52,15 @@ public class Person { @@ -52,6 +52,15 @@ public class Person {
this.lastname = lastname;
}
private Person(long id, String firstname, String lastname, int age, Address address, List<String> nicknames) {
this.id = id;
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
this.address = address;
this.nicknames = nicknames;
}
public String getFirstname() {
return firstname;
}
@ -72,8 +81,10 @@ public class Person { @@ -72,8 +81,10 @@ public class Person {
return id;
}
public void setId(long id) {
id = id;
public Person withId(long id) {
return new Person(id, firstname, lastname, age, address, nicknames);
}
public Address getAddress() {

123
spring-data-mongodb/src/main/java/org/springframework/data/util/PersonTypeInformation.java

@ -32,20 +32,16 @@ @@ -32,20 +32,16 @@
package org.springframework.data.util;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
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.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.FieldType;
/**
@ -54,63 +50,63 @@ import org.springframework.data.mongodb.core.mapping.FieldType; @@ -54,63 +50,63 @@ import org.springframework.data.mongodb.core.mapping.FieldType;
*/
public class PersonTypeInformation extends StaticTypeInformation<Person> {
public PersonTypeInformation() {
private static final PersonTypeInformation INSTANCE = new PersonTypeInformation();
private PersonTypeInformation() {
super(Person.class);
}
@Override
protected Map<String, TypeInformation<?>> computePropertiesMap() {
LinkedHashMap<String, TypeInformation<?>> properties = new LinkedHashMap<>();
properties.put("firstname", new StringTypeInformation());
properties.put("lastname", new StringTypeInformation());
properties.put("id", new StaticTypeInformation<>(Long.class));
properties.put("age", new StaticTypeInformation<>(int.class));
properties.put("address", new AddressTypeInformation());
properties.put("nicknames", new ListTypeInformation(new StringTypeInformation()));
return properties;
public static PersonTypeInformation instance() {
return INSTANCE;
}
@Override
protected Map<String, BiFunction<Person, Object, Person>> computeSetter() {
Map<String, BiFunction<Person, Object, Person>> setter = new LinkedHashMap<>();
setter.put("id", (bean, id) -> {
bean.setId((Long) id);
return bean;
});
setter.put("age", (bean, id) -> {
bean.setAge((int) id);
return bean;
});
// setter.put("firstname", (bean, id) -> {bean.setFirstname((String)id); return bean;});
// setter.put("lastname", (bean, id) -> {bean.setLastname((String)id); return bean;});
setter.put("address", (bean, id) -> {
bean.setAddress((Address) id);
return bean;
});
setter.put("nicknames", (bean, id) -> {
bean.setNicknames((List<String>) id);
return bean;
});
return setter;
protected void computeFields() {
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;
}
}));
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));
addField(Field.<Person, Address> type("address", AddressTypeInformation.instance()).getter(Person::getAddress)
.setter(Person::setAddress));
addField(Field.<Person, List<String>> type("nicknames", new ListTypeInformation<>(StringTypeInformation.instance()))
.getter(Person::getNicknames).setter(Person::setNicknames));
}
@Override
protected Map<String, Function<Person, Object>> computeGetter() {
protected void computeAnnotations() {
addAnnotation(new Document() {
@Override
public Class<? extends Annotation> annotationType() {
return Document.class;
}
Map<String, Function<Person, Object>> getter = new LinkedHashMap<>();
@Override
public String value() {
return collection();
}
getter.put("firstname", Person::getFirstname);
getter.put("lastname", Person::getLastname);
getter.put("id", Person::getId);
getter.put("address", Person::getAddress);
getter.put("nicknames", Person::getNicknames);
getter.put("age", Person::getAge);
@Override
public String collection() {
return "star-wars";
}
@Override
public String language() {
return "";
}
return getter;
@Override
public String collation() {
return "";
}
});
}
@Override
@ -122,12 +118,15 @@ public class PersonTypeInformation extends StaticTypeInformation<Person> { @@ -122,12 +118,15 @@ public class PersonTypeInformation extends StaticTypeInformation<Person> {
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", new StringTypeInformation(), new Annotation[] {}, entity));
String lastname = (String) provider
.getParameterValue(new Parameter("lastname", new StringTypeInformation(), new Annotation[] {}, entity));
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));
return (T) new Person(firstname, lastname);
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;
}
};
}
@ -137,15 +136,13 @@ public class PersonTypeInformation extends StaticTypeInformation<Person> { @@ -137,15 +136,13 @@ public class PersonTypeInformation extends StaticTypeInformation<Person> {
return StaticPreferredConstructor.of("firstname", "lastname");
}
@Override
protected Map<String, List<Annotation>> computePropertyAnnotations() {
Annotation atFieldOnFirstname() {
Map<String, List<Annotation>> annotationMap = new LinkedHashMap<>();
annotationMap.put("firstname", Collections.singletonList(new Field() {
return new org.springframework.data.mongodb.core.mapping.Field() {
@Override
public Class<? extends Annotation> annotationType() {
return Field.class;
return org.springframework.data.mongodb.core.mapping.Field.class;
}
@Override
@ -167,8 +164,6 @@ public class PersonTypeInformation extends StaticTypeInformation<Person> { @@ -167,8 +164,6 @@ public class PersonTypeInformation extends StaticTypeInformation<Person> {
public FieldType targetType() {
return FieldType.IMPLICIT;
}
}));
return annotationMap;
};
}
}

159
spring-data-mongodb/src/main/java/org/springframework/data/util/StaticTypeInformation.java

@ -34,24 +34,35 @@ package org.springframework.data.util; @@ -34,24 +34,35 @@ 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.Map;
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.AccessorFunctionProvider;
import org.springframework.data.mapping.model.EntityInstantiator;
import org.springframework.data.mapping.model.EntiyInstantiatorProvider;
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 StaticTypeInformation<S> extends ClassTypeInformation<S> {
public class StaticTypeInformation<S> extends ClassTypeInformation<S>
implements AnnotationProvider, EntiyInstantiatorProvider, PreferredConstructorProvider<S>,
PersistentPropertyAccessorFactoryProvider, AccessorFunctionProvider<S> {
private final Class<S> type;
@ -60,13 +71,12 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> { @@ -60,13 +71,12 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
private StaticTypeInformation<?> superTypeInformation;
private List<TypeInformation<?>> typeArguments;
private final Map<String, TypeInformation<?>> properties;
private final Map<String, BiFunction<S,Object,S>> setter;
private final Map<String, Function<S,Object>> getter;
private final Map<String, List<Annotation>> propertyAnnotations;
private MultiValueMap<Class<? extends Annotation>, Annotation> annotations;
private final Fields fields;
private EntityInstantiator instantiator;
private PreferredConstructor preferredConstructor;
private PreferredConstructor<S, ?> preferredConstructor;
public StaticTypeInformation(Class<S> type) {
this(type, null, null);
@ -79,18 +89,19 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> { @@ -79,18 +89,19 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
this.type = type;
this.componentType = componentType;
this.keyType = keyType;
this.properties = computePropertiesMap();
this.typeArguments = computeTypeArguments();
this.instantiator = computeEntityInstantiator();
this.setter = computeSetter();
this.getter = computeGetter();
this.preferredConstructor = computePreferredConstructor();
this.propertyAnnotations = computePropertyAnnotations();
this.preferredConstructor = computePreferredConstructor();
this.annotations = new LinkedMultiValueMap<>();
this.fields = new Fields(type);
computeFields();
computeAnnotations();
}
protected Map<String, TypeInformation<?>> computePropertiesMap() {
return Collections.emptyMap();
};
protected void addField(Field<?, S> field) {
this.fields.add(field);
}
protected List<TypeInformation<?>> computeTypeArguments() {
return Collections.emptyList();
@ -100,44 +111,29 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> { @@ -100,44 +111,29 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
return null;
}
protected PreferredConstructor computePreferredConstructor() {
protected PreferredConstructor<S, ?> computePreferredConstructor() {
return null;
}
public PreferredConstructor getPreferredConstructor() {
@Override
public PreferredConstructor<S, ?> getPreferredConstructor() {
return preferredConstructor;
}
protected Map<String, BiFunction<S,Object,S>> computeSetter() {
return Collections.emptyMap();
}
protected Map<String, Function<S,Object>> computeGetter() {
return Collections.emptyMap();
}
protected Map<String, List<Annotation>> computePropertyAnnotations() {
return Collections.emptyMap();
protected void computeFields() {
//
}
public Map<String, TypeInformation<?>> getProperties() {
return properties;
}
protected void computeAnnotations() {
public Map<String, BiFunction<S, Object, S>> getSetter() {
return setter;
}
public Map<String, Function<S, Object>> getGetter() {
return getter;
protected void addAnnotation(Annotation annotation) {
this.annotations.add(annotation.annotationType(), annotation);
}
public EntityInstantiator getInstantiator() {
return instantiator;
}
public Map<String, List<Annotation>> getPropertyAnnotations() {
return propertyAnnotations;
public void doWithFields(BiConsumer<String, Field<?, S>> consumer) {
fields.doWithFields(consumer);
}
@Override
@ -148,7 +144,12 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> { @@ -148,7 +144,12 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
@Nullable
@Override
public TypeInformation<?> getProperty(String property) {
return properties.get(property);
if (!fields.hasField(property)) {
return null;
}
return fields.getField(property).getTypeInformation();
}
@Override
@ -216,9 +217,12 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> { @@ -216,9 +217,12 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
@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;
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
if (!super.equals(o))
return false;
StaticTypeInformation<?> that = (StaticTypeInformation<?>) o;
@ -237,13 +241,7 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> { @@ -237,13 +241,7 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
if (!ObjectUtils.nullSafeEquals(typeArguments, that.typeArguments)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(properties, that.properties)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(setter, that.setter)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(getter, that.getter)) {
if (!ObjectUtils.nullSafeEquals(fields, that.fields)) {
return false;
}
return ObjectUtils.nullSafeEquals(instantiator, that.instantiator);
@ -257,13 +255,64 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> { @@ -257,13 +255,64 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
result = 31 * result + ObjectUtils.nullSafeHashCode(keyType);
result = 31 * result + ObjectUtils.nullSafeHashCode(superTypeInformation);
result = 31 * result + ObjectUtils.nullSafeHashCode(typeArguments);
result = 31 * result + ObjectUtils.nullSafeHashCode(properties);
result = 31 * result + ObjectUtils.nullSafeHashCode(setter);
result = 31 * result + ObjectUtils.nullSafeHashCode(getter);
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;
@ -279,7 +328,7 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> { @@ -279,7 +328,7 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
@Override
public boolean isConstructorParameter(PersistentProperty property) {
if(args.contains(property.getName())) {
if (args.contains(property.getName())) {
return true;
}

5
spring-data-mongodb/src/main/java/org/springframework/data/util/StringTypeInformation.java

@ -37,8 +37,13 @@ package org.springframework.data.util; @@ -37,8 +37,13 @@ package org.springframework.data.util;
*/
public class StringTypeInformation extends StaticTypeInformation<String> {
private static final StringTypeInformation INSTANCE = new StringTypeInformation();
public StringTypeInformation() {
super(String.class);
}
public static TypeInformation<String> instance() {
return INSTANCE;
}
}

104
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

@ -71,6 +71,7 @@ import org.springframework.data.mongodb.core.convert.DocumentAccessorUnitTests.N @@ -71,6 +71,7 @@ import org.springframework.data.mongodb.core.convert.DocumentAccessorUnitTests.N
import org.springframework.data.mongodb.core.convert.DocumentAccessorUnitTests.ProjectingType;
import org.springframework.data.mongodb.core.convert.MappingMongoConverterUnitTests.ClassWithMapUsingEnumAsKey.FooBarEnum;
import org.springframework.data.mongodb.core.geo.Sphere;
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.FieldType;
@ -81,6 +82,7 @@ import org.springframework.data.mongodb.core.mapping.TextScore; @@ -81,6 +82,7 @@ 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.util.ClassTypeInformation;
import org.springframework.data.util.Person;
import org.springframework.data.util.PersonTypeInformation;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.StopWatch;
@ -2183,46 +2185,46 @@ public class MappingMongoConverterUnitTests { @@ -2183,46 +2185,46 @@ public class MappingMongoConverterUnitTests {
assertThat(((LinkedHashMap) result.get("cluster")).get("_id")).isEqualTo(100L);
}
@Test
public void perf1() {
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.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"));
source.setAge(10);
source.setId(9876);
source.setNicknames(Arrays.asList("tick", "trick", "track"));
StopWatch stopWatch = new StopWatch();
List<org.bson.Document> sources = new ArrayList<>();
stopWatch.start("write");
for (int i = 0; i < 10000; i++) {
org.bson.Document targetDocument = new org.bson.Document();
converter.write(source, targetDocument);
sources.add(targetDocument);
}
stopWatch.stop();
stopWatch.start("read");
for (org.bson.Document sourceDoc : sources) {
assertThat(converter.read(org.springframework.data.util.Person.class, sourceDoc)).isEqualTo(source);
}
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());
}
// @Test
// public void perf1() {
//
// ClassTypeInformation.warmCache(PersonTypeInformation.instance(), AddressTypeInformation.instance());
//
// MongoMappingContext mappingContext = new MongoMappingContext();
// mappingContext.setInitialEntitySet(new LinkedHashSet<>(
// Arrays.asList(org.springframework.data.util.Person.class, org.springframework.data.util.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"));
// source.setAge(10);
// source = source.withId(9876);
// source.setNicknames(Arrays.asList("tick", "trick", "track"));
//
// StopWatch stopWatch = new StopWatch();
//
// List<org.bson.Document> sources = new ArrayList<>();
// stopWatch.start("write");
// for (int i = 0; i < 10000; i++) {
//
// org.bson.Document targetDocument = new org.bson.Document();
// converter.write(source, targetDocument);
//
// sources.add(targetDocument);
// }
// stopWatch.stop();
//
// stopWatch.start("read");
// for (org.bson.Document sourceDoc : sources) {
// assertThat(converter.read(org.springframework.data.util.Person.class, sourceDoc)).isEqualTo(source);
// }
// stopWatch.stop();
//
// System.out.println(stopWatch.prettyPrint());
//
// }
// public void perf2() {
//
@ -2244,9 +2246,9 @@ public class MappingMongoConverterUnitTests { @@ -2244,9 +2246,9 @@ public class MappingMongoConverterUnitTests {
// }
@Test
public void xxx() {
public void staticEntityMetadata() {
ClassTypeInformation.warmCache(new PersonTypeInformation(), new AddressTypeInformation());
ClassTypeInformation.warmCache(PersonTypeInformation.instance(), AddressTypeInformation.instance());
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setInitialEntitySet(new LinkedHashSet<>(
@ -2256,19 +2258,33 @@ public class MappingMongoConverterUnitTests { @@ -2256,19 +2258,33 @@ public class MappingMongoConverterUnitTests {
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"));
source.setAge(10);
source.setId(9876);
source = source.withId(9876);
source.setNicknames(Arrays.asList("tick", "trick", "track"));
MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext);
org.bson.Document targetDocument = new org.bson.Document();
System.out.println();
System.out.println("------ WRITE -------");
converter.write(source, targetDocument);
System.out.println();
System.out.println("target: " + targetDocument);
System.out.println("targetDocument: " + targetDocument);
System.out.println();
System.out.println("------ READ -------");
assertThat(targetDocument).containsEntry("_id", 9876L);
assertThat(targetDocument).containsEntry("first-name", "spring");
assertThat(targetDocument).containsEntry("address",
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,
targetDocument);
System.out.println();
System.out.println("targetEntity: " + targetEntity);
assertThat(targetEntity).isEqualTo(source);
BasicMongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(org.springframework.data.util.Person.class);
assertThat(entity.getCollection()).isEqualTo("star-wars");
}
static class GenericType<T> {

109
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/staticmetadata/StaticMetadataTests.java

@ -0,0 +1,109 @@ @@ -0,0 +1,109 @@
/*
* 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.mongodb.core.staticmetadata;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;
import java.util.Arrays;
import java.util.LinkedHashSet;
import org.bson.Document;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.mongodb.core.MongoTemplate;
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.util.ClassTypeInformation;
import org.springframework.data.util.Person;
import org.springframework.data.util.PersonTypeInformation;
import com.mongodb.client.MongoClients;
/**
* @author Christoph Strobl
* @since 2020/10
*/
public class StaticMetadataTests {
MongoMappingContext mappingContext;
MappingMongoConverter mongoConverter;
MongoTemplate template;
Person luke;
@BeforeAll
static void beforeAll() {
ClassTypeInformation.warmCache(PersonTypeInformation.instance(), AddressTypeInformation.instance());
}
@BeforeEach
void beforeEach() {
mappingContext = new MongoMappingContext();
mappingContext.setInitialEntitySet(new LinkedHashSet<>(
Arrays.asList(org.springframework.data.util.Person.class, org.springframework.data.util.Address.class)));
mappingContext.initialize();
mongoConverter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext);
mongoConverter.afterPropertiesSet();
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.setAge(22);
luke = luke.withId(9876);
luke.setNicknames(Arrays.asList("jedi", "wormie"));
}
@Test
void readWrite() {
template.save(luke);
Document savedDocument = template.execute("star-wars",
collection -> collection.find(new Document("_id", luke.getId())).first());
System.out.println("savedDocument.toJson(): " + savedDocument.toJson());
Person savedEntity = template.findOne(query(where("id").is(luke.getId())), Person.class);
System.out.println("savedEntity: " + savedEntity);
assertThat(savedEntity).isEqualTo(luke);
}
}
Loading…
Cancel
Save