/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package freemarker.ext.beans;

import java.beans.IndexedPropertyDescriptor;
import java.beans.PropertyDescriptor;

import freemarker.ext.beans.BeansWrapper.MethodAppearanceDecision;
import freemarker.ext.beans.BeansWrapper.MethodAppearanceDecisionInput;

Used for customizing how the methods are visible from templates, via BeansWrapper.setMethodAppearanceFineTuner(MethodAppearanceFineTuner). The object that implements this should also implement SingletonCustomizer whenever possible.
Since:2.3.21
/** * Used for customizing how the methods are visible from templates, via * {@link BeansWrapper#setMethodAppearanceFineTuner(MethodAppearanceFineTuner)}. * The object that implements this should also implement {@link SingletonCustomizer} whenever possible. * * @since 2.3.21 */
public interface MethodAppearanceFineTuner {
Implement 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). With this method you can do the following tweaks:
  • Hide a method that would be otherwise shown by calling MethodAppearanceDecision.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 process is not called for those.
  • Show the method with a different name in the data-model than its real name by calling MethodAppearanceDecision.setExposeMethodAs(String) with non-null parameter.
  • Create a fake JavaBean property for this method by calling MethodAppearanceDecision.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 (but remember calling setMethodShadowsProperty(false) as well, if the method name is exactly the same as the property name). 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, or a fake property of the same name was already assigned earlier, it won't be replaced by the new one by default, however this can be changed with MethodAppearanceDecision.setReplaceExistingProperty(boolean).
  • Prevent the method to hide a JavaBean property (fake or real) of the same name by calling MethodAppearanceDecision.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.

Params:
  • in – Describes the method about which the decision will have to be made.
  • out – Stores how the method will be exposed in the data-model after process returns. This is initialized so that it reflects the default behavior of BeansWrapper, so you don't have to do anything with this when you don't want to change the default behavior.
/** * Implement this to tweak certain aspects of how methods appear in the * data-model. {@link BeansWrapper} will pass in all Java methods here that * it intends to expose in the data-model as methods (so you can do * <tt>obj.foo()</tt> in the template). * With this method you can do the following tweaks: * <ul> * <li>Hide a method that would be otherwise shown by calling * {@link MethodAppearanceDecision#setExposeMethodAs(String)} * with <tt>null</tt> parameter. Note that you can't un-hide methods * that are not public or are considered to by unsafe * (like {@link Object#wait()}) because * {@link #process} is not called for those.</li> * <li>Show the method with a different name in the data-model than its * real name by calling * {@link MethodAppearanceDecision#setExposeMethodAs(String)} * with non-<tt>null</tt> parameter. * <li>Create a fake JavaBean property for this method by calling * {@link MethodAppearanceDecision#setExposeAsProperty(PropertyDescriptor)}. * For example, if you have <tt>int size()</tt> in a class, but you * want it to be accessed from the templates as <tt>obj.size</tt>, * rather than as <tt>obj.size()</tt>, you can do that with this * (but remember calling * {@link MethodAppearanceDecision#setMethodShadowsProperty(boolean) * setMethodShadowsProperty(false)} as well, if the method name is exactly * the same as the property name). * The default is {@code null}, which means that no fake property is * created for the method. You need not and shouldn't set this * to non-<tt>null</tt> for the getter methods of real JavaBean * properties, as those are automatically shown as properties anyway. * The property name in the {@link PropertyDescriptor} can be anything, * but the method (or methods) in it must belong to the class that * is given as the <tt>clazz</tt> parameter or it must be inherited from * that class, or else whatever errors can occur later. * {@link IndexedPropertyDescriptor}-s are supported. * If a real JavaBean property of the same name exists, or a fake property * of the same name was already assigned earlier, it won't be * replaced by the new one by default, however this can be changed with * {@link MethodAppearanceDecision#setReplaceExistingProperty(boolean)}. * <li>Prevent the method to hide a JavaBean property (fake or real) of * the same name by calling * {@link MethodAppearanceDecision#setMethodShadowsProperty(boolean)} * with <tt>false</tt>. The default is <tt>true</tt>, so if you have * both a property and a method called "foo", then in the template * <tt>myObject.foo</tt> will return the method itself instead * of the property value, which is often undesirable. * </ul> * * <p>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. * * @param in Describes the method about which the decision will have to be made. * * @param out Stores how the method will be exposed in the * data-model after {@link #process} returns. * This is initialized so that it reflects the default * behavior of {@link BeansWrapper}, so you don't have to do anything with this * when you don't want to change the default behavior. */
void process(MethodAppearanceDecisionInput in, MethodAppearanceDecision out); }