Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2014 Attila Szegedi, Daniel Dekany, Jonathan Revusky
   * 
   * Licensed 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.util.List;
 import java.util.Map;
 import java.util.Set;
 
A class that will wrap an arbitrary object into freemarker.template.TemplateHashModel interface allowing calls to arbitrary property getters and invocation of accessible methods on the object from a template using the object.foo to access properties and object.bar(arg1, arg2) to invoke methods on it. You can also use the object.foo[index] syntax to access indexed properties. It uses Beans java.beans.Introspector to dynamically discover the properties and methods.
 
 
 public class BeanModel
 implements
 {
     private static final Logger LOG = Logger.getLogger("freemarker.beans");
     protected final Object object;
     protected final BeansWrapper wrapper;
     
     // We use this to represent an unknown value as opposed to known value of null (JR)
     static final TemplateModel UNKNOWN = new SimpleScalar("UNKNOWN");
     
     static final ModelFactory FACTORY =
         new ModelFactory()
         {
             public TemplateModel create(Object objectObjectWrapper wrapper)
             {
                 return new BeanModel(object, (BeansWrapper)wrapper);
             }
         };
 
     // Cached template models that implement member properties and methods for this
     // instance. Keys are FeatureDescriptor instances (from classCache values),
     // values are either ReflectionMethodModels/ReflectionScalarModels
     private HashMap memberMap;

    
Creates a new model that wraps the specified object. Note that there are specialized subclasses of this class for wrapping arrays, collections, enumeration, iterators, and maps. Note also that the superclass can be used to wrap String objects if only scalar functionality is needed. You can also choose to delegate the choice over which model class is used for wrapping to BeansWrapper.wrap(java.lang.Object).

Parameters:
object the object to wrap into a model.
wrapper the BeansWrapper associated with this model. Every model has to have an associated BeansWrapper instance. The model gains many attributes from its wrapper, including the caching behavior, method exposure level, method-over-item shadowing policy etc.
 
     public BeanModel(Object objectBeansWrapper wrapper)
    {
        // [2.4]: All models were introspected here, then the results was discareded, and get() will just do the
        // introspection again. So is this necessary? (The inrospectNow parameter was added in 2.3.21 to allow
        // lazy-introspecting BeansWrapper.trueModel|falseModel.)
        this(objectwrappertrue);
    }

    

Since:
2.3.21
    BeanModel(Object objectBeansWrapper wrapperboolean inrospectNow)
    {
        this. = object;
        this. = wrapper;
        if (inrospectNow && object != null) {
            // [2.4]: Could this be removed?
            wrapper.getClassIntrospector().get(object.getClass());
        }
    }
    
    
Uses Beans introspection to locate a property or method with name matching the key name. If a method or property is found, it's wrapped into freemarker.template.TemplateMethodModelEx (for a method or indexed property), or evaluated on-the-fly and the return value wrapped into appropriate model (for a simple property) Models for various properties and methods are cached on a per-class basis, so the costly introspection is performed only once per property or method of a class. (Side-note: this also implies that any class whose method has been called will be strongly referred to by the framework and will not become unloadable until this class has been unloaded first. Normally this is not an issue, but can be in a rare scenario where you create many classes on- the-fly. Also, as the cache grows with new classes and methods introduced to the framework, it may appear as if it were leaking memory. The framework does, however detect class reloads (if you happen to be in an environment that does this kind of things--servlet containers do it when they reload a web application) and flushes the cache. If no method or property matching the key is found, the framework will try to invoke methods with signature non-void-return-type get(java.lang.String), then non-void-return-type get(java.lang.Object), or alternatively (if the wrapped object is a resource bundle) Object getObject(java.lang.String).

Throws:
freemarker.template.TemplateModelException if there was no property nor method nor a generic get method to invoke.
    public TemplateModel get(String key)
        throws
    {
        Class clazz = .getClass();
        Map classInfo = .getClassIntrospector().get(clazz);
        TemplateModel retval = null;
        
        try
        {
            if (.isMethodsShadowItems())
            {
                Object fd = classInfo.get(key);
                if(fd != null)
                {
                    retval = invokeThroughDescriptor(fdclassInfo);
                } else {
                    retval = invokeGenericGet(classInfoclazzkey);
                }
            }
            else
            {
                TemplateModel model = invokeGenericGet(classInfoclazzkey);
                final TemplateModel nullModel = .wrap(null);
                if(model != nullModel && model != 
                {
                    return model;
                }
                Object fd = classInfo.get(key);
                if(fd != null) {
                    retval = invokeThroughDescriptor(fdclassInfo);
                    if (retval ==  && model == nullModel) {
                        // This is the (somewhat subtle) case where the generic get() returns null
                        // and we have no bean info, so we respect the fact that
                        // the generic get() returns null and return null. (JR)
                        retval = nullModel;
                    }
                }
            }
            if (retval == ) {
                if (.isStrict()) {
                    throw new InvalidPropertyException("No such bean property: " + key);
                } else if (.isDebugEnabled()) {
                    logNoSuchKey(keyclassInfo);
                }
                retval = .wrap(null);
            }
            return retval;
        }
        catch(TemplateModelException e)
        {
            throw e;
        }
        catch(Exception e)
        {
            throw new _TemplateModelException(enew Object [] {
                    "An error has occurred when reading existing sub-variable "new _DelayedJQuote(key),
                    "; see cause exception! The type of the containing value was: ",
                    new _DelayedFTLTypeDescription(this)
            });
        }
    }
    private void logNoSuchKey(String keyMap keyMap)
    {
        .debug("Key " + StringUtil.jQuoteNoXSS(key) + " was not found on instance of " + 
            .getClass().getName() + ". Introspection information for " +
            "the class is: " + keyMap);
    }
    
    
Whether the model has a plain get(String) or get(Object) method
    
    protected boolean hasPlainGetMethod() {
    }
    
    private TemplateModel invokeThroughDescriptor(Object descMap classInfo)
        throws
        IllegalAccessException,
    {
        // See if this particular instance has a cached implementation
        // for the requested feature descriptor
        TemplateModel member;
        synchronized(this) {
            if( != null) {
                member = (TemplateModel).get(desc);
            }
            else {
                member = null;
            }
        }
        if(member != null)
            return member;
        TemplateModel retval = ;
        if(desc instanceof IndexedPropertyDescriptor)
        {
            Method readMethod = 
                ((IndexedPropertyDescriptor)desc).getIndexedReadMethod(); 
            retval = member = 
                new SimpleMethodModel(readMethod
                        ClassIntrospector.getArgTypes(classInforeadMethod), );
        }
        else if(desc instanceof PropertyDescriptor)
        {
            PropertyDescriptor pd = (PropertyDescriptor)desc;
            retval = .invokeMethod(pd.getReadMethod(), null);
            // (member == null) condition remains, as we don't cache these
        }
        else if(desc instanceof Field)
        {
            retval = .wrap(((Field)desc).get());
            // (member == null) condition remains, as we don't cache these
        }
        else if(desc instanceof Method)
        {
            Method method = (Method)desc;
            retval = member = new SimpleMethodModel(method
                    ClassIntrospector.getArgTypes(classInfomethod), );
        }
        else if(desc instanceof OverloadedMethods)
        {
            retval = member = 
                new OverloadedMethodsModel(, (OverloadedMethodsdesc);
        }
        
        // If new cacheable member was created, cache it
        if(member != null) {
            synchronized(this) {
                if( == null) {
                     = new HashMap();
                }
                .put(descmember);
            }
        }
        return retval;
    }
    
    void clearMemberCache() {
        synchronized(this) {
             = null;
        }
    }
    protected TemplateModel invokeGenericGet(Map keyMapClass clazzString key)
    throws
        IllegalAccessException,
    {
        Method genericGet = (Method)keyMap.get(.);
        if(genericGet == null)
            return ;
        return .invokeMethod(genericGetnew Object[] { key });
    }
    protected TemplateModel wrap(Object obj)
    {
        return .getOuterIdentity().wrap(obj);
    }
    
    protected Object unwrap(TemplateModel model)
    throws
    {
        return .unwrap(model);
    }

    
Tells whether the model is empty. It is empty if either the wrapped object is null, or it's a Boolean with false value.
    public boolean isEmpty()
    {
        if ( instanceof String) {
            return ((String).length() == 0;
        }
        if ( instanceof Collection) {
            return ((Collection).isEmpty();
        }
        if ( instanceof Map) {
            return ((Map).isEmpty();
        }
        return  == null || ..equals();
    }
    
    
Returns the same as getWrappedObject(); to ensure that, this method will be final starting from 2.4. This behavior of BeanModel is assumed by some FreeMarker code.
    public Object getAdaptedObject(Class hint) {
        return ;  // return getWrappedObject(); starting from 2.4
    }
    public Object getWrappedObject() {
        return ;
    }
    
    public int size()
    {
    }
    public TemplateCollectionModel keys()
    {
        return new CollectionAndSequence(new SimpleSequence(keySet(), ));
    }
    {
        List values = new ArrayList(size());
        TemplateModelIterator it = keys().iterator();
        while (it.hasNext()) {
            String key = ((TemplateScalarModel)it.next()).getAsString();
            values.add(get(key));
        }
        return new CollectionAndSequence(new SimpleSequence(values));
    }
    
    
Used for classic_compatbile mode; don't use it for anything else. In FreeMarker 1.7 (and also at least in 2.1) BeanModel was a freemarker.template.TemplateScalarModel. Some internal FreeMarker code tries to emulate FreeMarker classic by calling this method when a freemarker.template.TemplateScalarModel is expected.
        return  == null ? "null" : .toString();        
    }
    
    public String toString() {
        return .toString();
    }

    
Helper method to support TemplateHashModelEx. Returns the Set of Strings which are available via the TemplateHashModel interface. Subclasses that override invokeGenericGet to provide additional hash keys should also override this method.
    protected Set keySet()
    {
        return .getClassIntrospector().keySet(.getClass());
    }
    public TemplateModel getAPI() throws TemplateModelException {
        return .wrapAsAPI();
    }
    
New to GrepCode? Check out our FAQ X