Skip to content

Commit 767d97a

Browse files
committed
Polishing.
Remove code duplications. Reuse target type computation for enum types. Refine method names. See #3766 Closes #3837
1 parent bbe8410 commit 767d97a

File tree

1 file changed

+63
-45
lines changed

1 file changed

+63
-45
lines changed

Diff for: spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MappingMongoJsonSchemaCreator.java

+63-45
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.stream.Collectors;
2525

2626
import org.bson.Document;
27+
2728
import org.springframework.data.mapping.PersistentProperty;
2829
import org.springframework.data.mapping.context.MappingContext;
2930
import org.springframework.data.mongodb.core.convert.MongoConverter;
@@ -40,7 +41,7 @@
4041
import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
4142
import org.springframework.data.mongodb.core.schema.MongoJsonSchema.MongoJsonSchemaBuilder;
4243
import org.springframework.data.mongodb.core.schema.TypedJsonSchemaObject;
43-
import org.springframework.lang.Nullable;
44+
import org.springframework.data.util.ClassTypeInformation;
4445
import org.springframework.util.Assert;
4546
import org.springframework.util.ClassUtils;
4647
import org.springframework.util.CollectionUtils;
@@ -168,7 +169,7 @@ private JsonSchemaProperty computeSchemaForProperty(List<MongoPersistentProperty
168169

169170
JsonSchemaProperty schemaProperty;
170171
if (isCollection(property)) {
171-
schemaProperty = createSchemaPropertyForCollection(fieldName, property, required);
172+
schemaProperty = createArraySchemaProperty(fieldName, property, required);
172173
} else if (property.isMap()) {
173174
schemaProperty = createSchemaProperty(fieldName, Type.objectType(), required);
174175
} else if (ClassUtils.isAssignable(Enum.class, targetType)) {
@@ -180,49 +181,52 @@ private JsonSchemaProperty computeSchemaForProperty(List<MongoPersistentProperty
180181
return applyEncryptionDataIfNecessary(property, schemaProperty);
181182
}
182183

183-
private JsonSchemaProperty createSchemaPropertyForCollection(String fieldName, MongoPersistentProperty property,
184+
private JsonSchemaProperty createArraySchemaProperty(String fieldName, MongoPersistentProperty property,
184185
boolean required) {
185186

186187
ArrayJsonSchemaProperty schemaProperty = JsonSchemaProperty.array(fieldName);
187188

188-
if (property.getActualType() != Object.class) {
189+
if (isSpecificType(property)) {
190+
schemaProperty = potentiallyEnhanceArraySchemaProperty(property, schemaProperty);
191+
}
189192

190-
MongoPersistentEntity<?> persistentEntity = mappingContext
191-
.getPersistentEntity(property.getTypeInformation().getComponentType());
193+
return createPotentiallyRequiredSchemaProperty(schemaProperty, required);
194+
}
192195

193-
if (persistentEntity == null) {
196+
@SuppressWarnings({ "unchecked", "rawtypes" })
197+
private ArrayJsonSchemaProperty potentiallyEnhanceArraySchemaProperty(MongoPersistentProperty property,
198+
ArrayJsonSchemaProperty schemaProperty) {
194199

195-
if (ClassUtils.isAssignable(Enum.class, property.getActualType())) {
200+
MongoPersistentEntity<?> persistentEntity = mappingContext
201+
.getPersistentEntity(property.getTypeInformation().getRequiredComponentType());
196202

197-
List<Object> possibleValues = new ArrayList<>();
203+
if (persistentEntity != null) {
198204

199-
for (Object enumValue : EnumSet.allOf((Class) property.getActualType())) {
200-
possibleValues.add(converter.convertToMongoType(enumValue));
201-
}
205+
List<JsonSchemaProperty> nestedProperties = computePropertiesForEntity(Collections.emptyList(), persistentEntity);
202206

203-
Class targetType = possibleValues.isEmpty() ? property.getActualType()
204-
: possibleValues.iterator().next().getClass();
205-
schemaProperty = schemaProperty
206-
.items(Collections.singleton(JsonSchemaObject.of(targetType).possibleValues(possibleValues)));
207-
} else {
208-
schemaProperty = schemaProperty.items(Collections.singleton(JsonSchemaObject.of(property.getActualType())));
209-
}
210-
} else {
207+
if (nestedProperties.isEmpty()) {
208+
return schemaProperty;
209+
}
211210

212-
List<JsonSchemaProperty> nestedProperties = computePropertiesForEntity(Collections.emptyList(),
213-
persistentEntity);
211+
return schemaProperty
212+
.items(JsonSchemaObject.object().properties(nestedProperties.toArray(new JsonSchemaProperty[0])));
213+
}
214214

215-
if (!nestedProperties.isEmpty()) {
216-
schemaProperty = schemaProperty.items(Collections
217-
.singleton(JsonSchemaObject.object().properties(nestedProperties.toArray(new JsonSchemaProperty[0]))));
218-
}
219-
}
215+
if (ClassUtils.isAssignable(Enum.class, property.getActualType())) {
216+
217+
List<Object> possibleValues = getPossibleEnumValues((Class<Enum>) property.getActualType());
218+
219+
return schemaProperty
220+
.items(createSchemaObject(computeTargetType(property.getActualType(), possibleValues), possibleValues));
220221
}
221222

222-
return createPotentiallyRequiredSchemaProperty(schemaProperty, required);
223+
return schemaProperty.items(JsonSchemaObject.of(property.getActualType()));
224+
}
225+
226+
private boolean isSpecificType(MongoPersistentProperty property) {
227+
return !ClassTypeInformation.OBJECT.equals(property.getTypeInformation().getActualType());
223228
}
224229

225-
@Nullable
226230
private JsonSchemaProperty applyEncryptionDataIfNecessary(MongoPersistentProperty property,
227231
JsonSchemaProperty schemaProperty) {
228232

@@ -252,15 +256,12 @@ private JsonSchemaProperty createObjectSchemaPropertyForEntity(List<MongoPersist
252256
target.properties(nestedProperties.toArray(new JsonSchemaProperty[0])), required);
253257
}
254258

259+
@SuppressWarnings({ "unchecked", "rawtypes" })
255260
private JsonSchemaProperty createEnumSchemaProperty(String fieldName, Class<?> targetType, boolean required) {
256261

257-
List<Object> possibleValues = new ArrayList<>();
262+
List<Object> possibleValues = getPossibleEnumValues((Class<Enum>) targetType);
258263

259-
for (Object enumValue : EnumSet.allOf((Class) targetType)) {
260-
possibleValues.add(converter.convertToMongoType(enumValue));
261-
}
262-
263-
targetType = possibleValues.isEmpty() ? targetType : possibleValues.iterator().next().getClass();
264+
targetType = computeTargetType(targetType, possibleValues);
264265
return createSchemaProperty(fieldName, targetType, required, possibleValues);
265266
}
266267

@@ -271,14 +272,20 @@ JsonSchemaProperty createSchemaProperty(String fieldName, Object type, boolean r
271272
JsonSchemaProperty createSchemaProperty(String fieldName, Object type, boolean required,
272273
Collection<?> possibleValues) {
273274

275+
TypedJsonSchemaObject schemaObject = createSchemaObject(type, possibleValues);
276+
277+
return createPotentiallyRequiredSchemaProperty(JsonSchemaProperty.named(fieldName).with(schemaObject), required);
278+
}
279+
280+
private TypedJsonSchemaObject createSchemaObject(Object type, Collection<?> possibleValues) {
281+
274282
TypedJsonSchemaObject schemaObject = type instanceof Type ? JsonSchemaObject.of(Type.class.cast(type))
275283
: JsonSchemaObject.of(Class.class.cast(type));
276284

277285
if (!CollectionUtils.isEmpty(possibleValues)) {
278286
schemaObject = schemaObject.possibleValues(possibleValues);
279287
}
280-
281-
return createPotentiallyRequiredSchemaProperty(JsonSchemaProperty.named(fieldName).with(schemaObject), required);
288+
return schemaObject;
282289
}
283290

284291
private String computePropertyFieldName(PersistentProperty property) {
@@ -309,23 +316,34 @@ private Class<?> computeTargetType(PersistentProperty<?> property) {
309316
return mongoProperty.getFieldType() != mongoProperty.getActualType() ? Object.class : mongoProperty.getFieldType();
310317
}
311318

312-
private static boolean isCollection(MongoPersistentProperty property) {
313-
return property.isCollectionLike() && !property.getType().equals(byte[].class);
319+
private static Class<?> computeTargetType(Class<?> fallback, List<Object> possibleValues) {
320+
return possibleValues.isEmpty() ? fallback : possibleValues.iterator().next().getClass();
314321
}
315322

316-
static JsonSchemaProperty createPotentiallyRequiredSchemaProperty(JsonSchemaProperty property, boolean required) {
323+
private <E extends Enum<E>> List<Object> getPossibleEnumValues(Class<E> targetType) {
317324

318-
if (!required) {
319-
return property;
325+
EnumSet<E> enumSet = EnumSet.allOf(targetType);
326+
List<Object> possibleValues = new ArrayList<>(enumSet.size());
327+
328+
for (Object enumValue : enumSet) {
329+
possibleValues.add(converter.convertToMongoType(enumValue));
320330
}
321331

322-
return JsonSchemaProperty.required(property);
332+
return possibleValues;
333+
}
334+
335+
private static boolean isCollection(MongoPersistentProperty property) {
336+
return property.isCollectionLike() && !property.getType().equals(byte[].class);
337+
}
338+
339+
static JsonSchemaProperty createPotentiallyRequiredSchemaProperty(JsonSchemaProperty property, boolean required) {
340+
return required ? JsonSchemaProperty.required(property) : property;
323341
}
324342

325343
class PropertyContext implements JsonSchemaPropertyContext {
326344

327-
private String path;
328-
private MongoPersistentProperty property;
345+
private final String path;
346+
private final MongoPersistentProperty property;
329347

330348
public PropertyContext(String path, MongoPersistentProperty property) {
331349
this.path = path;

0 commit comments

Comments
 (0)