New BeansWrapper customization point

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

New BeansWrapper customization point

Daniel Dekany
I have added a new customization point to BeansWrapper in 2.3, but
it's a quite strange one, so before I port it to the other branches,
please tell your opinions/ideas. Can it remain at all?

Here's the JavaDoc of the new BeansWrapper method:

  protected void finetuneMethodAppearance(java.lang.Class clazz,
                                          java.lang.reflect.Method m,
                                          BeansWrapper.MethodAppereanceDecision decision)

  Override this to tweak certain aspects of how methods appear in the
  data-model. BeansWrapper will pass in all Java methods here that it
  intends to expose in the data-model as methods (so you can do
  obj.foo() in the template). By default this method does nothing. By
  overriding it you can do the following tweaks:

  * Hide a method that would be otherwise shown by calling
    BeansWrapper.MethodAppereanceDecision.setExposeMethodAs(String)
    with null parameter. Note that you can't un-hide methods that are
    not public or are considered to by unsafe (like Object.wait())
    because finetuneMethodAppearance is not called for those.

  * Show the method with a different name in the data-model than its
    real name by calling
    BeansWrapper.MethodAppereanceDecision.setExposeMethodAs(String)
    with non-null parameter.

  * Create a fake JavaBean property for this method by calling
    BeansWrapper.MethodAppereanceDecision.setExposeAsProperty(PropertyDescriptor).
    For example, if you have int size() in a class, but you want it to
    be accessed from the templates as obj.size, rather than as
    obj.size(), you can do that with this. The default is null, which
    means that no fake property is created for the method. You need
    not and shouldn't set this to non-null for the getter methods of
    real JavaBean properties, as those are automatically shown as
    properties anyway. The property name in the PropertyDescriptor can
    be anything, but the method (or methods) in it must belong to the
    class that is given as the clazz parameter or it must be inherited
    from that class, or else whatever errors can occur later.
    IndexedPropertyDescriptor-s are supported. If a real JavaBean
    property of the same name exists, it won't be replaced by the fake
    one. Also if a fake property of the same name was assigned
    earlier, it won't be replaced.

  * Prevent the method to hide a JavaBean property (fake or real) of
    the same name by calling
    BeansWrapper.MethodAppereanceDecision.setMethodShadowsProperty(boolean)
    with false. The default is true, so if you have both a property
    and a method called "foo", then in the template myObject.foo will
    return the method itself instead of the property value, which is
    often undesirable.

  Note that you can expose a Java method both as a method and as a
  JavaBean property on the same time, however you have to chose
  different names for them to prevent shadowing.

  Parameters:

     decision - Stores how the parameter method will be exposed in the
     data-model after finetuneMethodAppearance returns. This is
     initialized so that it reflects the default behavior of
     BeansWrapper.

Here's a real-world application of this new feature:

    /**
     * Ensures that Scala var-s and val-s are accessible in templates
     * as <tt>${someObject.someVar}</tt>. It also hides var mutator methods.
     */
    @Override
    protected void finetuneMethodAppearance(Class clazz, Method m, MethodAppereanceDecision decision) {
        if (m.getParameterTypes().length == 0 && m.getReturnType() != Void.TYPE) {
            try {
                decision.setExposeAsProperty(new PropertyDescriptor(m.getName(), m, null));
            } catch (IntrospectionException e) {
                // This should never occur...
                throw new RuntimeException("Unexpected error when creating fake PropertyDescriptor (see cause)", e);
            }

            // Just in case the method itself is needed for some expert stuff...
            decision.setExposeMethodAs(m.getName() + "$method");
        } else if (m.getName().endsWith("_$eq")) {
            // Hide var mutator
            decision.setExposeMethodAs(null);
        }
        decision.setMethodShadowsProperty(false);
    }

--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
Oracle to DB2 Conversion Guide: Learn learn about native support for PL/SQL,
new data types, scalar functions, improved concurrency, built-in packages,
OCI, SQL*Plus, data movement tools, best practices and more.
http://p.sf.net/sfu/oracle-sfdev2dev 
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel