/** * When wrapping an object, the BeansWrapper commonly needs to wrap * "sub-objects", for example each element in a wrapped collection. * Normally it wraps these objects using itself. However, this makes * it difficult to delegate to a BeansWrapper as part of a custom * aggregate ObjectWrapper. This method lets you set the ObjectWrapper * which will be used to wrap the sub-objects. * @param outerIdentity the aggregate ObjectWrapper */ public void setOuterIdentity(ObjectWrapper outerIdentity) { checkModifiable(); this.outerIdentity = outerIdentity; }
/** * Sets the default date type to use for date models that result from * a plain <tt>java.util.Date</tt> instead of <tt>java.sql.Date</tt> or * <tt>java.sql.Time</tt> or <tt>java.sql.Timestamp</tt>. Default value is * {@link TemplateDateModel#UNKNOWN}. * @param defaultDateType the new default date type. */ public void setDefaultDateType(int defaultDateType) { // This sync is here as this method was originally synchronized, but was never truly thread-safe, so I don't // want to advertise it in the javadoc, nor I wanted to break any apps that work because of this accidentally. synchronized (this) { checkModifiable(); this.defaultDateType = defaultDateType; } }
/** * Sets whether methods shadow items in beans. When true (this is the * default value), <code>${object.name}</code> 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 * <code>object.get(name)</code>, 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 setMethodsShadowItems(boolean methodsShadowItems) { // This sync is here as this method was originally synchronized, but was never truly thread-safe, so I don't // want to advertise it in the javadoc, nor I wanted to break any apps that work because of this accidentally. synchronized (this) { checkModifiable(); this.methodsShadowItems = methodsShadowItems; } }
/** * Sets if when a JavaBean property has both a normal read method (like {@code String[] getFoos()}) and an indexed * read method (like {@code String getFoos(int index)}), and the Java {@link 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 {@code myObj.foos}). Before {@link #getIncompatibleImprovements() incompatibleImprovements} * 2.3.27 it defaults to {@code 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 * {@link #getIncompatibleImprovements() incompatibleImprovements} 2.3.27 is {@code 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 ({@code <#list foo as myObj.foos>} will fail). * * <p> * Apparently, this setting only matters since Java 8, as before that {@link Introspector} did not expose the * indexed reader method if there was also a normal reader method. As with Java 8 the behavior of * {@link Introspector} has changed, some old templates started to break, as the property has suddenly become * unlistable (see earlier why). So setting this to {@code false} can be seen as a Java 8 compatibility fix. * * @since 2.3.27 */ public void setPreferIndexedReadMethod(boolean preferIndexedReadMethod) { checkModifiable(); this.preferIndexedReadMethod = preferIndexedReadMethod; }
/** * When set to {@code true}, the keys in {@link Map}-s won't mix with the method names when looking at them * from templates. The default is {@code false} for backward-compatibility, but is not recommended. * * <p>When this is {@code false}, {@code myMap.foo} or {@code myMap['foo']} either returns the method {@code foo}, * or calls {@code Map.get("foo")}. If both exists (the method and the {@link Map} key), one will hide the other, * depending on the {@link #isMethodsShadowItems()}, which default to {@code true} (the method * wins). Some frameworks use this so that you can call {@code 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 * {@link Map} entries (or the other way around). Thus, this setup is not recommended. * (Technical note: {@link Map}-s will be wrapped into {@link MapModel} in this case.) * * <p>When this is {@code true}, {@code myMap.foo} or {@code myMap['foo']} always calls {@code Map.get("foo")}. * The methods of the {@link Map} object aren't visible from templates in this case. This, however, spoils the * {@code myMap.get(nonStringKey)} workaround. But now you can use {@code myMap(nonStringKey)} instead, that is, you * can use the map itself as the {@code get} method. * (Technical note: {@link Map}-s will be wrapped into {@link SimpleMapModel} in this case.) * * <p>*: For historical reasons, FreeMarker 2.3.X doesn't support non-string keys with the {@code []} 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 {@code myMap.get} can return the {@code get} * method. */ public void setSimpleMapWrapper(boolean simpleMapWrapper) { checkModifiable(); this.simpleMapWrapper = simpleMapWrapper; }
/** * Specifies if an attempt to read a bean property that doesn't exist in the * wrapped object should throw an {@link InvalidPropertyException}. * * <p>If this property is <tt>false</tt> (the default) then an attempt to read * a missing bean property is the same as reading an existing bean property whose * value is <tt>null</tt>. The template can't tell the difference, and thus always * can use <tt>?default('something')</tt> and <tt>?exists</tt> and similar built-ins * to handle the situation. * * <p>If this property is <tt>true</tt> then an attempt to read a bean propertly in * the template (like <tt>myBean.aProperty</tt>) that doesn't exist in the bean * object (as opposed to just holding <tt>null</tt> value) will cause * {@link InvalidPropertyException}, which can't be suppressed in the template * (not even with <tt>myBean.noSuchProperty?default('something')</tt>). This way * <tt>?default('something')</tt> and <tt>?exists</tt> and similar built-ins can be used to * handle existing properties whose value is <tt>null</tt>, 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 setStrict(boolean strict) { checkModifiable(); this.strict = strict; }
/** * Sets the null model. This model is returned from the {@link #wrap(Object)} method whenever the wrapped object is * {@code null}. It defaults to {@code 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 * {@code nullModel} should be an {@link AdapterTemplateModel} that returns {@code null} for * {@link AdapterTemplateModel#getAdaptedObject(Class)}. * * @deprecated Changing the {@code null} model can cause a lot of confusion; don't do it. */ @Deprecated public void setNullModel(TemplateModel nullModel) { checkModifiable(); this.nullModel = nullModel; }
/** * Sets whether this wrapper caches the {@link TemplateModel}-s created for the Java objects that has wrapped with * this object wrapper. Default is {@code false}. * When set to {@code true}, calling {@link #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 void setUseCache(boolean useCache) { checkModifiable(); modelCache.setUseCache(useCache); }
void setMethodSorter(MethodSorter methodSorter) { checkModifiable(); if (classIntrospector.getMethodSorter() != methodSorter) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setMethodSorter(methodSorter); replaceClassIntrospector(builder); } }
/** * Used to tweak certain aspects of how methods appear in the data-model; * see {@link MethodAppearanceFineTuner} for more. */ public void setMethodAppearanceFineTuner(MethodAppearanceFineTuner methodAppearanceFineTuner) { checkModifiable(); if (classIntrospector.getMethodAppearanceFineTuner() != methodAppearanceFineTuner) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setMethodAppearanceFineTuner(methodAppearanceFineTuner); replaceClassIntrospector(builder); } }
/** * Sets the method exposure level. By default, set to <code>EXPOSE_SAFE</code>. * @param exposureLevel can be any of the <code>EXPOSE_xxx</code> * constants. */ public void setExposureLevel(int exposureLevel) { checkModifiable(); if (classIntrospector.getExposureLevel() != exposureLevel) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setExposureLevel(exposureLevel); replaceClassIntrospector(builder); } }
/** * Controls whether public instance fields of classes are exposed to * templates. * @param 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 setExposeFields(boolean exposeFields) { checkModifiable(); if (classIntrospector.getExposeFields() != exposeFields) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setExposeFields(exposeFields); replaceClassIntrospector(builder); } }
/** * 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. (We expose bean properties and bean * actions, not methods in general.) Before {@link #getIncompatibleImprovements incompatibleImprovements} 2.3.26 * this defaults to {@code false} for backward compatibility. Starting with {@link #getIncompatibleImprovements * incompatibleImprovements} 2.3.26 it defaults to {@code true}. * <p> * Some explanation: FreeMarker uses {@link java.beans.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 {@code true}, we search for non-overridden default methods ourselves, and add them to the set of * discovered bean members. * * @since 2.3.26 */ public void setTreatDefaultMethodsAsBeanMembers(boolean treatDefaultMethodsAsBeanMembers) { checkModifiable(); if (classIntrospector.getTreatDefaultMethodsAsBeanMembers() != treatDefaultMethodsAsBeanMembers) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setTreatDefaultMethodsAsBeanMembers(treatDefaultMethodsAsBeanMembers); replaceClassIntrospector(builder); } }
/** * Sets whether this wrapper caches the {@link TemplateModel}-s created for the Java objects that has wrapped with * this object wrapper. Default is {@code false}. * When set to {@code true}, calling {@link #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 void setUseCache(boolean useCache) { checkModifiable(); modelCache.setUseCache(useCache); }
/** * Sets whether this wrapper caches the {@link TemplateModel}-s created for the Java objects that has wrapped with * this object wrapper. Default is {@code false}. * When set to {@code true}, calling {@link #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 void setUseCache(boolean useCache) { checkModifiable(); modelCache.setUseCache(useCache); }
/** * Used to tweak certain aspects of how methods appear in the data-model; * see {@link MethodAppearanceFineTuner} for more. */ public void setMethodAppearanceFineTuner(MethodAppearanceFineTuner methodAppearanceFineTuner) { checkModifiable(); if (classIntrospector.getMethodAppearanceFineTuner() != methodAppearanceFineTuner) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setMethodAppearanceFineTuner(methodAppearanceFineTuner); replaceClassIntrospector(builder); } }
/** * Used to tweak certain aspects of how methods appear in the data-model; * see {@link MethodAppearanceFineTuner} for more. */ public void setMethodAppearanceFineTuner(MethodAppearanceFineTuner methodAppearanceFineTuner) { checkModifiable(); if (classIntrospector.getMethodAppearanceFineTuner() != methodAppearanceFineTuner) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setMethodAppearanceFineTuner(methodAppearanceFineTuner); replaceClassIntrospector(builder); } }
void setMethodSorter(MethodSorter methodSorter) { checkModifiable(); if (classIntrospector.getMethodSorter() != methodSorter) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setMethodSorter(methodSorter); replaceClassIntrospector(builder); } }
/** * Sets the method exposure level. By default, set to <code>EXPOSE_SAFE</code>. * @param exposureLevel can be any of the <code>EXPOSE_xxx</code> * constants. */ public void setExposureLevel(int exposureLevel) { checkModifiable(); if (classIntrospector.getExposureLevel() != exposureLevel) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setExposureLevel(exposureLevel); replaceClassIntrospector(builder); } }