hick hack - annotation support for properties
This commit is contained in:
@@ -16,12 +16,14 @@
|
||||
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;
|
||||
@@ -380,9 +382,10 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
// ((StaticTypeInformation<?>)typeInformation).doWithProperties()
|
||||
|
||||
Map<String, TypeInformation<?>> properties = ((StaticTypeInformation<?>) typeInformation).getProperties();
|
||||
Map<String, List<Annotation>> annotations = ((StaticTypeInformation<?>) typeInformation).getPropertyAnnotations();
|
||||
for (Entry<String, TypeInformation<?>> entry : properties.entrySet()) {
|
||||
|
||||
P target = createPersistentProperty(Property.of(typeInformation, entry.getKey()), entity, simpleTypeHolder);
|
||||
P target = createPersistentProperty(Property.of(entry.getValue(), entry.getKey(), annotations.get(entry.getKey())), entity, simpleTypeHolder);
|
||||
entity.addPersistentProperty(target);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* 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()));
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,11 @@ 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;
|
||||
@@ -41,6 +44,8 @@ import org.springframework.util.StringUtils;
|
||||
public class Property {
|
||||
|
||||
private @Nullable TypeInformation<?> typeInformation;
|
||||
private List<Annotation> annotations;
|
||||
|
||||
private final Optional<Field> field;
|
||||
private final Optional<PropertyDescriptor> descriptor;
|
||||
|
||||
@@ -53,8 +58,9 @@ public class Property {
|
||||
private final Lazy<String> toString;
|
||||
private final Lazy<Optional<Method>> wither;
|
||||
|
||||
private Property(String name, TypeInformation<?> typeInformation) {
|
||||
private Property(String name, TypeInformation<?> typeInformation, List<Annotation> annotations) {
|
||||
|
||||
this.annotations = annotations;
|
||||
this.typeInformation = typeInformation;
|
||||
this.field = Optional.empty();
|
||||
this.descriptor = Optional.empty();
|
||||
@@ -73,6 +79,7 @@ public class Property {
|
||||
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;
|
||||
|
||||
@@ -135,7 +142,11 @@ public class Property {
|
||||
* @return
|
||||
*/
|
||||
public static Property of(TypeInformation<?> type, String name) {
|
||||
return new Property(name, type);
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,6 +251,10 @@ public class Property {
|
||||
return rawType;
|
||||
}
|
||||
|
||||
public List<Annotation> getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
@@ -53,19 +55,38 @@ public class Address {
|
||||
return street;
|
||||
}
|
||||
|
||||
// public void setCity(String city) {
|
||||
// this.city = city;
|
||||
// }
|
||||
//
|
||||
// public void setStreet(String street) {
|
||||
// this.street = 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 + '\'' +
|
||||
'}';
|
||||
return "Address{" + "city='" + city + '\'' + ", street='" + street + '\'' + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
Address address = (Address) o;
|
||||
|
||||
if (!ObjectUtils.nullSafeEquals(city, address.city)) {
|
||||
return false;
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(street, address.street);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = ObjectUtils.nullSafeHashCode(city);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(street);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ package org.springframework.data.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2020/10
|
||||
@@ -100,13 +102,43 @@ public class Person {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Person{" +
|
||||
"id=" + id +
|
||||
", firstname='" + firstname + '\'' +
|
||||
", lastname='" + lastname + '\'' +
|
||||
", age=" + age +
|
||||
", address=" + address +
|
||||
", nicknames=" + nicknames +
|
||||
'}';
|
||||
return "Person{" + "id=" + id + ", firstname='" + firstname + '\'' + ", lastname='" + lastname + '\'' + ", age="
|
||||
+ age + ", address=" + address + ", nicknames=" + nicknames + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
Person person = (Person) o;
|
||||
|
||||
if (id != person.id)
|
||||
return false;
|
||||
if (age != person.age)
|
||||
return false;
|
||||
if (!ObjectUtils.nullSafeEquals(firstname, person.firstname)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(lastname, person.lastname)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(address, person.address)) {
|
||||
return false;
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(nicknames, person.nicknames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (int) (id ^ (id >>> 32));
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(firstname);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(lastname);
|
||||
result = 31 * result + age;
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(address);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(nicknames);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
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;
|
||||
@@ -44,6 +45,8 @@ 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.FieldType;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
@@ -133,4 +136,39 @@ public class PersonTypeInformation extends StaticTypeInformation<Person> {
|
||||
protected PreferredConstructor computePreferredConstructor() {
|
||||
return StaticPreferredConstructor.of("firstname", "lastname");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, List<Annotation>> computePropertyAnnotations() {
|
||||
|
||||
Map<String, List<Annotation>> annotationMap = new LinkedHashMap<>();
|
||||
annotationMap.put("firstname", Collections.singletonList(new Field() {
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Field.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String value() {
|
||||
return "first-name";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return value();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int order() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldType targetType() {
|
||||
return FieldType.IMPLICIT;
|
||||
}
|
||||
}));
|
||||
|
||||
return annotationMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
@@ -62,6 +63,7 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
|
||||
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 EntityInstantiator instantiator;
|
||||
private PreferredConstructor preferredConstructor;
|
||||
@@ -83,6 +85,7 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
|
||||
this.setter = computeSetter();
|
||||
this.getter = computeGetter();
|
||||
this.preferredConstructor = computePreferredConstructor();
|
||||
this.propertyAnnotations = computePropertyAnnotations();
|
||||
}
|
||||
|
||||
protected Map<String, TypeInformation<?>> computePropertiesMap() {
|
||||
@@ -113,6 +116,10 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
protected Map<String, List<Annotation>> computePropertyAnnotations() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
public Map<String, TypeInformation<?>> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
@@ -129,6 +136,10 @@ public class StaticTypeInformation<S> extends ClassTypeInformation<S> {
|
||||
return instantiator;
|
||||
}
|
||||
|
||||
public Map<String, List<Annotation>> getPropertyAnnotations() {
|
||||
return propertyAnnotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInformation<?>> getParameterTypes(Constructor<?> constructor) {
|
||||
return null;
|
||||
|
||||
@@ -23,6 +23,7 @@ import static org.springframework.data.mongodb.core.DocumentTestUtils.*;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URL;
|
||||
@@ -78,12 +79,11 @@ 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.Address;
|
||||
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;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
@@ -2182,14 +2182,75 @@ 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());
|
||||
|
||||
}
|
||||
|
||||
// public void perf2() {
|
||||
//
|
||||
// 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"));
|
||||
//
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void xxx() {
|
||||
|
||||
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.util.Person.class, org.springframework.data.util.Address.class)));
|
||||
mappingContext.initialize();
|
||||
|
||||
org.springframework.data.util.Person source = new org.springframework.data.util.Person("spring", "data");
|
||||
@@ -2197,17 +2258,17 @@ public class MappingMongoConverterUnitTests {
|
||||
source.setAge(10);
|
||||
source.setId(9876);
|
||||
source.setNicknames(Arrays.asList("tick", "trick", "track"));
|
||||
|
||||
|
||||
MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext);
|
||||
org.bson.Document targetDocument = new org.bson.Document();
|
||||
converter.write(source, targetDocument);
|
||||
|
||||
|
||||
System.out.println("target: " + targetDocument);
|
||||
|
||||
org.springframework.data.util.Person targetEntity = converter.read(org.springframework.data.util.Person.class, targetDocument);
|
||||
org.springframework.data.util.Person targetEntity = converter.read(org.springframework.data.util.Person.class,
|
||||
targetDocument);
|
||||
System.out.println("targetEntity: " + targetEntity);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static class GenericType<T> {
|
||||
@@ -2680,4 +2741,34 @@ public class MappingMongoConverterUnitTests {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
void xxx2() {
|
||||
|
||||
new Field() {
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String value() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int order() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldType targetType() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user