Polishing.
Remove code duplications. Reuse target type computation for enum types. Refine method names. See #3766 Closes #3837
This commit is contained in:
@@ -24,6 +24,7 @@ import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
@@ -40,7 +41,7 @@ import org.springframework.data.mongodb.core.schema.JsonSchemaProperty;
|
||||
import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
|
||||
import org.springframework.data.mongodb.core.schema.MongoJsonSchema.MongoJsonSchemaBuilder;
|
||||
import org.springframework.data.mongodb.core.schema.TypedJsonSchemaObject;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -168,7 +169,7 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
|
||||
|
||||
JsonSchemaProperty schemaProperty;
|
||||
if (isCollection(property)) {
|
||||
schemaProperty = createSchemaPropertyForCollection(fieldName, property, required);
|
||||
schemaProperty = createArraySchemaProperty(fieldName, property, required);
|
||||
} else if (property.isMap()) {
|
||||
schemaProperty = createSchemaProperty(fieldName, Type.objectType(), required);
|
||||
} else if (ClassUtils.isAssignable(Enum.class, targetType)) {
|
||||
@@ -180,49 +181,52 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
|
||||
return applyEncryptionDataIfNecessary(property, schemaProperty);
|
||||
}
|
||||
|
||||
private JsonSchemaProperty createSchemaPropertyForCollection(String fieldName, MongoPersistentProperty property,
|
||||
private JsonSchemaProperty createArraySchemaProperty(String fieldName, MongoPersistentProperty property,
|
||||
boolean required) {
|
||||
|
||||
ArrayJsonSchemaProperty schemaProperty = JsonSchemaProperty.array(fieldName);
|
||||
|
||||
if (property.getActualType() != Object.class) {
|
||||
|
||||
MongoPersistentEntity<?> persistentEntity = mappingContext
|
||||
.getPersistentEntity(property.getTypeInformation().getComponentType());
|
||||
|
||||
if (persistentEntity == null) {
|
||||
|
||||
if (ClassUtils.isAssignable(Enum.class, property.getActualType())) {
|
||||
|
||||
List<Object> possibleValues = new ArrayList<>();
|
||||
|
||||
for (Object enumValue : EnumSet.allOf((Class) property.getActualType())) {
|
||||
possibleValues.add(converter.convertToMongoType(enumValue));
|
||||
}
|
||||
|
||||
Class targetType = possibleValues.isEmpty() ? property.getActualType()
|
||||
: possibleValues.iterator().next().getClass();
|
||||
schemaProperty = schemaProperty
|
||||
.items(Collections.singleton(JsonSchemaObject.of(targetType).possibleValues(possibleValues)));
|
||||
} else {
|
||||
schemaProperty = schemaProperty.items(Collections.singleton(JsonSchemaObject.of(property.getActualType())));
|
||||
}
|
||||
} else {
|
||||
|
||||
List<JsonSchemaProperty> nestedProperties = computePropertiesForEntity(Collections.emptyList(),
|
||||
persistentEntity);
|
||||
|
||||
if (!nestedProperties.isEmpty()) {
|
||||
schemaProperty = schemaProperty.items(Collections
|
||||
.singleton(JsonSchemaObject.object().properties(nestedProperties.toArray(new JsonSchemaProperty[0]))));
|
||||
}
|
||||
}
|
||||
if (isSpecificType(property)) {
|
||||
schemaProperty = potentiallyEnhanceArraySchemaProperty(property, schemaProperty);
|
||||
}
|
||||
|
||||
return createPotentiallyRequiredSchemaProperty(schemaProperty, required);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private ArrayJsonSchemaProperty potentiallyEnhanceArraySchemaProperty(MongoPersistentProperty property,
|
||||
ArrayJsonSchemaProperty schemaProperty) {
|
||||
|
||||
MongoPersistentEntity<?> persistentEntity = mappingContext
|
||||
.getPersistentEntity(property.getTypeInformation().getRequiredComponentType());
|
||||
|
||||
if (persistentEntity != null) {
|
||||
|
||||
List<JsonSchemaProperty> nestedProperties = computePropertiesForEntity(Collections.emptyList(), persistentEntity);
|
||||
|
||||
if (nestedProperties.isEmpty()) {
|
||||
return schemaProperty;
|
||||
}
|
||||
|
||||
return schemaProperty
|
||||
.items(JsonSchemaObject.object().properties(nestedProperties.toArray(new JsonSchemaProperty[0])));
|
||||
}
|
||||
|
||||
if (ClassUtils.isAssignable(Enum.class, property.getActualType())) {
|
||||
|
||||
List<Object> possibleValues = getPossibleEnumValues((Class<Enum>) property.getActualType());
|
||||
|
||||
return schemaProperty
|
||||
.items(createSchemaObject(computeTargetType(property.getActualType(), possibleValues), possibleValues));
|
||||
}
|
||||
|
||||
return schemaProperty.items(JsonSchemaObject.of(property.getActualType()));
|
||||
}
|
||||
|
||||
private boolean isSpecificType(MongoPersistentProperty property) {
|
||||
return !ClassTypeInformation.OBJECT.equals(property.getTypeInformation().getActualType());
|
||||
}
|
||||
|
||||
private JsonSchemaProperty applyEncryptionDataIfNecessary(MongoPersistentProperty property,
|
||||
JsonSchemaProperty schemaProperty) {
|
||||
|
||||
@@ -252,15 +256,12 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
|
||||
target.properties(nestedProperties.toArray(new JsonSchemaProperty[0])), required);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private JsonSchemaProperty createEnumSchemaProperty(String fieldName, Class<?> targetType, boolean required) {
|
||||
|
||||
List<Object> possibleValues = new ArrayList<>();
|
||||
List<Object> possibleValues = getPossibleEnumValues((Class<Enum>) targetType);
|
||||
|
||||
for (Object enumValue : EnumSet.allOf((Class) targetType)) {
|
||||
possibleValues.add(converter.convertToMongoType(enumValue));
|
||||
}
|
||||
|
||||
targetType = possibleValues.isEmpty() ? targetType : possibleValues.iterator().next().getClass();
|
||||
targetType = computeTargetType(targetType, possibleValues);
|
||||
return createSchemaProperty(fieldName, targetType, required, possibleValues);
|
||||
}
|
||||
|
||||
@@ -271,14 +272,20 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
|
||||
JsonSchemaProperty createSchemaProperty(String fieldName, Object type, boolean required,
|
||||
Collection<?> possibleValues) {
|
||||
|
||||
TypedJsonSchemaObject schemaObject = createSchemaObject(type, possibleValues);
|
||||
|
||||
return createPotentiallyRequiredSchemaProperty(JsonSchemaProperty.named(fieldName).with(schemaObject), required);
|
||||
}
|
||||
|
||||
private TypedJsonSchemaObject createSchemaObject(Object type, Collection<?> possibleValues) {
|
||||
|
||||
TypedJsonSchemaObject schemaObject = type instanceof Type ? JsonSchemaObject.of(Type.class.cast(type))
|
||||
: JsonSchemaObject.of(Class.class.cast(type));
|
||||
|
||||
if (!CollectionUtils.isEmpty(possibleValues)) {
|
||||
schemaObject = schemaObject.possibleValues(possibleValues);
|
||||
}
|
||||
|
||||
return createPotentiallyRequiredSchemaProperty(JsonSchemaProperty.named(fieldName).with(schemaObject), required);
|
||||
return schemaObject;
|
||||
}
|
||||
|
||||
private String computePropertyFieldName(PersistentProperty property) {
|
||||
@@ -309,23 +316,34 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
|
||||
return mongoProperty.getFieldType() != mongoProperty.getActualType() ? Object.class : mongoProperty.getFieldType();
|
||||
}
|
||||
|
||||
private static Class<?> computeTargetType(Class<?> fallback, List<Object> possibleValues) {
|
||||
return possibleValues.isEmpty() ? fallback : possibleValues.iterator().next().getClass();
|
||||
}
|
||||
|
||||
private <E extends Enum<E>> List<Object> getPossibleEnumValues(Class<E> targetType) {
|
||||
|
||||
EnumSet<E> enumSet = EnumSet.allOf(targetType);
|
||||
List<Object> possibleValues = new ArrayList<>(enumSet.size());
|
||||
|
||||
for (Object enumValue : enumSet) {
|
||||
possibleValues.add(converter.convertToMongoType(enumValue));
|
||||
}
|
||||
|
||||
return possibleValues;
|
||||
}
|
||||
|
||||
private static boolean isCollection(MongoPersistentProperty property) {
|
||||
return property.isCollectionLike() && !property.getType().equals(byte[].class);
|
||||
}
|
||||
|
||||
static JsonSchemaProperty createPotentiallyRequiredSchemaProperty(JsonSchemaProperty property, boolean required) {
|
||||
|
||||
if (!required) {
|
||||
return property;
|
||||
}
|
||||
|
||||
return JsonSchemaProperty.required(property);
|
||||
return required ? JsonSchemaProperty.required(property) : property;
|
||||
}
|
||||
|
||||
class PropertyContext implements JsonSchemaPropertyContext {
|
||||
|
||||
private String path;
|
||||
private MongoPersistentProperty property;
|
||||
private final String path;
|
||||
private final MongoPersistentProperty property;
|
||||
|
||||
public PropertyContext(String path, MongoPersistentProperty property) {
|
||||
this.path = path;
|
||||
|
||||
Reference in New Issue
Block a user