@@ -2958,6 +2958,103 @@ public void failsWhenSettingContextForExpression_SPR12326() {
2958
2958
assertTrue (expression .getValue (Boolean .class ));
2959
2959
}
2960
2960
2961
+
2962
+ /**
2963
+ * Test variants of using T(...) and static/non-static method/property/field references.
2964
+ */
2965
+ @ Test
2966
+ public void constructorReference_SPR13781 () {
2967
+ // Static field access on a T() referenced type
2968
+ expression = parser .parseExpression ("T(java.util.Locale).ENGLISH" );
2969
+ assertEquals ("en" ,expression .getValue ().toString ());
2970
+ assertCanCompile (expression );
2971
+ assertEquals ("en" ,expression .getValue ().toString ());
2972
+
2973
+ // The actual expression from the bug report. It fails if the ENGLISH reference fails
2974
+ // to pop the type reference for Locale off the stack (if it isn't popped then
2975
+ // toLowerCase() will be called with a Locale parameter). In this situation the
2976
+ // code generation for ENGLISH should notice there is something on the stack that
2977
+ // is not required and pop it off.
2978
+ expression = parser .parseExpression ("#userId.toString().toLowerCase(T(java.util.Locale).ENGLISH)" );
2979
+ StandardEvaluationContext context =
2980
+ new StandardEvaluationContext ();
2981
+ context .setVariable ("userId" , "RoDnEy" );
2982
+ assertEquals ("rodney" ,expression .getValue (context ));
2983
+ assertCanCompile (expression );
2984
+ assertEquals ("rodney" ,expression .getValue (context ));
2985
+
2986
+ // Property access on a class object
2987
+ expression = parser .parseExpression ("T(String).name" );
2988
+ assertEquals ("java.lang.String" ,expression .getValue ());
2989
+ assertCanCompile (expression );
2990
+ assertEquals ("java.lang.String" ,expression .getValue ());
2991
+
2992
+ // Now the type reference isn't on the stack, and needs loading
2993
+ context = new StandardEvaluationContext (String .class );
2994
+ expression = parser .parseExpression ("name" );
2995
+ assertEquals ("java.lang.String" ,expression .getValue (context ));
2996
+ assertCanCompile (expression );
2997
+ assertEquals ("java.lang.String" ,expression .getValue (context ));
2998
+
2999
+ expression = parser .parseExpression ("T(String).getName()" );
3000
+ assertEquals ("java.lang.String" ,expression .getValue ());
3001
+ assertCanCompile (expression );
3002
+ assertEquals ("java.lang.String" ,expression .getValue ());
3003
+
3004
+ // These tests below verify that the chain of static accesses (either method/property or field)
3005
+ // leave the right thing on top of the stack for processing by any outer consuming code.
3006
+ // Here the consuming code is the String.valueOf() function. If the wrong thing were on
3007
+ // the stack (for example if the compiled code for static methods wasn't popping the
3008
+ // previous thing off the stack) the valueOf() would operate on the wrong value.
3009
+
3010
+ String shclass = StaticsHelper .class .getName ();
3011
+ // Basic chain: property access then method access
3012
+ expression = parser .parseExpression ("T(String).valueOf(T(String).name.valueOf(1))" );
3013
+ assertEquals ("1" ,expression .getValue ());
3014
+ assertCanCompile (expression );
3015
+ assertEquals ("1" ,expression .getValue ());
3016
+
3017
+ // chain of statics ending with static method
3018
+ expression = parser .parseExpression ("T(String).valueOf(T(" +shclass +").methoda().methoda().methodb())" );
3019
+ assertEquals ("mb" ,expression .getValue ());
3020
+ assertCanCompile (expression );
3021
+ assertEquals ("mb" ,expression .getValue ());
3022
+
3023
+ // chain of statics ending with static field
3024
+ expression = parser .parseExpression ("T(String).valueOf(T(" +shclass +").fielda.fielda.fieldb)" );
3025
+ assertEquals ("fb" ,expression .getValue ());
3026
+ assertCanCompile (expression );
3027
+ assertEquals ("fb" ,expression .getValue ());
3028
+
3029
+ // chain of statics ending with static property access
3030
+ expression = parser .parseExpression ("T(String).valueOf(T(" +shclass +").propertya.propertya.propertyb)" );
3031
+ assertEquals ("pb" ,expression .getValue ());
3032
+ assertCanCompile (expression );
3033
+ assertEquals ("pb" ,expression .getValue ());
3034
+
3035
+ // variety chain
3036
+ expression = parser .parseExpression ("T(String).valueOf(T(" +shclass +").fielda.methoda().propertya.fieldb)" );
3037
+ assertEquals ("fb" ,expression .getValue ());
3038
+ assertCanCompile (expression );
3039
+ assertEquals ("fb" ,expression .getValue ());
3040
+
3041
+ expression = parser .parseExpression ("T(String).valueOf(fielda.fieldb)" );
3042
+ assertEquals ("fb" ,expression .getValue (StaticsHelper .sh ));
3043
+ assertCanCompile (expression );
3044
+ assertEquals ("fb" ,expression .getValue (StaticsHelper .sh ));
3045
+
3046
+ expression = parser .parseExpression ("T(String).valueOf(propertya.propertyb)" );
3047
+ assertEquals ("pb" ,expression .getValue (StaticsHelper .sh ));
3048
+ assertCanCompile (expression );
3049
+ assertEquals ("pb" ,expression .getValue (StaticsHelper .sh ));
3050
+
3051
+ expression = parser .parseExpression ("T(String).valueOf(methoda().methodb())" );
3052
+ assertEquals ("mb" ,expression .getValue (StaticsHelper .sh ));
3053
+ assertCanCompile (expression );
3054
+ assertEquals ("mb" ,expression .getValue (StaticsHelper .sh ));
3055
+
3056
+ }
3057
+
2961
3058
@ Test
2962
3059
public void constructorReference_SPR12326 () {
2963
3060
String type = this .getClass ().getName ();
@@ -5341,4 +5438,29 @@ public static String format(String s, Object... args) {
5341
5438
}
5342
5439
}
5343
5440
5441
+ public static class StaticsHelper {
5442
+ static StaticsHelper sh = new StaticsHelper ();
5443
+ public static StaticsHelper methoda () {
5444
+ return sh ;
5445
+ }
5446
+ public static String methodb () {
5447
+ return "mb" ;
5448
+ }
5449
+
5450
+ public static StaticsHelper getPropertya () {
5451
+ return sh ;
5452
+ }
5453
+
5454
+ public static String getPropertyb () {
5455
+ return "pb" ;
5456
+ }
5457
+
5458
+
5459
+ public static StaticsHelper fielda = sh ;
5460
+ public static String fieldb = "fb" ;
5461
+
5462
+ public String toString () {
5463
+ return "sh" ;
5464
+ }
5465
+ }
5344
5466
}
0 commit comments