Velocity
  1. Velocity
  2. VELOCITY-818

Case-insensitive matching ${object.methodName} == ${object.methodname} == ${object.methodName}

    Details

    • Type: New Feature New Feature
    • Status: Closed
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: 1.7
    • Fix Version/s: None
    • Component/s: Engine
    • Labels:

      Description

      I thought I would share the following code with the Apache Velocity community.

      Currently there is no easy way for Velocity to do a case-insensitive match on a property or method. Below is my implementation to achieve this.

      VelocityContext velocityContext = new VelocityContext();

      { context.put( "aNumericValue", "1234567890" ); }


      | If String template = | Then String evaluatedTemplate = |
      | ${aNumericValue} | 1234567890 |
      | ${anumericvalue} | 1234567890 |
      | ${anumericValue} | 1234567890 |
      | ${aNumericvalue} | 1234567890 |
      | ${aNumericValue.toString()} | 1234567890 |
      | ${anumericvalue.tostring()} | 1234567890 |



      – Setup Snippet –
      Properties p = new Properties();

      p.setProperty( RuntimeConstants.INPUT_ENCODING, DEFAULT_ENCODING );
      p.setProperty( RuntimeConstants.OUTPUT_ENCODING, DEFAULT_ENCODING );

      p.setProperty( RuntimeConstants.UBERSPECT_CLASSNAME,
      "custom.CustomSecureUberspector" ); //$NON-NLS-1$

      VelocityEngine engine = new VelocityEngine( p );
      engine.init();

      RuntimeInstance ri = new RuntimeInstance();
      ri.init( p );
      uberspector = (CustomSecureUberspector)ri.getUberspect();


      – Setup Snippet –


      – Call Snippet –
      VelocityContext velocityContext = new VelocityContext();{ context.put( "aNumericValue", "1234567890" ); }

      EventCartridge eventCartridge = new EventCartridge();
      eventCartridge.addEventHandler( new SloppyNameReferenceEventHandler( uberspector ) );
      eventCartridge.addEventHandler( new NullValueReferenceInsertionEventHandler() );
      eventCartridge.attachToContext( velocityContext );

      String template = "$

      {aNumericvalue}

      ";
      StringWriter velocityWriter = new StringWriter();
      velocityEngine.evaluate( velocityContext, velocityWriter, "LOG", template );
      String evaluatedTemplate = velocityWriter.toString();

      – Call Snippet –

      – Supporting Classes Snippet –

      package custom;

      import org.apache.velocity.util.introspection.SecureIntrospectorImpl;
      import org.apache.velocity.util.introspection.SecureUberspector;

      public class CustomSecureUberspector extends SecureUberspector
      {
      public SecureIntrospectorImpl getSecureIntrospector()

      { return (SecureIntrospectorImpl)introspector; }

      }

      package custom;

      import java.lang.reflect.Method;
      import java.util.ArrayList;
      import java.util.List;

      import org.apache.velocity.app.event.InvalidReferenceEventHandler;
      import org.apache.velocity.context.Context;
      import org.apache.velocity.util.introspection.Info;
      import org.apache.velocity.util.introspection.SecureIntrospectorImpl;

      import custom.CustomSecureUberspector;

      @SuppressWarnings(

      { "unused" }

      )
      public class SloppyNameReferenceEventHandler implements InvalidReferenceEventHandler
      {

      protected CustomSecureUberspector uberspector;

      public SloppyNameReferenceEventHandler( CustomSecureUberspector uberspector )

      { this.uberspector = uberspector; }

      @Override
      public Object invalidGetMethod( Context context, String reference, Object object, String property, Info info )
      {

      try

      { return callMethod( object, property ); }

      catch ( Exception e )

      { return null; }

      }


      @Override
      public boolean invalidSetMethod( Context context, String leftReference, String rightReference, Info info )
      { // Do nothing return false; }


      @Override
      public Object invalidMethod( Context context, String reference, Object object, String method, Info info )
      {

      try
      { return callMethod( object, method ); }
      catch ( Exception e )
      { return null; }

      }

      protected Object callMethod( Object object, String method )
      throws Exception
      {
      if ( null == object || null == method )

      { return null; }

      List<String> possibleMethodMatches = findCaseInsensitiveMethodsForObject( object, method, "get" + method ); //$NON-NLS-1$

      SecureIntrospectorImpl secureIntrospectorImpl = uberspector.getSecureIntrospector();

      for ( String possibleMethodMatch : possibleMethodMatches )
      {
      if ( secureIntrospectorImpl.checkObjectExecutePermission( object.getClass(), possibleMethodMatch ) )
      {
      Method[] objectMethods = object.getClass().getMethods();
      for ( int i = 0; i < objectMethods.length; i++ )
      {
      if ( possibleMethodMatch.equals( objectMethods[i].getName() ) )

      { return objectMethods[i].invoke( object ); }

      }
      }
      }

      return null;
      }

      @SuppressWarnings( "static-method" )
      protected List<String> findCaseInsensitiveMethodsForObject( Object object, String ... methodNames )
      {
      List<String> methodMatches = new ArrayList<String>();

      Method[] methods = object.getClass().getMethods();
      for ( int i = 0; i < methods.length; i++ )
      {

      String objectMethodName = methods[i].getName();
      String objectMethodNameInLowerCase = objectMethodName.toLowerCase();

      for ( int j = 0; j < methodNames.length; j++ )
      {
      if ( objectMethodNameInLowerCase.equals( methodNames[j].toLowerCase() ) )

      { methodMatches.add( objectMethodName ); }

      }

      }

      return methodMatches;
      }

      }

      package custom;

      import org.apache.velocity.app.event.ReferenceInsertionEventHandler;

      public class NullValueReferenceInsertionEventHandler implements ReferenceInsertionEventHandler
      {

      @Override
      public Object referenceInsert( String reference, Object value )
      {

      if ( null == value )

      { return String.valueOf( reference ); }

      return value;

      }
      }

      – Supporting Classes Snippet –

        Activity

        Mark S created issue -
        Hide
        Mike Kienenberger added a comment -

        It seems unlikely that Velocity will directly support case-insensitive method and property names since java treats such methods and property names as case-sensitive and distinct.

        Your example of

        Case-insensitive matching $

        {object.methodName}

        == $

        {object.methodname}

        fails to account for the possibility that both of these methods could exist on the same object.

        public String getMethodName();
        public String getMethodname();

        I'm going to mark this as won't fix.

        Show
        Mike Kienenberger added a comment - It seems unlikely that Velocity will directly support case-insensitive method and property names since java treats such methods and property names as case-sensitive and distinct. Your example of Case-insensitive matching $ {object.methodName} == $ {object.methodname} fails to account for the possibility that both of these methods could exist on the same object. public String getMethodName(); public String getMethodname(); I'm going to mark this as won't fix.
        Mike Kienenberger made changes -
        Field Original Value New Value
        Resolution Won't Fix [ 2 ]
        Status Open [ 1 ] Closed [ 6 ]
        Hide
        Sergiu Dumitriu added a comment -

        I agree that it doesn't make sense as a default language feature, but this could be an optional uberspector that could be enabled in the configuration.

        Show
        Sergiu Dumitriu added a comment - I agree that it doesn't make sense as a default language feature, but this could be an optional uberspector that could be enabled in the configuration.
        Transition Time In Source Status Execution Times Last Executer Last Execution Date
        Open Open Closed Closed
        1208d 10h 50m 1 Mike Kienenberger 03/Jun/15 04:33

          People

          • Assignee:
            Unassigned
            Reporter:
            Mark S
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Time Tracking

              Estimated:
              Original Estimate - 4h
              4h
              Remaining:
              Remaining Estimate - 4h
              4h
              Logged:
              Time Spent - Not Specified
              Not Specified

                Development