/*
 *  Copyright 2001-2011 Stephen Colebourne
 *
 *  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 org.joda.beans.integrate.freemarker;

import java.util.NoSuchElementException;

import org.joda.beans.Bean;
import org.joda.beans.Property;

import freemarker.template.AdapterTemplateModel;
import freemarker.template.ObjectWrapper;
import freemarker.template.SimpleCollection;
import freemarker.template.TemplateCollectionModel;
import freemarker.template.TemplateHashModelEx;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.WrappingTemplateModel;

/**
 * Template model converting a Joda-Bean to a Freemarker model.
 * <p>
 * Although this class is public, it should not normally be use directly.
 * Follow the instructions in {@link FreemarkerObjectWrapper} to use this class.
 */
public class FreemarkerTemplateModel
        extends WrappingTemplateModel
        implements TemplateHashModelEx, AdapterTemplateModel {

    /**
     * The bean being wrapped.
     */
    private final Bean _bean;

    /**
     * Creates an instance of the model.
     * @param bean  the bean being wrapped, not null
     * @param wrapper  the default wrapper for further wrapping, not null
     */
    public FreemarkerTemplateModel(final Bean bean, final ObjectWrapper wrapper) {
        super(wrapper);
        _bean = bean;
    }

    //-------------------------------------------------------------------------
    /**
     * Gets the value for the specified key, wrapping the result in another model.
     * @param key  the property name, not null
     * @return the model, null if not found
     */
    @Override
    public TemplateModel get(String key) throws TemplateModelException {
        Object object;
        try {
            Property<Object> property = _bean.property(key);
            object = property.get();
        } catch (NoSuchElementException ex) {
            return null;
        }
        return wrap(object);
    }

    /**
     * Checks if there are no properties.
     * @return true if no properties
     */
    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    /**
     * Gets the number of properties.
     * @return the number of properties
     */
    @Override
    public int size() {
        return _bean.metaBean().metaPropertyCount();
    }

    /**
     * Gets the full set of property names, allowing the bean to be accessed as a sequence.
     * @return the property names, not null
     */
    @Override
    public TemplateCollectionModel keys() {
        return new SimpleCollection(_bean.propertyMap().keySet(), getObjectWrapper());
    }

    /**
     * Gets the full set of property values, allowing the bean to be accessed as a sequence.
     * @return the wrapped property values, not null
     */
    @Override
    public TemplateCollectionModel values() {
        return new SimpleCollection(_bean.propertyMap().flatten().values(), getObjectWrapper());
    }

    /**
     * Unwraps the model, returning the bean.
     * @return the underlying bean, not null
     */
    @SuppressWarnings("rawtypes")
    @Override
    public Object getAdaptedObject(Class hint) {
        return _bean;
    }

}

@@ -684,60 +684,90 @@
 ort 
-java.util.NoSuchElementException;%0D%0A%0D%0Aimport org.joda
+org.joda.beans.Bean;%0D%0Aimport org.joda.beans.MetaProperty;%0D%0A%0D%0Aimport freemarker.ext
 .bea
@@ -765,32 +765,37 @@
 r.ext.beans.Bean
+Model
 ;%0D%0Aimport org.jo
@@ -792,34 +792,42 @@
 ort 
-org.joda.beans.Property;%0D%0A
+freemarker.ext.beans.BeansWrapper;
 %0D%0Aim
@@ -878,51 +878,8 @@
 l;%0D%0A
-import freemarker.template.ObjectWrapper;%0D%0A
 impo
@@ -916,24 +916,66 @@
 ollection;%0D%0A
+import freemarker.template.SimpleScalar;%0D%0A
 import freem
@@ -1925,16 +1925,26 @@
 , final 
+Freemarker
 ObjectWr
@@ -2395,186 +2395,563 @@
     
-Object object;%0D%0A        try %7B%0D%0A            Property%3CObject%3E property = _bean.property(key);%0D%0A            object = property.get();%0D%0A        %7D catch (NoSuchElementException ex
+MetaProperty%3CObject%3E metaProperty = _bean.metaBean().metaPropertyMap().get(key);%0D%0A        if (metaProperty == null) %7B%0D%0A          // try standard approach via BeanModel for non-bean properties and methods%0D%0A          BeanModel model = new BeanModel(_bean, (BeansWrapper) getObjectWrapper());%0D%0A          TemplateModel result = model.get(key);%0D%0A          if (result instanceof SimpleScalar) %7B%0D%0A            // have to map empty string to null%0D%0A            String str = ((SimpleScalar) result).getAsString();%0D%0A            if (str == null %7C%7C str.isEmpty()
 ) %7B%0D%0A
+  
     
@@ -2984,37 +2984,108 @@
     
-%7D%0D%0A        return wrap(object
+    %7D%0D%0A          %7D%0D%0A          return result;%0D%0A        %7D%0D%0A        return wrap(metaProperty.get(_bean)
 );%0D%0A
@@ -4182,16 +4182,52 @@
  bean.%0D%0A
+     * @param hint  the class hint%0D%0A
      * @

Enhance freemarker integration