public class BeansWrapper extends java.lang.Object implements RichObjectWrapper, WriteProtectable
ObjectWrapper
that is able to expose the Java API of arbitrary Java objects. This is also the superclass of
DefaultObjectWrapper
. Note that instances of this class generally should be created with a
BeansWrapperBuilder
, not with its public constructors.
As of 2.3.22, using BeansWrapper
unextended is not recommended. Instead, DefaultObjectWrapper
with
its incompatibleImprovements
property set to 2.3.22 (or higher) is the recommended ObjectWrapper
.
This class is only thread-safe after you have finished calling its setter methods, and then safely published it (see
JSR 133 and related literature). When used as part of Configuration
, of course it's enough if that was safely
published and then left unmodified. Using BeansWrapperBuilder
also guarantees thread safety.
Modifier and Type | Class and Description |
---|---|
static class |
BeansWrapper.MethodAppearanceDecision
Used for
MethodAppearanceFineTuner.process(freemarker.ext.beans.BeansWrapper.MethodAppearanceDecisionInput, freemarker.ext.beans.BeansWrapper.MethodAppearanceDecision)
to store the results; see there. |
static class |
BeansWrapper.MethodAppearanceDecisionInput
Used for
MethodAppearanceFineTuner.process(freemarker.ext.beans.BeansWrapper.MethodAppearanceDecisionInput, freemarker.ext.beans.BeansWrapper.MethodAppearanceDecision) as input parameter; see there. |
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, and the
MemberAccessPolicy
will be ignored. |
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.
|
CANT_UNWRAP_TO_TARGET_CLASS
BEANS_WRAPPER, DEFAULT_WRAPPER, SIMPLE_WRAPPER
Modifier | Constructor and Description |
---|---|
|
BeansWrapper()
Deprecated.
Use
BeansWrapperBuilder or, in rare cases, BeansWrapper(Version) instead. |
protected |
BeansWrapper(BeansWrapperConfiguration bwConf,
boolean writeProtected)
Same as
BeansWrapper(BeansWrapperConfiguration, boolean, boolean) with true
finalizeConstruction argument. |
protected |
BeansWrapper(BeansWrapperConfiguration bwConf,
boolean writeProtected,
boolean finalizeConstruction)
Initializes the instance based on the the
BeansWrapperConfiguration specified. |
|
BeansWrapper(Version incompatibleImprovements)
Use
BeansWrapperBuilder instead of the public constructors if possible. |
Modifier and Type | Method and Description |
---|---|
protected void |
checkModifiable()
If this object is already read-only according to
WriteProtectable , throws IllegalStateException ,
otherwise does nothing. |
void |
clearClassIntrospecitonCache()
Deprecated.
There's a typo in this method name, so use
clearClassIntrospectionCache() instead. |
void |
clearClassIntrospectionCache()
Removes all class introspection data from the cache.
|
static java.lang.Object |
coerceBigDecimal(java.math.BigDecimal bd,
java.lang.Class<?> formalType)
Converts
BigDecimal to the class given in the formalType argument if that's a known numerical
type, returns the BigDecimal as is otherwise. |
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 via coerceBigDecimal(BigDecimal, Class) . |
protected void |
finalizeConstruction(boolean writeProtected)
Meant to be called after
BeansWrapper(BeansWrapperConfiguration, boolean, boolean) when
its last argument was false ; makes the instance read-only if necessary, then registers the model
factories in the class introspector. |
protected void |
finetuneMethodAppearance(java.lang.Class<?> clazz,
java.lang.reflect.Method m,
BeansWrapper.MethodAppearanceDecision decision)
Deprecated.
Use
setMethodAppearanceFineTuner(MethodAppearanceFineTuner) ;
no need to extend this class anymore.
Soon this method will be final, so trying to override it will break your app.
Note that if the methodAppearanceFineTuner property is set to non-null , this method is not
called anymore. |
int |
getDefaultDateType()
Returns the default date type.
|
static BeansWrapper |
getDefaultInstance()
Deprecated.
Use
BeansWrapperBuilder instead. The instance returned here is not read-only, so it's
dangerous to use. |
TemplateHashModel |
getEnumModels()
Returns a hash model that represents the so-called class enum models.
|
int |
getExposureLevel() |
Version |
getIncompatibleImprovements()
Returns the version given with
BeansWrapper(Version) , normalized to the lowest version where a change
has occurred. |
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 |
MemberAccessPolicy |
getMemberAccessPolicy() |
MethodAppearanceFineTuner |
getMethodAppearanceFineTuner() |
protected ModelFactory |
getModelFactory(java.lang.Class<?> clazz) |
ObjectWrapper |
getOuterIdentity()
By default returns this.
|
boolean |
getPreferIndexedReadMethod()
Getter pair of
setPreferIndexedReadMethod(boolean) |
TemplateHashModel |
getStaticModels()
Returns a hash model that represents the so-called class static models.
|
boolean |
getTreatDefaultMethodsAsBeanMembers()
|
boolean |
getUseCache() |
protected TemplateModel |
invokeMethod(java.lang.Object object,
java.lang.reflect.Method method,
java.lang.Object[] args)
Invokes the specified method, wrapping the return value.
|
boolean |
isClassIntrospectionCacheRestricted()
Tells if this instance acts like if its class introspection cache is sharable with other
BeansWrapper -s. |
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() |
boolean |
isWriteProtected() |
java.lang.Object |
newInstance(java.lang.Class<?> clazz,
java.util.List arguments)
Creates a new instance of the specified class using the method call logic of this object wrapper for calling the
constructor.
|
protected static Version |
normalizeIncompatibleImprovementsVersion(Version incompatibleImprovements)
Returns the lowest version number that is equivalent with the parameter version.
|
protected TemplateModel |
readField(java.lang.Object object,
java.lang.reflect.Field field)
Reads the specified field, returns its value as
TemplateModel . |
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 |
setMemberAccessPolicy(MemberAccessPolicy memberAccessPolicy)
Sets the
MemberAccessPolicy ; default is DefaultMemberAccessPolicy.getInstance(Version) , which
is not appropriate if template editors aren't trusted. |
void |
setMethodAppearanceFineTuner(MethodAppearanceFineTuner methodAppearanceFineTuner)
Used to tweak certain aspects of how methods appear in the data-model;
see
MethodAppearanceFineTuner for more. |
void |
setMethodsShadowItems(boolean methodsShadowItems)
Sets whether methods shadow items in beans.
|
void |
setNullModel(TemplateModel nullModel)
Deprecated.
Changing the
null model can cause a lot of confusion; don't do it. |
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 |
setPreferIndexedReadMethod(boolean preferIndexedReadMethod)
Sets if when a JavaBean property has both a normal read method (like
String[] getFoos() ) and an indexed
read method (like String getFoos(int index) ), and the Java Introspector exposes both (which only
happens since Java 8, apparently), which read method will be used when the property is accessed with the
shorthand syntax (like myObj.foos ). |
void |
setSimpleMapWrapper(boolean simpleMapWrapper)
When set to
true , the keys in Map -s won't mix with the method names when looking at them
from templates. |
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 |
setTreatDefaultMethodsAsBeanMembers(boolean treatDefaultMethodsAsBeanMembers)
Controls whether Java 8 default methods that weren't overridden in a class will be recognized as bean property
accessors and/or bean actions, and thus will be visible from templates.
|
void |
setUseCache(boolean useCache)
Sets whether this wrapper caches the
TemplateModel -s created for the Java objects that has wrapped with
this object wrapper. |
protected java.lang.String |
toPropertiesString()
Returns the name-value pairs that describe the configuration of this
BeansWrapper ; called from
toString() . |
java.lang.String |
toString()
Returns the exact class name and the identity hash, also the values of the most often used
BeansWrapper
configuration properties, also if which (if any) shared class introspection cache it uses. |
java.lang.Object |
tryUnwrapTo(TemplateModel model,
java.lang.Class<?> targetClass)
Attempts to unwrap a
TemplateModel to a plain Java object that's the instance of the given class (or is
null ). |
java.lang.Object |
unwrap(TemplateModel model)
Attempts to unwrap a model into underlying object.
|
java.lang.Object |
unwrap(TemplateModel model,
java.lang.Class<?> targetClass)
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.
|
TemplateMethodModelEx |
wrap(java.lang.Object object,
java.lang.reflect.Method method)
Wraps a Java method so that it can be called from templates, without wrapping its parent ("this") object.
|
TemplateHashModel |
wrapAsAPI(java.lang.Object obj)
Wraps an object to a
TemplateModel that exposes the object's "native" (usually, Java) API. |
void |
writeProtect()
Makes the configuration properties (settings) of this
BeansWrapper object read-only. |
public static final int EXPOSE_ALL
MemberAccessPolicy
will be ignored.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.@Deprecated public BeansWrapper()
BeansWrapperBuilder
or, in rare cases, BeansWrapper(Version)
instead.Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS
.public BeansWrapper(Version incompatibleImprovements)
BeansWrapperBuilder
instead of the public constructors if possible.
The main disadvantage of using the public constructors is that the instances won't share caches. So unless having
a private cache is your goal, don't use them. SeeincompatibleImprovements
- Sets which of the non-backward-compatible improvements should be enabled. Not null
. This version number
is the same as the FreeMarker version number with which the improvements were implemented.
For new projects, it's recommended to set this to the FreeMarker version that's used during the development. For released products that are still actively developed it's a low risk change to increase the 3rd version number further as FreeMarker is updated, but of course you should always check the list of effects below. Increasing the 2nd or 1st version number possibly mean substantial changes with higher risk of breaking the application, but again, see the list of effects below.
The reason it's separate from Configuration.setIncompatibleImprovements(Version)
is that
ObjectWrapper
objects are often shared among multiple Configuration
-s, so the two version
numbers are technically independent. But it's recommended to keep those two version numbers the same.
The changes enabled by incompatibleImprovements
are:
2.3.0: No changes; this is the starting point, the version used in older projects.
2.3.21 (or higher):
Several glitches were fixed in overloaded method selection. This usually just gets
rid of errors (like ambiguity exceptions and numerical precision loses due to bad overloaded method
choices), still, as in some cases the method chosen can be a different one now (that was the point of
the reworking after all), it can mean a change in the behavior of the application. The most important
change is that the treatment of null
arguments were fixed, as earlier they were only seen
applicable to parameters of type Object
. Now null
-s are seen to be applicable to any
non-primitive parameters, and among those the one with the most specific type will be preferred (just
like in Java), which is hence never the one with the Object
parameter type. For more details
about overloaded method selection changes see the version history in the FreeMarker Manual.
2.3.24 (or higher):
Iterator
-s were always said to be non-empty when using ?has_content
and such (i.e.,
operators that check emptiness without reading any elements). Now an Iterator
counts as
empty exactly if it has no elements left. (Note that this bug has never affected basic functionality, like
<#list ...>
.)
2.3.26 (or higher):
The default of getTreatDefaultMethodsAsBeanMembers()
changes from false
to
true
. Thus, Java 8 default methods (and the bean properties they define) are exposed, despite that
Introspector
(the official JavaBeans introspector) ignores them, at least as of Java 8.
2.3.27 (or higher):
The default of the preferIndexedReadMethod
setting changes
from true
to false
.
Note that the version will be normalized to the lowest version where the same incompatible
BeansWrapper
improvements were already present, so getIncompatibleImprovements()
might return
a lower version than what you have specified.
protected BeansWrapper(BeansWrapperConfiguration bwConf, boolean writeProtected)
BeansWrapper(BeansWrapperConfiguration, boolean, boolean)
with true
finalizeConstruction
argument.protected BeansWrapper(BeansWrapperConfiguration bwConf, boolean writeProtected, boolean finalizeConstruction)
BeansWrapperConfiguration
specified.writeProtected
- Makes the instance's configuration settings read-only via
WriteProtectable.writeProtect()
; this way it can use the shared class introspection cache.finalizeConstruction
- Decides if the construction is finalized now, or the caller will do some more
adjustments on the instance and then call finalizeConstruction(boolean)
itself.protected void finalizeConstruction(boolean writeProtected)
BeansWrapper(BeansWrapperConfiguration, boolean, boolean)
when
its last argument was false
; makes the instance read-only if necessary, then registers the model
factories in the class introspector. No further changes should be done after calling this, if
writeProtected
was true
.public void writeProtect()
BeansWrapper
object read-only. As changing them
after the object has become visible to multiple threads leads to undefined behavior, it's recommended to call
this when you have finished configuring the object.
Consider using BeansWrapperBuilder
instead, which gives an instance that's already
write protected and also uses some shared caches/pools.
writeProtect
in interface WriteProtectable
public boolean isWriteProtected()
isWriteProtected
in interface WriteProtectable
protected void checkModifiable()
WriteProtectable
, throws IllegalStateException
,
otherwise does nothing.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 you are doing.
public void setOuterIdentity(ObjectWrapper outerIdentity)
outerIdentity
- the aggregate ObjectWrapperpublic ObjectWrapper getOuterIdentity()
setOuterIdentity(ObjectWrapper)
public void setSimpleMapWrapper(boolean simpleMapWrapper)
true
, the keys in Map
-s won't mix with the method names when looking at them
from templates. The default is false
for backward-compatibility, but is not recommended.
When this is false
, myMap.foo
or myMap['foo']
either returns the method foo
,
or calls Map.get("foo")
. If both exists (the method and the Map
key), one will hide the other,
depending on the isMethodsShadowItems()
, which default to true
(the method
wins). Some frameworks use this so that you can call myMap.get(nonStringKey)
from templates [*], but it
comes on the cost of polluting the key-set with the method names, and risking methods accidentally hiding
Map
entries (or the other way around). Thus, this setup is not recommended.
(Technical note: Map
-s will be wrapped into MapModel
in this case.)
When this is true
, myMap.foo
or myMap['foo']
always calls Map.get("foo")
.
The methods of the Map
object aren't visible from templates in this case. This, however, spoils the
myMap.get(nonStringKey)
workaround. But now you can use myMap(nonStringKey)
instead, that is, you
can use the map itself as the get
method.
(Technical note: Map
-s will be wrapped into SimpleMapModel
in this case.)
*: For historical reasons, FreeMarker 2.3.X doesn't support non-string keys with the []
operator,
hence the workarounds. This will be likely fixed in FreeMarker 2.4.0. Also note that the method- and
the "field"-namespaces aren't separate in FreeMarker, hence myMap.get
can return the get
method.
public boolean isSimpleMapWrapper()
setSimpleMapWrapper(boolean)
for details.public boolean getPreferIndexedReadMethod()
setPreferIndexedReadMethod(boolean)
public void setPreferIndexedReadMethod(boolean preferIndexedReadMethod)
String[] getFoos()
) and an indexed
read method (like String getFoos(int index)
), and the Java Introspector
exposes both (which only
happens since Java 8, apparently), which read method will be used when the property is accessed with the
shorthand syntax (like myObj.foos
). Before incompatibleImprovements
2.3.27 it defaults to true
for backward compatibility (although it's actually less backward compatible if
you are just switching to Java 8; see later), but the recommended value and the default starting with
incompatibleImprovements
2.3.27 is false
. This setting has no
effect on properties that only has normal read method, or only has indexed read method. In case a property has
both, using the indexed reader method is disadvantageous, as then FreeMarker can't tell what the highest allowed
index is, and so the property will be unlistable (<#list foo as myObj.foos>
will fail).
Apparently, this setting only matters since Java 8, as before that Introspector
did not expose the
indexed reader method if there was also a normal reader method. As with Java 8 the behavior of
Introspector
has changed, some old templates started to break, as the property has suddenly become
unlistable (see earlier why). So setting this to false
can be seen as a Java 8 compatibility fix.
public void setExposureLevel(int exposureLevel)
EXPOSE_SAFE
.exposureLevel
- can be any of the EXPOSE_xxx
constants.public int getExposureLevel()
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 void setTreatDefaultMethodsAsBeanMembers(boolean treatDefaultMethodsAsBeanMembers)
incompatibleImprovements
2.3.26
this defaults to false
for backward compatibility. Starting with incompatibleImprovements
2.3.26 it defaults to true
.
Some explanation: FreeMarker uses Introspector
to discover the bean properties and actions of
classes, for maximum conformance to the JavaBeans specification. But for some reason (perhaps just a bug in the
Oracle/OpenJDK Java 8 implementation) that ignores the Java 8 default methods coming from the interfaces. When
this setting is true
, we search for non-overridden default methods ourselves, and add them to the set of
discovered bean members.
public boolean isExposeFields()
setExposeFields(boolean)
for details.public boolean getTreatDefaultMethodsAsBeanMembers()
public MethodAppearanceFineTuner getMethodAppearanceFineTuner()
public void setMethodAppearanceFineTuner(MethodAppearanceFineTuner methodAppearanceFineTuner)
MethodAppearanceFineTuner
for more.public MemberAccessPolicy getMemberAccessPolicy()
public void setMemberAccessPolicy(MemberAccessPolicy memberAccessPolicy)
MemberAccessPolicy
; default is DefaultMemberAccessPolicy.getInstance(Version)
, which
is not appropriate if template editors aren't trusted.public boolean isClassIntrospectionCacheRestricted()
BeansWrapper
-s.
A restricted cache denies certain too "antisocial" operations, like clearClassIntrospectionCache()
.
The value depends on how the instance
was created; with a public constructor (then this is false
), or with BeansWrapperBuilder
(then it's true
). Note that in the last case it's possible that the introspection cache
will not be actually shared because there's no one to share with, but this will true
even then.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.public int getDefaultDateType()
setDefaultDateType(int)
for
details.public void setUseCache(boolean useCache)
TemplateModel
-s created for the Java objects that has wrapped with
this object wrapper. Default is false
.
When set to true
, calling 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 any time).public boolean getUseCache()
@Deprecated public void setNullModel(TemplateModel nullModel)
null
model can cause a lot of confusion; don't do it.wrap(Object)
method whenever the wrapped object is
null
. It defaults to null
, which is dealt with quite strictly on engine level, however you can
substitute an arbitrary (perhaps more lenient) model, like an empty string. For proper working, the
nullModel
should be an AdapterTemplateModel
that returns null
for
AdapterTemplateModel.getAdaptedObject(Class)
.public Version getIncompatibleImprovements()
BeansWrapper(Version)
, normalized to the lowest version where a change
has occurred. Thus, this is not necessarily the same version than that was given to the constructor.protected static Version normalizeIncompatibleImprovementsVersion(Version incompatibleImprovements)
@Deprecated public static final BeansWrapper getDefaultInstance()
BeansWrapperBuilder
instead. The instance returned here is not read-only, so it's
dangerous to use.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
StringModel
for it.
wrap
in interface ObjectWrapper
object
- The object to wrap into a TemplateModel
. If it already implements TemplateModel
,
it should just return the object as is. If it's null
, the method should return null
(however, BeansWrapper
, has a legacy option for returning a null model object instead, but it's not
a good idea).TemplateModel
wrapper of the object passed in. To support un-wrapping, you may consider the
return value to implement WrapperTemplateModel
and AdapterTemplateModel
.
The default expectation is that the TemplateModel
isn't less thread safe than the wrapped object.
If the ObjectWrapper
returns less thread safe objects, that should be clearly documented, as it
restricts how it can be used, like, then it can't be used to wrap "shared variables"
(Configuration.setSharedVaribles(Map)
).TemplateModelException
public TemplateMethodModelEx wrap(java.lang.Object object, java.lang.reflect.Method method)
TemplateHashModel
by name. Except, if the wrapped method is overloaded, with this method you
explicitly select an overload, while otherwise you would get a TemplateMethodModelEx
that selects an
overload each time it's called based on the argument values.object
- The object whose method will be called, or null
if method
is a static method.
This object will be used "as is", like without unwrapping it if it's a TemplateModelAdapter
.method
- The method to call, which must be an (inherited) member of the class of object
, as
described by Method.invoke(Object, Object...)
public TemplateHashModel wrapAsAPI(java.lang.Object obj) throws TemplateModelException
ObjectWrapperWithAPISupport
TemplateModel
that exposes the object's "native" (usually, Java) API.wrapAsAPI
in interface ObjectWrapperWithAPISupport
obj
- The object for which the API model has to be returned. Shouldn't be null
.TemplateModel
through which the API of the object can be accessed. Can't be null
.TemplateModelException
@Deprecated 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
- The object to wrapfactory
- The factory that wraps the objectprotected 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.unwrap
in interface ObjectWrapperAndUnwrapper
null
, if null
is the appropriate Java value to represent
the template model. null
must not be used to indicate an unwrapping failure. It must NOT be
ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS
.TemplateModelException
- if an attempted unwrapping fails.ObjectWrapperAndUnwrapper.tryUnwrapTo(TemplateModel, Class)
public java.lang.Object unwrap(TemplateModel model, java.lang.Class<?> targetClass) throws TemplateModelException
wrap(Object)
method. It recognizes a wide range of target classes - all Java built-in
primitives, primitive wrappers, numbers, dates, sets, lists, maps, and
native arrays.model
- the model to unwraptargetClass
- the class of the unwrapped result; Object.class
if we don't know what the expected type is.TemplateModelException
- if an attempted unwrapping fails.tryUnwrapTo(TemplateModel, Class)
public java.lang.Object tryUnwrapTo(TemplateModel model, java.lang.Class<?> targetClass) throws TemplateModelException
ObjectWrapperAndUnwrapper
TemplateModel
to a plain Java object that's the instance of the given class (or is
null
).tryUnwrapTo
in interface ObjectWrapperAndUnwrapper
targetClass
- The class that the return value must be an instance of (except when the return value is null
).
Can't be null
; if the caller doesn't care, it should either use {#unwrap(TemplateModel)}, or
Object.class
as the parameter value.targetClass
, or is null
(if null
is the appropriate Java value to represent the template model), or is
ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS
if the unwrapping can't satisfy the targetClass
(nor the
result can be null
). However, ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS
must not be returned if the
targetClass
parameter was Object.class
.TemplateModelException
- If the unwrapping fails for a reason than doesn't fit the meaning of the
ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS
return value.ObjectWrapperAndUnwrapper.unwrap(TemplateModel)
protected TemplateModel invokeMethod(java.lang.Object object, java.lang.reflect.Method method, java.lang.Object[] args) throws java.lang.reflect.InvocationTargetException, java.lang.IllegalAccessException, TemplateModelException
ObjectWrapper
).
This method is protected since 2.3.30; before that it was package private. The intended application of
overriding this is monitoring what calls are made from templates. That can be useful to asses what will be needed
in a WhitelistMemberAccessPolicy
for example. Note that Object.toString()
calls caused by type
conversion (like when you have ${myObject}
) will not go through here, as they aren't called by the
template directly (and aren't called via reflection). On the other hand, ${myObject[key]}
,
if myObject
is not a Map
, will go through here as a get(String|Object)
method call, if
there's a such method.
If the return value is null, and the return type of the invoked method is void,
TemplateModel.NOTHING
is returned.
object
- the object to invoke the method on (null
may be null for static methods)method
- the method to invokeargs
- the arguments to the methodjava.lang.reflect.InvocationTargetException
- if the invoked method threw an exceptionjava.lang.IllegalAccessException
- if the method can't be invoked due to an
access restriction.TemplateModelException
- if the return value couldn't be wrapped
(this can happen if the wrapper has an outer identity or is subclassed,
and the outer identity or the subclass throws an exception. Plain
BeansWrapper never throws TemplateModelException).readField(Object, Field)
protected TemplateModel readField(java.lang.Object object, java.lang.reflect.Field field) throws java.lang.IllegalAccessException, TemplateModelException
TemplateModel
. All field reading done in templates
should go through this (assuming the target object was wrapped with this ObjectWrapper
).
Just like in the case of invokeMethod(Object, Method, Object[])
, overriding this can be useful if you
want to monitor what members are accessed by templates. However, it has the caveat that final field values are
possibly cached, so you won't see all reads. Furthermore, at least static models pre-read final fields, so
they will be read even if the templates don't read them.
java.lang.IllegalAccessException
TemplateModelException
invokeMethod(Object, Method, Object[])
public TemplateHashModel getStaticModels()
statics["java.lang.
System"]. currentTimeMillis()
to call the System.currentTimeMillis()
method.public TemplateHashModel getEnumModels()
enums["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
clazz
- The class whose constructor we will call.arguments
- The list of TemplateModel
-s to pass to the constructor after unwrapping themTemplateModel
.TemplateModelException
public void removeFromClassIntrospectionCache(java.lang.Class<?> clazz)
@Deprecated public void clearClassIntrospecitonCache()
clearClassIntrospectionCache()
instead.Removes all class introspection data from the cache.
Use this if you want to free up memory on the expense of recreating the cache entries for the classes that will be used later in templates.
java.lang.IllegalStateException
- if isClassIntrospectionCacheRestricted()
is true
.public void clearClassIntrospectionCache()
Use this if you want to free up memory on the expense of recreating the cache entries for the classes that will be used later in templates.
java.lang.IllegalStateException
- if isClassIntrospectionCacheRestricted()
is true
.clearClassIntrospecitonCache()
)@Deprecated protected void finetuneMethodAppearance(java.lang.Class<?> clazz, java.lang.reflect.Method m, BeansWrapper.MethodAppearanceDecision decision)
setMethodAppearanceFineTuner(MethodAppearanceFineTuner)
;
no need to extend this class anymore.
Soon this method will be final, so trying to override it will break your app.
Note that if the methodAppearanceFineTuner
property is set to non-null
, this method is not
called anymore.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 via coerceBigDecimal(BigDecimal, Class)
.public static java.lang.Object coerceBigDecimal(java.math.BigDecimal bd, java.lang.Class<?> formalType)
BigDecimal
to the class given in the formalType
argument if that's a known numerical
type, returns the BigDecimal
as is otherwise. Overflow and precision loss are possible, similarly as
with casting in Java.public java.lang.String toString()
BeansWrapper
configuration properties, also if which (if any) shared class introspection cache it uses.toString
in class java.lang.Object
protected java.lang.String toPropertiesString()
BeansWrapper
; called from
toString()
. The expected format is like "foo=bar, baaz=wombat"
. When overriding this, you should
call the super method, and then insert the content before it with a following ", "
, or after it with a
preceding ", "
.