@@ -106,7 +106,7 @@ public QueryMapper(MongoConverter converter) {
106106 public DBObject getMappedObject (DBObject query , MongoPersistentEntity <?> entity ) {
107107
108108 if (isNestedKeyword (query )) {
109- return getMappedKeyword (keywordFor (query , entity , mappingContext ), entity );
109+ return getMappedKeyword (keywordFor (query , entity , null , mappingContext ), entity );
110110 }
111111
112112 DBObject result = new BasicDBObject ();
@@ -124,8 +124,7 @@ public DBObject getMappedObject(DBObject query, MongoPersistentEntity<?> entity)
124124 }
125125
126126 if (isKeyword (key )) {
127- result .putAll (getMappedKeyword (new Keyword (query , key , new KeywordContext (null , entity , mappingContext )),
128- entity ));
127+ result .putAll (getMappedKeyword (keywordFor (key , query .get (key ), entity , null , mappingContext ), entity ));
129128 continue ;
130129 }
131130
@@ -531,41 +530,17 @@ protected boolean isKeyword(String candidate) {
531530 static class Keyword {
532531
533532 private static final String N_OR_PATTERN = "\\ $.*or" ;
534- private List <Validator > validators ;
535533 private final String key ;
536534 private final Object value ;
537535 private final KeywordContext context ;
536+ private final List <Validator > validators ;
538537
539- private static final Validator MIN_OPERATOR_VALIDATOR = KeywordParameterTypeValidator .whitelist (Byte .class ,
540- Short .class , Integer .class , Long .class , Float .class , Double .class , Date .class );
541-
542- public Keyword (DBObject dbo , KeywordContext context ) {
543- this (dbo , assertAndReturnOnlySingleKey (dbo ), context );
544- }
545-
546- public Keyword (DBObject dbo , String key , KeywordContext context ) {
538+ public Keyword (String key , Object value , KeywordContext context , List <Validator > validators ) {
547539
548540 this .key = key ;
549- this .value = dbo . get ( key ) ;
541+ this .value = value ;
550542 this .context = context ;
551- this .validators = createValidators (key );
552- }
553-
554- private List <Validator > createValidators (String key ) {
555-
556- if (key .equalsIgnoreCase ("$min" )) {
557- return Arrays .asList (MIN_OPERATOR_VALIDATOR );
558- }
559-
560- return Collections .<Validator > emptyList ();
561- }
562-
563- static String assertAndReturnOnlySingleKey (DBObject dbo ) {
564-
565- Set <String > keys = dbo .keySet ();
566- Assert .isTrue (keys .size () == 1 , "Can only use a single value DBObject!" );
567-
568- return keys .iterator ().next ();
543+ this .validators = validators ;
569544 }
570545
571546 /**
@@ -682,24 +657,55 @@ public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentPropert
682657 * @author Christoph Strobl
683658 * @since 1.7
684659 */
685- static class KeywordFactory {
660+ static enum KeywordFactory {
661+
662+ INSTANCE ;
663+
664+ private static final Validator VALID_MIN_OPERATOR_TYPES_VALIDATOR = KeywordParameterTypeValidator .whitelist (
665+ Byte .class , Short .class , Integer .class , Long .class , Float .class , Double .class , Date .class );
686666
687667 static Keyword keywordFor (DBObject source ,
688668 MappingContext <? extends MongoPersistentEntity <?>, MongoPersistentProperty > mappingContext ) {
689- return keywordFor (source , (MongoPersistentEntity <?>) null , mappingContext );
669+ return keywordFor (source , (MongoPersistentEntity <?>) null , null , mappingContext );
690670 }
691671
692- static Keyword keywordFor (DBObject source , MongoPersistentEntity <?> entity ,
672+ static Keyword keywordFor (DBObject source , MongoPersistentProperty property ,
693673 MappingContext <? extends MongoPersistentEntity <?>, MongoPersistentProperty > mappingContext ) {
694- return new Keyword (source , new KeywordContext ( null , entity , mappingContext ) );
674+ return keywordFor (source , null , property , mappingContext );
695675 }
696676
697- static Keyword keywordFor (DBObject source , MongoPersistentProperty property ,
677+ static Keyword keywordFor (DBObject source , MongoPersistentEntity <?> entity , MongoPersistentProperty property ,
698678 MappingContext <? extends MongoPersistentEntity <?>, MongoPersistentProperty > mappingContext ) {
699679
700- KeywordContext context = new KeywordContext (property , property == null ? null
680+ String key = assertAndReturnOnlySingleKey (source );
681+ return keywordFor (key , source .get (key ), entity , property , mappingContext );
682+ }
683+
684+ static Keyword keywordFor (String key , Object value , MongoPersistentEntity <?> entity ,
685+ MongoPersistentProperty property ,
686+ MappingContext <? extends MongoPersistentEntity <?>, MongoPersistentProperty > mappingContext ) {
687+
688+ KeywordContext context = new KeywordContext (property , property == null ? entity
701689 : (MongoPersistentEntity <?>) property .getOwner (), mappingContext );
702- return new Keyword (source , context );
690+
691+ return new Keyword (key , value , context , INSTANCE .getValidatorsFor (key ));
692+ }
693+
694+ private List <Validator > getValidatorsFor (String key ) {
695+
696+ if (key .equalsIgnoreCase ("$min" )) {
697+ return Arrays .asList (VALID_MIN_OPERATOR_TYPES_VALIDATOR );
698+ }
699+
700+ return Collections .<Validator > emptyList ();
701+ }
702+
703+ static String assertAndReturnOnlySingleKey (DBObject dbo ) {
704+
705+ Set <String > keys = dbo .keySet ();
706+ Assert .isTrue (keys .size () == 1 , "Can only use a single value DBObject!" );
707+
708+ return keys .iterator ().next ();
703709 }
704710 }
705711
@@ -732,21 +738,25 @@ public void validate(Object target, Errors errors) {
732738 */
733739 static class KeywordParameterTypeValidator extends KeywordValidator {
734740
741+ enum Mode {
742+ WHITE_LIST , BLACK_LIST ;
743+ }
744+
735745 private final Set <Class <?>> types ;
736- private final boolean invert ;
746+ private final Mode mode ;
737747
738- private KeywordParameterTypeValidator (boolean invert , Class <?>... supportedTypes ) {
748+ private KeywordParameterTypeValidator (Mode mode , Class <?>... supportedTypes ) {
739749
740- this .invert = invert ;
750+ this .mode = mode ;
741751 this .types = new HashSet <Class <?>>(Arrays .asList (supportedTypes ));
742752 }
743753
744754 public static KeywordParameterTypeValidator whitelist (Class <?>... supportedTypes ) {
745- return new KeywordParameterTypeValidator (false , supportedTypes );
755+ return new KeywordParameterTypeValidator (Mode . WHITE_LIST , supportedTypes );
746756 }
747757
748758 public static KeywordParameterTypeValidator blacklist (Class <?>... unsupportedTypes ) {
749- return new KeywordParameterTypeValidator (true , unsupportedTypes );
759+ return new KeywordParameterTypeValidator (Mode . BLACK_LIST , unsupportedTypes );
750760 }
751761
752762 private void doValidate (Object candidate , Errors errors ) {
@@ -768,15 +778,11 @@ private void doValidate(Object candidate, Errors errors) {
768778
769779 Class <?> typeToValidate = ClassUtils .isAssignable (MongoPersistentProperty .class , candidate .getClass ()) ? ((MongoPersistentProperty ) candidate )
770780 .getActualType () : candidate .getClass ();
781+ boolean givenTypeContainedInTypes = types .contains (ClassUtils .resolvePrimitiveIfNecessary (typeToValidate ));
771782
772- if (types .contains (ClassUtils .resolvePrimitiveIfNecessary (typeToValidate ))) {
773- if (invert ) {
774- errors .reject ("" , String .format ("Using %s is not supported for %s." , typeToValidate , errors .getObjectName ()));
775- }
776- } else {
777- if (!invert ) {
778- errors .reject ("" , String .format ("Using %s is not supported for %s." , typeToValidate , errors .getObjectName ()));
779- }
783+ if ((Mode .BLACK_LIST .equals (mode ) && givenTypeContainedInTypes )
784+ || (Mode .WHITE_LIST .equals (mode ) && !givenTypeContainedInTypes )) {
785+ errors .reject ("" , String .format ("Using %s is not supported for %s." , typeToValidate , errors .getObjectName ()));
780786 }
781787 }
782788
@@ -791,53 +797,58 @@ public void validate(Keyword target, Errors errors) {
791797 return ;
792798 }
793799
794- if (target .isDBObjectValue ()) {
800+ if (! target .isDBObjectValue ()) {
795801
796- DBObject dbo = ( DBObject ) target . getValue ();
802+ MongoPersistentProperty propertyToUse = target . getContext (). getProperty ();
797803
798- Iterator <?> keysIterator = dbo .toMap ().keySet ().iterator ();
799- while (keysIterator .hasNext ()) {
804+ if (propertyToUse == null && target .getContext ().getEntity () != null ) {
805+ propertyToUse = target .getContext ().getEntity ().getPersistentProperty (errors .getObjectName ());
806+ }
800807
801- String propertyName = keysIterator .next ().toString ();
808+ doValidate (propertyToUse , errors );
809+ return ;
810+ }
802811
803- if (StringUtils .countOccurrencesOf (propertyName , "." ) == 0 ) {
804- doValidate (target .getContext ().getEntity ().getPersistentProperty (propertyName ), errors );
805- continue ;
806- }
812+ DBObject dbo = (DBObject ) target .getValue ();
807813
808- MongoPersistentEntity <?> propertyScope = target .getContext ().getEntity ();
814+ Iterator <?> keysIterator = dbo .keySet ().iterator ();
815+ while (keysIterator .hasNext ()) {
816+ validatePropertyPath (keysIterator .next ().toString (), target .getContext (), errors );
817+ }
818+ }
809819
810- Iterator <String > partsIterator = Arrays .asList (propertyName .split ("\\ ." )).iterator ();
811- while (partsIterator .hasNext ()) {
820+ private void validatePropertyPath (String propertyPath , KeywordContext context , Errors errors ) {
812821
813- MongoPersistentProperty property = (MongoPersistentProperty ) propertyScope
814- .getPersistentProperty (partsIterator .next ());
822+ if (StringUtils .countOccurrencesOf (propertyPath , "." ) == 0 ) {
823+ doValidate (context .getEntity ().getPersistentProperty (propertyPath ), errors );
824+ return ;
825+ }
815826
816- if (!partsIterator .hasNext ()) {
817- doValidate (property , errors );
818- continue ;
819- }
827+ MongoPersistentEntity <?> persistentEntity = context .getEntity ();
820828
821- if (property != null && property .isEntity () && partsIterator .hasNext ()) {
829+ Iterator <String > partsIterator = Arrays .asList (propertyPath .split ("\\ ." )).iterator ();
830+ while (partsIterator .hasNext ()) {
822831
823- propertyScope = target .getContext ().getMappingContext ().getPersistentEntity (property .getActualType ());
832+ MongoPersistentProperty persistentProperty = (MongoPersistentProperty ) persistentEntity
833+ .getPersistentProperty (partsIterator .next ());
824834
825- if (propertyScope == null ) {
826- break ;
827- }
828- }
829- }
835+ if (persistentProperty == null ) {
836+ continue ;
837+ }
830838
839+ if (!partsIterator .hasNext ()) {
840+ doValidate (persistentProperty , errors );
841+ return ;
831842 }
832- } else {
833843
834- MongoPersistentProperty propertyToUse = target . getContext (). getProperty ();
844+ if ( persistentProperty . isEntity () && partsIterator . hasNext ()) {
835845
836- if (propertyToUse == null && target .getContext ().getEntity () != null ) {
837- propertyToUse = target .getContext ().getEntity ().getPersistentProperty (errors .getObjectName ());
838- }
846+ persistentEntity = context .getMappingContext ().getPersistentEntity (persistentProperty .getActualType ());
839847
840- doValidate (propertyToUse , errors );
848+ if (persistentEntity == null ) {
849+ return ;
850+ }
851+ }
841852 }
842853 }
843854 }
0 commit comments