public class BeansWrapper extends java.lang.Object implements ObjectWrapper
wrap(Object)
and unwrap(TemplateModel)
methods.Modifier and Type | Class and Description |
---|---|
static class |
BeansWrapper.MethodAppearanceDecision
Experimental class; subject to change!
|
Modifier and Type | Field and Description |
---|---|
static int |
EXPOSE_ALL
At this level of exposure, all methods and properties of the
wrapped objects are exposed to the template.
|
static int |
EXPOSE_NOTHING
At this level of exposure, no bean properties and methods are exposed.
|
static int |
EXPOSE_PROPERTIES_ONLY
At this level of exposure, only property getters are exposed.
|
static int |
EXPOSE_SAFE
At this level of exposure, all methods and properties of the wrapped
objects are exposed to the template except methods that are deemed
not safe.
|
BEANS_WRAPPER, DEFAULT_WRAPPER, SIMPLE_WRAPPER
Constructor and Description |
---|
BeansWrapper()
Creates a new instance of BeansWrapper.
|
Modifier and Type | Method and Description |
---|---|
void |
clearClassIntrospecitonCache()
Removes all class introspection data from the cache.
|
static java.lang.Object |
coerceBigDecimal(java.math.BigDecimal bd,
java.lang.Class formalType) |
static void |
coerceBigDecimals(java.lang.reflect.AccessibleObject callable,
java.lang.Object[] args)
Converts any
BigDecimal s in the passed array to the type of
the corresponding formal argument of the method. |
static void |
coerceBigDecimals(java.lang.Class[] formalTypes,
java.lang.Object[] args)
Converts any
BigDecimal s in the passed array to the type of
the corresponding formal argument of the method. |
protected void |
finetuneMethodAppearance(java.lang.Class clazz,
java.lang.reflect.Method m,
BeansWrapper.MethodAppearanceDecision decision)
Experimental method; subject to change!
|
protected int |
getDefaultDateType()
Returns the default date type.
|
static BeansWrapper |
getDefaultInstance()
Returns the default instance of the wrapper.
|
TemplateHashModel |
getEnumModels()
Returns a hash model that represents the so-called class enum models.
|
protected TemplateModel |
getInstance(java.lang.Object object,
ModelFactory factory)
Deprecated.
override
getModelFactory(Class) instead. Using this
method will now bypass wrapper caching (if it's enabled) and always
result in creation of a new wrapper. This method will be removed in 2.4 |
protected ModelFactory |
getModelFactory(java.lang.Class clazz) |
ObjectWrapper |
getOuterIdentity()
By default returns this.
|
TemplateHashModel |
getStaticModels()
Returns a hash model that represents the so-called class static models.
|
boolean |
isExposeFields()
Returns whether exposure of public instance fields of classes is
enabled.
|
boolean |
isSimpleMapWrapper()
Tells whether Maps are exposed as simple maps, without access to their
method.
|
boolean |
isStrict() |
java.lang.Object |
newInstance(java.lang.Class clazz,
java.util.List arguments) |
void |
removeFromClassIntrospectionCache(java.lang.Class clazz)
Removes the introspection data for a class from the cache.
|
void |
setDefaultDateType(int defaultDateType)
Sets the default date type to use for date models that result from
a plain java.util.Date instead of java.sql.Date or
java.sql.Time or java.sql.Timestamp.
|
void |
setExposeFields(boolean exposeFields)
Controls whether public instance fields of classes are exposed to
templates.
|
void |
setExposureLevel(int exposureLevel)
Sets the method exposure level.
|
void |
setMethodsShadowItems(boolean methodsShadowItems)
Sets whether methods shadow items in beans.
|
void |
setNullModel(TemplateModel nullModel)
Sets the null model.
|
void |
setOuterIdentity(ObjectWrapper outerIdentity)
When wrapping an object, the BeansWrapper commonly needs to wrap
"sub-objects", for example each element in a wrapped collection.
|
void |
setSimpleMapWrapper(boolean simpleMapWrapper)
By default the BeansWrapper wraps classes implementing
java.util.Map using
MapModel . |
void |
setStrict(boolean strict)
Specifies if an attempt to read a bean property that doesn't exist in the
wrapped object should throw an
InvalidPropertyException . |
void |
setUseCache(boolean useCache)
Sets whether this wrapper caches model instances.
|
java.lang.Object |
unwrap(TemplateModel model)
Attempts to unwrap a model into underlying object.
|
java.lang.Object |
unwrap(TemplateModel model,
java.lang.Class hint)
Attempts to unwrap a model into an object of the desired class.
|
TemplateModel |
wrap(java.lang.Object object)
Wraps the object with a template model that is most specific for the object's
class.
|
public static final int EXPOSE_ALL
public static final int EXPOSE_SAFE
public static final int EXPOSE_PROPERTIES_ONLY
public static final int EXPOSE_NOTHING
setMethodsShadowItems(boolean)
with false value to
speed up map item retrieval.public BeansWrapper()
EXPOSE_SAFE
method exposure level, and will not cache
model instances.public boolean isStrict()
setStrict(boolean)
public void setStrict(boolean strict)
InvalidPropertyException
.
If this property is false (the default) then an attempt to read a missing bean property is the same as reading an existing bean property whose value is null. The template can't tell the difference, and thus always can use ?default('something') and ?exists and similar built-ins to handle the situation.
If this property is true then an attempt to read a bean propertly in
the template (like myBean.aProperty) that doesn't exist in the bean
object (as opposed to just holding null value) will cause
InvalidPropertyException
, which can't be suppressed in the template
(not even with myBean.noSuchProperty?default('something')). This way
?default('something') and ?exists and similar built-ins can be used to
handle existing properties whose value is null, without the risk of
hiding typos in the property names. Typos will always cause error. But mind you, it
goes against the basic approach of FreeMarker, so use this feature only if you really
know what are you doing.
public void setOuterIdentity(ObjectWrapper outerIdentity)
outerIdentity
- the aggregate ObjectWrapperpublic ObjectWrapper getOuterIdentity()
setOuterIdentity(ObjectWrapper)
public void setSimpleMapWrapper(boolean simpleMapWrapper)
MapModel
. Setting this flag will
cause it to use a SimpleMapModel
instead. The biggest
difference is that when using a SimpleMapModel
, the
map will be visible as TemplateHashModelEx
,
and the subvariables will be the content of the map,
without the other methods and properties of the map object.simpleMapWrapper
- enable simple map wrappingpublic boolean isSimpleMapWrapper()
setSimpleMapWrapper(boolean)
for details.public void setExposureLevel(int exposureLevel)
EXPOSE_SAFE
.exposureLevel
- can be any of the EXPOSE_xxx
constants.public void setExposeFields(boolean exposeFields)
exposeFields
- if set to true, public instance fields of classes
that do not have a property getter defined can be accessed directly by
their name. If there is a property getter for a property of the same
name as the field (i.e. getter "getFoo()" and field "foo"), then
referring to "foo" in template invokes the getter. If set to false, no
access to public instance fields of classes is given. Default is false.public boolean isExposeFields()
setExposeFields(boolean)
for details.public void setMethodsShadowItems(boolean methodsShadowItems)
${object.name}
will first try to locate
a bean method or property with the specified name on the object, and
only if it doesn't find it will it try to call
object.get(name)
, the so-called "generic get method" that
is usually used to access items of a container (i.e. elements of a map).
When set to false, the lookup order is reversed and generic get method
is called first, and only if it returns null is method lookup attempted.public void setDefaultDateType(int defaultDateType)
TemplateDateModel.UNKNOWN
.defaultDateType
- the new default date type.protected int getDefaultDateType()
setDefaultDateType(int)
for
details.public void setUseCache(boolean useCache)
wrap(Object)
multiple times for
the same object will likely return the same model (although there is
no guarantee as the cache items can be cleared anytime).public void setNullModel(TemplateModel nullModel)
wrap(Object)
method whenever the underlying object
reference is null. It defaults to null reference, which is dealt
with quite strictly on engine level, however you can substitute an
arbitrary (perhaps more lenient) model, such as
TemplateScalarModel.EMPTY_STRING
.public static final BeansWrapper getDefaultInstance()
ObjectWrapper.BEANS_WRAPPER
and this is the sole instance that is used by the JSP adapter.
You can modify the properties of the default instance (caching,
exposure level, null model) to affect its operation. By default, the
default instance is not caching, uses the EXPOSE_SAFE
exposure level, and uses null reference as the null model.public TemplateModel wrap(java.lang.Object object) throws TemplateModelException
null model
,NumberModel
for it,DateModel
for it,TemplateBooleanModel.TRUE
or
TemplateBooleanModel.FALSE
ArrayModel
for it
MapModel
for it
CollectionModel
for it
IteratorModel
for it
EnumerationModel
for it
StringModel
for it
BeanModel
for it.
wrap
in interface ObjectWrapper
object
- The object to wrap into a TemplateModel
. If the it already implements TemplateModel
,
it should just return the object as is.TemplateModel
wrapper of the object passed in. To support un-wrapping, you may consider the
return value to implement WrapperTemplateModel
and AdapterTemplateModel
.TemplateModelException
protected TemplateModel getInstance(java.lang.Object object, ModelFactory factory)
getModelFactory(Class)
instead. Using this
method will now bypass wrapper caching (if it's enabled) and always
result in creation of a new wrapper. This method will be removed in 2.4object
- factory
- protected ModelFactory getModelFactory(java.lang.Class clazz)
public java.lang.Object unwrap(TemplateModel model) throws TemplateModelException
wrap(Object)
method. In addition
it will unwrap arbitrary TemplateNumberModel
instances into
a number, arbitrary TemplateDateModel
instances into a date,
TemplateScalarModel
instances into a String, arbitrary
TemplateBooleanModel
instances into a Boolean, arbitrary
TemplateHashModel
instances into a Map, arbitrary
TemplateSequenceModel
into a List, and arbitrary
TemplateCollectionModel
into a Set. All other objects are
returned unchanged.TemplateModelException
- if an attempted unwrapping fails.public java.lang.Object unwrap(TemplateModel model, java.lang.Class hint) throws TemplateModelException
wrap(Object)
method. It recognizes a wide range of hint classes - all Java built-in
primitives, primitive wrappers, numbers, dates, sets, lists, maps, and
native arrays.model
- the model to unwraphint
- the class of the unwrapped resultTemplateModelException
- if an attempted unwrapping fails.public TemplateHashModel getStaticModels()
statics["java.lang.
System"]. currentTimeMillis()
to call the System.currentTimeMillis()
method.public TemplateHashModel getEnumModels()
statics["java.math.RoundingMode"].UP
to access the
RoundingMode.UP
value.java.lang.UnsupportedOperationException
- if this method is invoked on a
pre-1.5 JRE, as Java enums aren't supported there.public java.lang.Object newInstance(java.lang.Class clazz, java.util.List arguments) throws TemplateModelException
TemplateModelException
public void removeFromClassIntrospectionCache(java.lang.Class clazz)
public void clearClassIntrospecitonCache()
protected void finetuneMethodAppearance(java.lang.Class clazz, java.lang.reflect.Method m, BeansWrapper.MethodAppearanceDecision decision)
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:
BeansWrapper.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
finetuneMethodAppearance(java.lang.Class, java.lang.reflect.Method, freemarker.ext.beans.BeansWrapper.MethodAppearanceDecision)
is not called for those.BeansWrapper.MethodAppearanceDecision.setExposeMethodAs(String)
with non-null parameter.
BeansWrapper.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.
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.
BeansWrapper.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.
decision
- Stores how the parameter method will be exposed in the
data-model after finetuneMethodAppearance(java.lang.Class, java.lang.reflect.Method, freemarker.ext.beans.BeansWrapper.MethodAppearanceDecision)
returns.
This is initialized so that it reflects the default
behavior of BeansWrapper
.public static void coerceBigDecimals(java.lang.reflect.AccessibleObject callable, java.lang.Object[] args)
BigDecimal
s in the passed array to the type of
the corresponding formal argument of the method.public static void coerceBigDecimals(java.lang.Class[] formalTypes, java.lang.Object[] args)
BigDecimal
s in the passed array to the type of
the corresponding formal argument of the method.public static java.lang.Object coerceBigDecimal(java.math.BigDecimal bd, java.lang.Class formalType)