@@ -711,6 +711,72 @@ void readAndWriteIndexWithSimpleEvaluationContext() {
711
711
assertThat (expr .getValue (context , arrayNode )).isSameAs (node1 );
712
712
}
713
713
714
+ @ Test // gh-32706
715
+ void readIndexWithStringIndexType () {
716
+ BirdNameToColorMappings birdNameMappings = new BirdNameToColorMappings ();
717
+
718
+ // Without a registered BirdNameToColorMappingsIndexAccessor, we should
719
+ // be able to index into an object via a property name.
720
+ Expression propertyExpression = parser .parseExpression ("['property']" );
721
+ assertThat (propertyExpression .getValue (context , birdNameMappings )).isEqualTo ("enigma" );
722
+
723
+ context .addIndexAccessor (new BirdNameToColorMappingsIndexAccessor ());
724
+
725
+ Expression expression = parser .parseExpression ("['cardinal']" );
726
+ assertThat (expression .getValue (context , birdNameMappings )).isEqualTo (Color .RED );
727
+
728
+ // With a registered BirdNameToColorMappingsIndexAccessor, an attempt
729
+ // to index into an object via a property name should fail.
730
+ assertThatExceptionOfType (SpelEvaluationException .class )
731
+ .isThrownBy (() -> propertyExpression .getValue (context , birdNameMappings ))
732
+ .withMessageEndingWith ("A problem occurred while attempting to read index '%s' in '%s'" ,
733
+ "property" , BirdNameToColorMappings .class .getName ())
734
+ .havingCause ().withMessage ("unknown bird color: property" );
735
+ }
736
+
737
+ static class BirdNameToColorMappings {
738
+
739
+ public final String property = "enigma" ;
740
+
741
+ public Color get (String name ) {
742
+ return switch (name ) {
743
+ case "cardinal" -> Color .RED ;
744
+ case "blue jay" -> Color .BLUE ;
745
+ default -> throw new RuntimeException ("unknown bird color: " + name );
746
+ };
747
+ }
748
+ }
749
+
750
+ static class BirdNameToColorMappingsIndexAccessor implements IndexAccessor {
751
+
752
+ @ Override
753
+ public Class <?>[] getSpecificTargetClasses () {
754
+ return new Class [] { BirdNameToColorMappings .class };
755
+ }
756
+
757
+ @ Override
758
+ public boolean canRead (EvaluationContext context , Object target , Object index ) {
759
+ return (target instanceof BirdNameToColorMappings && index instanceof String );
760
+ }
761
+
762
+ @ Override
763
+ public TypedValue read (EvaluationContext context , Object target , Object index ) {
764
+ BirdNameToColorMappings mappings = (BirdNameToColorMappings ) target ;
765
+ String name = (String ) index ;
766
+ return new TypedValue (mappings .get (name ));
767
+ }
768
+
769
+ @ Override
770
+ public boolean canWrite (EvaluationContext context , Object target , Object index ) {
771
+ return false ;
772
+ }
773
+
774
+ @ Override
775
+ public void write (EvaluationContext context , Object target , Object index , @ Nullable Object newValue ) {
776
+ throw new UnsupportedOperationException ();
777
+ }
778
+ }
779
+
714
780
/**
715
781
* {@link IndexAccessor} that knows how to read and write indexes in a
716
782
* Jackson {@link ArrayNode}.
0 commit comments