2424import java .util .Map .Entry ;
2525import java .util .Optional ;
2626import java .util .function .Function ;
27- import java .util .stream .StreamSupport ;
2827
2928import org .bson .BsonBinary ;
3029import org .bson .BsonBinarySubType ;
3130import org .bson .BsonNull ;
3231import org .bson .Document ;
32+
3333import org .springframework .data .mongodb .core .mapping .Field ;
3434import org .springframework .data .mongodb .core .query .Collation ;
3535import org .springframework .data .mongodb .core .schema .IdentifiableJsonSchemaProperty ;
@@ -391,6 +391,7 @@ public CollectionOptions changeStream(CollectionChangeStreamOptions changeStream
391391 *
392392 * @param encryptedFieldsOptions must not be {@literal null}.
393393 * @return new instance of {@link CollectionOptions}.
394+ * @since 4.5
394395 */
395396 @ Contract ("_ -> new" )
396397 @ CheckReturnValue
@@ -708,7 +709,7 @@ public static EncryptedFieldsOptions fromSchema(MongoJsonSchema schema) {
708709 /**
709710 * @return new instance of {@link EncryptedFieldsOptions}.
710711 */
711- public static EncryptedFieldsOptions fromProperties (List <JsonSchemaProperty > properties ) {
712+ public static EncryptedFieldsOptions fromProperties (List <? extends JsonSchemaProperty > properties ) {
712713 return new EncryptedFieldsOptions (null , List .copyOf (properties ));
713714 }
714715
@@ -740,6 +741,7 @@ public EncryptedFieldsOptions queryable(JsonSchemaProperty property, QueryCharac
740741 *
741742 * @param property must not be {@literal null}.
742743 * @return new instance of {@link EncryptedFieldsOptions}.
744+ * @since 4.5.1
743745 */
744746 @ Contract ("_ -> new" )
745747 @ CheckReturnValue
@@ -748,24 +750,26 @@ public EncryptedFieldsOptions with(EncryptedJsonSchemaProperty property) {
748750 }
749751
750752 /**
751- * Add a {@link JsonSchemaProperty property} that should not be encrypted but not queryable.
753+ * Add a {@link JsonSchemaProperty property} that should be encrypted but not queryable.
752754 *
753755 * @param property must not be {@literal null}.
754- * @param key can be {@literal null}.
756+ * @param keyId the key identifier to be used, can be {@literal null}.
755757 * @return new instance of {@link EncryptedFieldsOptions}.
758+ * @since 4.5.1
756759 */
757760 @ Contract ("_, _ -> new" )
758761 @ CheckReturnValue
759- public EncryptedFieldsOptions encrypted (JsonSchemaProperty property , @ Nullable Object key ) {
762+ public EncryptedFieldsOptions encrypted (JsonSchemaProperty property , @ Nullable Object keyId ) {
760763
761764 List <JsonSchemaProperty > targetPropertyList = new ArrayList <>(properties .size () + 1 );
762765 targetPropertyList .addAll (properties );
766+
763767 if (property instanceof IdentifiableJsonSchemaProperty .EncryptedJsonSchemaProperty ) {
764768 targetPropertyList .add (property );
765769 } else {
766770 EncryptedJsonSchemaProperty encryptedJsonSchemaProperty = new EncryptedJsonSchemaProperty (property );
767- if (key != null ) {
768- targetPropertyList .add (encryptedJsonSchemaProperty .keyId (key ));
771+ if (keyId != null ) {
772+ targetPropertyList .add (encryptedJsonSchemaProperty .keyId (keyId ));
769773 }
770774 }
771775
@@ -796,45 +800,48 @@ private List<Document> fromProperties() {
796800
797801 List <Document > converted = new ArrayList <>(properties .size ());
798802 for (JsonSchemaProperty property : properties ) {
803+ converted .add (getEncryptedField (property ));
804+ }
805+ return converted ;
806+ }
799807
800- Document field = new Document ( "path" , property . getIdentifier ());
808+ private Document getEncryptedField ( JsonSchemaProperty property ) {
801809
802- if (!property .getTypes ().isEmpty ()) {
803- field .append ("bsonType" , property .getTypes ().iterator ().next ().toBsonType ().value ());
804- }
810+ Document field = new Document ("path" , property .getIdentifier ());
805811
806- if (property instanceof QueryableJsonSchemaProperty qproperty && qproperty
807- .getTargetProperty () instanceof IdentifiableJsonSchemaProperty .EncryptedJsonSchemaProperty encrypted ) {
808- if (encrypted .getKeyId () != null ) {
809- if (encrypted .getKeyId () instanceof String stringKey ) {
810- field .append ("keyId" ,
811- new BsonBinary (BsonBinarySubType .UUID_STANDARD , stringKey .getBytes (StandardCharsets .UTF_8 )));
812- } else {
813- field .append ("keyId" , encrypted .getKeyId ());
814- }
815- }
816- } else if (property instanceof IdentifiableJsonSchemaProperty .EncryptedJsonSchemaProperty encrypted ) {
817- if (encrypted .getKeyId () != null ) {
818- if (encrypted .getKeyId () instanceof String stringKey ) {
819- field .append ("keyId" ,
820- new BsonBinary (BsonBinarySubType .UUID_STANDARD , stringKey .getBytes (StandardCharsets .UTF_8 )));
821- } else {
822- field .append ("keyId" , encrypted .getKeyId ());
823- }
824- }
825- }
812+ if (!property .getTypes ().isEmpty ()) {
813+ field .append ("bsonType" , property .getTypes ().iterator ().next ().toBsonType ().value ());
814+ }
815+
816+ if (property instanceof QueryableJsonSchemaProperty qp
817+ && qp .getTargetProperty () instanceof IdentifiableJsonSchemaProperty .EncryptedJsonSchemaProperty encrypted
818+ && encrypted .getKeyId () != null ) {
826819
827- if (property instanceof QueryableJsonSchemaProperty qproperty ) {
828- field .append ("queries" , StreamSupport .stream (qproperty .getCharacteristics ().spliterator (), false )
829- .map (QueryCharacteristic ::toDocument ).toList ());
820+ if (encrypted .getKeyId () instanceof String stringKey ) {
821+ field .append ("keyId" ,
822+ new BsonBinary (BsonBinarySubType .UUID_STANDARD , stringKey .getBytes (StandardCharsets .UTF_8 )));
823+ } else {
824+ field .append ("keyId" , encrypted .getKeyId ());
830825 }
831- if (!field .containsKey ("keyId" )) {
832- field .append ("keyId" , BsonNull .VALUE );
826+ } else if (property instanceof IdentifiableJsonSchemaProperty .EncryptedJsonSchemaProperty encrypted
827+ && encrypted .getKeyId () != null ) {
828+ if (encrypted .getKeyId () instanceof String stringKey ) {
829+ field .append ("keyId" ,
830+ new BsonBinary (BsonBinarySubType .UUID_STANDARD , stringKey .getBytes (StandardCharsets .UTF_8 )));
831+ } else {
832+ field .append ("keyId" , encrypted .getKeyId ());
833833 }
834+ }
834835
835- converted .add (field );
836+ if (property instanceof QueryableJsonSchemaProperty qp ) {
837+ field .append ("queries" , qp .getCharacteristics ().map (QueryCharacteristic ::toDocument ).toList ());
836838 }
837- return converted ;
839+
840+ if (!field .containsKey ("keyId" )) {
841+ field .append ("keyId" , BsonNull .VALUE );
842+ }
843+
844+ return field ;
838845 }
839846
840847 private List <Document > fromSchema () {
@@ -848,19 +855,25 @@ private List<Document> fromSchema() {
848855 collectPaths (root , null , paths );
849856
850857 List <Document > fields = new ArrayList <>();
851- if (!paths .isEmpty ()) {
858+ if (paths .isEmpty ()) {
859+ return fields ;
860+ }
852861
853- for (Entry <String , Document > entry : paths .entrySet ()) {
854- Document field = new Document ("path" , entry .getKey ());
855- field .append ("keyId" , entry .getValue ().getOrDefault ("keyId" , BsonNull .VALUE ));
856- if (entry .getValue ().containsKey ("bsonType" )) {
857- field .append ("bsonType" , entry .getValue ().get ("bsonType" ));
858- }
859- if (entry .getValue ().containsKey ("queries" )) {
860- field .put ("queries" , entry .getValue ().get ("queries" ));
861- }
862- fields .add (field );
862+ for (Entry <String , Document > entry : paths .entrySet ()) {
863+
864+ Document field = new Document ("path" , entry .getKey ());
865+
866+ field .append ("keyId" , entry .getValue ().getOrDefault ("keyId" , BsonNull .VALUE ));
867+
868+ if (entry .getValue ().containsKey ("bsonType" )) {
869+ field .append ("bsonType" , entry .getValue ().get ("bsonType" ));
870+ }
871+
872+ if (entry .getValue ().containsKey ("queries" )) {
873+ field .put ("queries" , entry .getValue ().get ("queries" ));
863874 }
875+
876+ fields .add (field );
864877 }
865878
866879 return fields ;
@@ -870,28 +883,29 @@ private List<Document> fromSchema() {
870883 private static void collectPaths (Document document , @ Nullable String currentPath , Map <String , Document > paths ) {
871884
872885 if (document .containsKey ("type" ) && document .get ("type" ).equals ("object" )) {
886+
873887 Object o = document .get ("properties" );
874- if (o == null ) {
888+
889+ if (!(o instanceof Document properties )) {
875890 return ;
876891 }
877892
878- if (o instanceof Document properties ) {
879- for (Entry <String , Object > entry : properties .entrySet ()) {
880- if (entry .getValue () instanceof Document nested ) {
881-
882- String path = currentPath == null ? entry .getKey () : (currentPath + "." + entry .getKey ());
883- if (nested .containsKey ("encrypt" )) {
884- Document target = new Document (nested .get ("encrypt" , Document .class ));
885- if (nested .containsKey ("queries" )) {
886- List <?> queries = nested .get ("queries" , List .class );
887- if (!queries .isEmpty () && queries .iterator ().next () instanceof Document qd ) {
888- target .putAll (qd );
889- }
893+ for (Entry <String , Object > entry : properties .entrySet ()) {
894+
895+ if (entry .getValue () instanceof Document nested ) {
896+
897+ String path = currentPath == null ? entry .getKey () : (currentPath + "." + entry .getKey ());
898+ if (nested .containsKey ("encrypt" )) {
899+ Document target = new Document (nested .get ("encrypt" , Document .class ));
900+ if (nested .containsKey ("queries" )) {
901+ List <?> queries = nested .get ("queries" , List .class );
902+ if (!queries .isEmpty () && queries .iterator ().next () instanceof Document qd ) {
903+ target .putAll (qd );
890904 }
891- paths .put (path , target );
892- } else {
893- collectPaths (nested , path , paths );
894905 }
906+ paths .put (path , target );
907+ } else {
908+ collectPaths (nested , path , paths );
895909 }
896910 }
897911 }
0 commit comments