2020import java .util .Collections ;
2121import java .util .EnumSet ;
2222import java .util .List ;
23+ import java .util .function .Predicate ;
24+ import java .util .stream .Collectors ;
2325
26+ import org .bson .Document ;
2427import org .springframework .data .mapping .PersistentProperty ;
2528import org .springframework .data .mapping .context .MappingContext ;
2629import org .springframework .data .mongodb .core .convert .MongoConverter ;
30+ import org .springframework .data .mongodb .core .mapping .BasicMongoPersistentEntity ;
31+ import org .springframework .data .mongodb .core .mapping .Encrypted ;
2732import org .springframework .data .mongodb .core .mapping .Field ;
2833import org .springframework .data .mongodb .core .mapping .MongoPersistentEntity ;
2934import org .springframework .data .mongodb .core .mapping .MongoPersistentProperty ;
35+ import org .springframework .data .mongodb .core .schema .IdentifiableJsonSchemaProperty .EncryptedJsonSchemaProperty ;
3036import org .springframework .data .mongodb .core .schema .IdentifiableJsonSchemaProperty .ObjectJsonSchemaProperty ;
3137import org .springframework .data .mongodb .core .schema .JsonSchemaObject ;
3238import org .springframework .data .mongodb .core .schema .JsonSchemaObject .Type ;
3339import org .springframework .data .mongodb .core .schema .JsonSchemaProperty ;
3440import org .springframework .data .mongodb .core .schema .MongoJsonSchema ;
3541import org .springframework .data .mongodb .core .schema .MongoJsonSchema .MongoJsonSchemaBuilder ;
3642import org .springframework .data .mongodb .core .schema .TypedJsonSchemaObject ;
43+ import org .springframework .lang .Nullable ;
3744import org .springframework .util .Assert ;
3845import org .springframework .util .ClassUtils ;
3946import org .springframework .util .CollectionUtils ;
4047import org .springframework .util .ObjectUtils ;
48+ import org .springframework .util .StringUtils ;
4149
4250/**
4351 * {@link MongoJsonSchemaCreator} implementation using both {@link MongoConverter} and {@link MappingContext} to obtain
@@ -52,6 +60,7 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
5260
5361 private final MongoConverter converter ;
5462 private final MappingContext <MongoPersistentEntity <?>, MongoPersistentProperty > mappingContext ;
63+ private final Predicate <JsonSchemaPropertyContext > filter ;
5564
5665 /**
5766 * Create a new instance of {@link MappingMongoJsonSchemaCreator}.
@@ -61,10 +70,24 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
6170 @ SuppressWarnings ("unchecked" )
6271 MappingMongoJsonSchemaCreator (MongoConverter converter ) {
6372
73+ this (converter , (MappingContext <MongoPersistentEntity <?>, MongoPersistentProperty >) converter .getMappingContext (),
74+ (property ) -> true );
75+ }
76+
77+ @ SuppressWarnings ("unchecked" )
78+ MappingMongoJsonSchemaCreator (MongoConverter converter ,
79+ MappingContext <MongoPersistentEntity <?>, MongoPersistentProperty > mappingContext ,
80+ Predicate <JsonSchemaPropertyContext > filter ) {
81+
6482 Assert .notNull (converter , "Converter must not be null!" );
6583 this .converter = converter ;
66- this .mappingContext = (MappingContext <MongoPersistentEntity <?>, MongoPersistentProperty >) converter
67- .getMappingContext ();
84+ this .mappingContext = mappingContext ;
85+ this .filter = filter ;
86+ }
87+
88+ @ Override
89+ public MongoJsonSchemaCreator filter (Predicate <JsonSchemaPropertyContext > filter ) {
90+ return new MappingMongoJsonSchemaCreator (converter , mappingContext , filter );
6891 }
6992
7093 /*
@@ -77,11 +100,29 @@ public MongoJsonSchema createSchemaFor(Class<?> type) {
77100 MongoPersistentEntity <?> entity = mappingContext .getRequiredPersistentEntity (type );
78101 MongoJsonSchemaBuilder schemaBuilder = MongoJsonSchema .builder ();
79102
103+ {
104+ Encrypted encrypted = entity .findAnnotation (Encrypted .class );
105+ if (encrypted != null ) {
106+
107+ Document encryptionMetadata = new Document ();
108+
109+ Collection <Object > encryptionKeyIds = entity .getEncryptionKeyIds ();
110+ if (!CollectionUtils .isEmpty (encryptionKeyIds )) {
111+ encryptionMetadata .append ("keyId" , encryptionKeyIds );
112+ }
113+
114+ if (StringUtils .hasText (encrypted .algorithm ())) {
115+ encryptionMetadata .append ("algorithm" , encrypted .algorithm ());
116+ }
117+
118+ schemaBuilder .encryptionMetadata (encryptionMetadata );
119+ }
120+ }
121+
80122 List <JsonSchemaProperty > schemaProperties = computePropertiesForEntity (Collections .emptyList (), entity );
81123 schemaBuilder .properties (schemaProperties .toArray (new JsonSchemaProperty [0 ]));
82124
83125 return schemaBuilder .build ();
84-
85126 }
86127
87128 private List <JsonSchemaProperty > computePropertiesForEntity (List <MongoPersistentProperty > path ,
@@ -93,6 +134,11 @@ private List<JsonSchemaProperty> computePropertiesForEntity(List<MongoPersistent
93134
94135 List <MongoPersistentProperty > currentPath = new ArrayList <>(path );
95136
137+ if (!filter .test (new PropertyContext (
138+ currentPath .stream ().map (PersistentProperty ::getName ).collect (Collectors .joining ("." )), nested ))) {
139+ continue ;
140+ }
141+
96142 if (path .contains (nested )) { // cycle guard
97143 schemaProperties .add (createSchemaProperty (computePropertyFieldName (CollectionUtils .lastElement (currentPath )),
98144 Object .class , false ));
@@ -120,15 +166,38 @@ private JsonSchemaProperty computeSchemaForProperty(List<MongoPersistentProperty
120166
121167 String fieldName = computePropertyFieldName (property );
122168
169+ JsonSchemaProperty schemaProperty ;
123170 if (property .isCollectionLike ()) {
124- return createSchemaProperty (fieldName , targetType , required );
171+ schemaProperty = createSchemaProperty (fieldName , targetType , required );
125172 } else if (property .isMap ()) {
126- return createSchemaProperty (fieldName , Type .objectType (), required );
173+ schemaProperty = createSchemaProperty (fieldName , Type .objectType (), required );
127174 } else if (ClassUtils .isAssignable (Enum .class , targetType )) {
128- return createEnumSchemaProperty (fieldName , targetType , required );
175+ schemaProperty = createEnumSchemaProperty (fieldName , targetType , required );
176+ } else {
177+ schemaProperty = createSchemaProperty (fieldName , targetType , required );
129178 }
130179
131- return createSchemaProperty (fieldName , targetType , required );
180+ return applyEncryptionDataIfNecessary (property , schemaProperty );
181+ }
182+
183+ @ Nullable
184+ private JsonSchemaProperty applyEncryptionDataIfNecessary (MongoPersistentProperty property ,
185+ JsonSchemaProperty schemaProperty ) {
186+
187+ Encrypted encrypted = property .findAnnotation (Encrypted .class );
188+ if (encrypted == null ) {
189+ return schemaProperty ;
190+ }
191+
192+ EncryptedJsonSchemaProperty enc = new EncryptedJsonSchemaProperty (schemaProperty );
193+ if (StringUtils .hasText (encrypted .algorithm ())) {
194+ enc = enc .algorithm (encrypted .algorithm ());
195+ }
196+ if (!ObjectUtils .isEmpty (encrypted .keyId ())) {
197+ enc = enc .keys (property .getEncryptionKeyIds ());
198+ }
199+ return enc ;
200+
132201 }
133202
134203 private JsonSchemaProperty createObjectSchemaPropertyForEntity (List <MongoPersistentProperty > path ,
@@ -207,4 +276,30 @@ static JsonSchemaProperty createPotentiallyRequiredSchemaProperty(JsonSchemaProp
207276
208277 return JsonSchemaProperty .required (property );
209278 }
279+
280+ class PropertyContext implements JsonSchemaPropertyContext {
281+
282+ private String path ;
283+ private MongoPersistentProperty property ;
284+
285+ public PropertyContext (String path , MongoPersistentProperty property ) {
286+ this .path = path ;
287+ this .property = property ;
288+ }
289+
290+ @ Override
291+ public String getPath () {
292+ return path ;
293+ }
294+
295+ @ Override
296+ public MongoPersistentProperty getProperty () {
297+ return property ;
298+ }
299+
300+ @ Override
301+ public <T > MongoPersistentEntity <T > resolveEntity (MongoPersistentProperty property ) {
302+ return (MongoPersistentEntity <T >) mappingContext .getPersistentEntity (property );
303+ }
304+ }
210305}
0 commit comments