Skip to content

Commit bbe8410

Browse files
christophstroblmp911de
authored andcommitted
Render items for collection-like properties when deriving $jsonSchema.
Closes #3766 Original pull request: #3837.
1 parent c0a4bdb commit bbe8410

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

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

+50-5
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727
import org.springframework.data.mapping.PersistentProperty;
2828
import org.springframework.data.mapping.context.MappingContext;
2929
import org.springframework.data.mongodb.core.convert.MongoConverter;
30-
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
3130
import org.springframework.data.mongodb.core.mapping.Encrypted;
3231
import org.springframework.data.mongodb.core.mapping.Field;
3332
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
3433
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
34+
import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.ArrayJsonSchemaProperty;
3535
import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty;
3636
import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.ObjectJsonSchemaProperty;
3737
import org.springframework.data.mongodb.core.schema.JsonSchemaObject;
@@ -160,15 +160,15 @@ private JsonSchemaProperty computeSchemaForProperty(List<MongoPersistentProperty
160160
Class<?> rawTargetType = computeTargetType(property); // target type before conversion
161161
Class<?> targetType = converter.getTypeMapper().getWriteTargetTypeFor(rawTargetType); // conversion target type
162162

163-
if (property.isEntity() && ObjectUtils.nullSafeEquals(rawTargetType, targetType)) {
163+
if (!isCollection(property) && property.isEntity() && ObjectUtils.nullSafeEquals(rawTargetType, targetType)) {
164164
return createObjectSchemaPropertyForEntity(path, property, required);
165165
}
166166

167167
String fieldName = computePropertyFieldName(property);
168168

169169
JsonSchemaProperty schemaProperty;
170-
if (property.isCollectionLike()) {
171-
schemaProperty = createSchemaProperty(fieldName, targetType, required);
170+
if (isCollection(property)) {
171+
schemaProperty = createSchemaPropertyForCollection(fieldName, property, required);
172172
} else if (property.isMap()) {
173173
schemaProperty = createSchemaProperty(fieldName, Type.objectType(), required);
174174
} else if (ClassUtils.isAssignable(Enum.class, targetType)) {
@@ -180,6 +180,48 @@ private JsonSchemaProperty computeSchemaForProperty(List<MongoPersistentProperty
180180
return applyEncryptionDataIfNecessary(property, schemaProperty);
181181
}
182182

183+
private JsonSchemaProperty createSchemaPropertyForCollection(String fieldName, MongoPersistentProperty property,
184+
boolean required) {
185+
186+
ArrayJsonSchemaProperty schemaProperty = JsonSchemaProperty.array(fieldName);
187+
188+
if (property.getActualType() != Object.class) {
189+
190+
MongoPersistentEntity<?> persistentEntity = mappingContext
191+
.getPersistentEntity(property.getTypeInformation().getComponentType());
192+
193+
if (persistentEntity == null) {
194+
195+
if (ClassUtils.isAssignable(Enum.class, property.getActualType())) {
196+
197+
List<Object> possibleValues = new ArrayList<>();
198+
199+
for (Object enumValue : EnumSet.allOf((Class) property.getActualType())) {
200+
possibleValues.add(converter.convertToMongoType(enumValue));
201+
}
202+
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 {
211+
212+
List<JsonSchemaProperty> nestedProperties = computePropertiesForEntity(Collections.emptyList(),
213+
persistentEntity);
214+
215+
if (!nestedProperties.isEmpty()) {
216+
schemaProperty = schemaProperty.items(Collections
217+
.singleton(JsonSchemaObject.object().properties(nestedProperties.toArray(new JsonSchemaProperty[0]))));
218+
}
219+
}
220+
}
221+
222+
return createPotentiallyRequiredSchemaProperty(schemaProperty, required);
223+
}
224+
183225
@Nullable
184226
private JsonSchemaProperty applyEncryptionDataIfNecessary(MongoPersistentProperty property,
185227
JsonSchemaProperty schemaProperty) {
@@ -197,7 +239,6 @@ private JsonSchemaProperty applyEncryptionDataIfNecessary(MongoPersistentPropert
197239
enc = enc.keys(property.getEncryptionKeyIds());
198240
}
199241
return enc;
200-
201242
}
202243

203244
private JsonSchemaProperty createObjectSchemaPropertyForEntity(List<MongoPersistentProperty> path,
@@ -268,6 +309,10 @@ private Class<?> computeTargetType(PersistentProperty<?> property) {
268309
return mongoProperty.getFieldType() != mongoProperty.getActualType() ? Object.class : mongoProperty.getFieldType();
269310
}
270311

312+
private static boolean isCollection(MongoPersistentProperty property) {
313+
return property.isCollectionLike() && !property.getType().equals(byte[].class);
314+
}
315+
271316
static JsonSchemaProperty createPotentiallyRequiredSchemaProperty(JsonSchemaProperty property, boolean required) {
272317

273318
if (!required) {

Diff for: spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MappingMongoJsonSchemaCreatorUnitTests.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ enum JustSomeEnum {
185185
" 'arrayProperty' : { 'type' : 'array' }," + //
186186
" 'binaryDataProperty' : { 'bsonType' : 'binData' }," + //
187187
" 'collectionProperty' : { 'type' : 'array' }," + //
188+
" 'simpleTypeCollectionProperty' : { 'type' : 'array', 'items' : { 'type' : 'string' } }," + //
189+
" 'complexTypeCollectionProperty' : { 'type' : 'array', 'items' : { 'type' : 'object', 'properties' : { 'field' : { 'type' : 'string'} } } }" + //
190+
" 'enumTypeCollectionProperty' : { 'type' : 'array', 'items' : " + JUST_SOME_ENUM + " }" + //
188191
" 'mapProperty' : { 'type' : 'object' }," + //
189192
" 'objectProperty' : { 'type' : 'object' }," + //
190193
" 'enumProperty' : " + JUST_SOME_ENUM + " }" + //
@@ -203,12 +206,19 @@ static class VariousFieldTypes {
203206
Date dateProperty;
204207
Object[] arrayProperty;
205208
byte[] binaryDataProperty;
206-
List<String> collectionProperty;
209+
List<Object> collectionProperty;
210+
List<String> simpleTypeCollectionProperty;
211+
List<SomeDomainType> complexTypeCollectionProperty;
212+
List<JustSomeEnum> enumTypeCollectionProperty;
207213
Map<String, String> mapProperty;
208214
Object objectProperty;
209215
JustSomeEnum enumProperty;
210216
}
211217

218+
static class SomeDomainType {
219+
String field;
220+
}
221+
212222
// --> NESTED DOMAIN TYPE
213223

214224
static final String WITH_NESTED_DOMAIN_TYPE = "" + //

0 commit comments

Comments
 (0)