Over a million developers have joined DZone.

JavaFX Tips to Save Memory: Shadow Fields for Properties and Observables

In JavaFX, the Properties API allows developers to bind values to UI controls. This capability is surprisingly easy, but when object models use properties too often, an application can quickly run out of memory.

· Java Zone

Learn more about how the Java language, tools and frameworks have been the foundation of countless enterprise systems, brought to you in partnership with Salesforce.

In the world of JavaFX, the Properties API allows UI developers to bind values to UI controls. This capability is surprisingly easy; however, when object models use properties too often, an application can quickly run out of memory. I usually will write two separate objects such as a POJO class and a presentation model object. This technique is often used in Swing-based applications. From a JavaFX perspective, you could just create one object with properties to allow observers (listeners) to update values. This sounds fine, right? Not exactly, because the main issue is when all of the object’s (POJO) attributes (fields) are properties that also wrap actual values, the programmer (user of the API) may not want to bind or use properties at all, but only want to access the actual values. So, what is a JavaFX developer to do?

I often go to the blog Pixel Perfect by Dirk Lemmermann, who will often post very useful JavaFX tips. Recently, Dirk blogged about how to save memory using an interesting pattern called Shadow Fields.  To see his post, please visit his blog entry JavaFX Tip 23: Save Memory! Shadow Fields for Properties. Dirk’s JavaFX tip does help solve the problem mentioned above (lessening the heap); however, I noticed boilerplate code that has to exist to provide (a smart determination) to the caller of whether the return is the actual object or the property wrapper object. For example, instead of returning an IntegerProperty object when calling get or set methods, the code will return an int or Integer value, thus saving memory. Furthermore, the code declares two variables to hold one of the two value types. For example:

private String _title = "Untitled"; // shadow field
private StringProperty title;

I felt I could make things more concise and possibly save more memory while reducing the boilerplate code. I decided to create an interface with Java 8’s default methods that will handle managing actual values and properties. The user of the API will simply create a domain class that implements the following interface:

Interface PropertyAccessors

This is an interface providing accessor methods to provide a smart determination of the actual object value or the JavaFX property wrapper object. The user of the API must implement one method called getModelProperties(), which returns a Map of the property name (String) and its value (Object). The value can be an actual object or a Property type object. The code below also will support Observable lists.

package com.jfxbe;

import javafx.beans.property.Property;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

 * Provide default methods to support the similar
 * capability of the shadow fields pattern.
 * To save memory object values don't have to be
 * wrapped into a Property object when using getters
 * and setters, however when calling property type methods
 * values will be wrapped into a property object.
 * Default methods for Observable lists are provided too.
 * Created by cpdea on 4/3/16.
public interface PropertyAccessors {

    Map<String, Object> getModelProperties();

    default <T> T getValue(String name, Object defaultVal) {
        Object p = getModelProperties().get(name);
        p = p==null ? defaultVal : p;
        return (T) ((p instanceof Property) ? ((Property) p).getValue(): p);

    default void setValue(String name, Object value) {
        Object p = getModelProperties().get(name);
        if (p instanceof Property) {
        } else {
            getModelProperties().put(name, value);

    default <T> T refProperty(String name, Class propClass, Class rawValType) {
        Object p = getModelProperties().get(name);
        Property prop = null;

        try {

            if (p == null) {
                Class[] constructorTypes =
                        new Class[]{Object.class, String.class};
                Constructor<Property> propConstr =
                prop = propConstr.newInstance(this, name);
            } else if (rawValType.isInstance(p)) {
                Class[] constructorTypes = new Class[]{Object.class,
                        String.class, rawValType};
                Constructor<Property> propConstr =
                prop = propConstr.newInstance(this, name, p);
            } else {
                prop = (Property) p;
            getModelProperties().put(name, prop);
        } catch (Exception e) {
        return (T) prop;

    default <T> List<T> getValues(String name, List<T> defaultValue) {
        Object p, o = getModelProperties().get(name);
        p = o;
        o = o==null ? defaultValue : o;
        if (!o.equals(p)) {
            getModelProperties().put(name, o);
        return  (List<T>) o;

    default <T> void setValues(String name, List<T> newList) {
        Object list = getModelProperties().get(name);
        if (list == null || !(list instanceof ObservableList)) {
            getModelProperties().put(name, newList);
        } else {
            // Should the list be totally replaced? below clears and adds all items
            ObservableList<T> observableList = (ObservableList<T>) list;

    default <T> ObservableList<T> refObservables(String name) {
        List list = (List) getModelProperties().get(name);

        if (list == null) {
            list = FXCollections.observableArrayList(getValues(name, new ArrayList<>()));
            getModelProperties().put(name, list);

        if (! (list instanceof ObservableList)) {
            list = FXCollections.observableArrayList(list);
            getModelProperties().put(name, list);

        return (ObservableList<T>) list;

Employee Class

This is a class named Employee, which implements the PropertyAccessor interface. Below you will notice the property name of each field is declared using a public static final String. For example, the employee’s name is:

public static final String NAME_PROPERTY = “name”;

For the accessor methods such as getters, setters, and xyzProperty(), you will notice the calls to the default methods in the PropertyAccessor interface.

package com.jfxbe;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

 * A hybrid domain and model object using the shadow field pattern to save memory.
 * Created by cpdea
public class Employee implements PropertyAccessors{

    /** This is a map to hold properties and observables */
    private Map<String, Object> modelProperties;

    public static final String NAME_PROPERTY = "name";
    public static final String POWERS_PROPERTY = "powers";
    public static final String SUPERVISOR_PROPERTY = "supervisor";
    public static final String MINIONS_PROPERTY = "minions";

    public Employee(String name, String powers) {

    public Map<String, Object> getModelProperties() {
        if (modelProperties == null) {
            modelProperties = new HashMap<>();
        return modelProperties;

    public final String getName() {
        return getValue(NAME_PROPERTY, "");
    public final void setName(String name) {
        setValue(NAME_PROPERTY, name);
    public final StringProperty nameProperty() {
        return refProperty(NAME_PROPERTY, SimpleStringProperty.class, String.class);

    public String getPowers() {
        return getValue(POWERS_PROPERTY, "");

    public final StringProperty powersProperty() {
        return refProperty(POWERS_PROPERTY, StringProperty.class, String.class);

    public final void setPowers(String powers) {
        setValue(POWERS_PROPERTY, powers);

    public final Employee getSupervisor() {
        return getValue(SUPERVISOR_PROPERTY, null);

    public final ObjectProperty<Employee> supervisorProperty() {
        return refProperty(SUPERVISOR_PROPERTY, ObjectProperty.class, Employee.class);

    public final void setSupervisor(Employee supervisor) {
        setValue(SUPERVISOR_PROPERTY, supervisor);

    public final List<Employee> getMinions() {
        return getValues(MINIONS_PROPERTY, new ArrayList<>());

    public final ObservableList<Employee> minionsObservables() {
        return refObservables(MINIONS_PROPERTY);

    public final void setMinions(List<Employee> minions) {
        setValues(MINIONS_PROPERTY, minions);



So there you have it: a solution in an attempt to eliminate two variables and other boilerplate code. I haven’t actually tested the code with a large amount of data, so maybe in another post I (or some lucky reader) will create a test comparing all three implementations (the object with all properties, Dirk's, and mine).

The possible downside to this approach is probably serializing the object when used with RMI servers. I’m sure there are other possible downsides, but for now, for most use cases, this might be easier and cleaner code to deal with.

Discover how the Force.com Web Services Connector (WSC) is a code-generation tool and runtime library for use with Force.com Web services, brought to you in partnership with Salesforce.

javafx,memory management

Published at DZone with permission of Carl Dea. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}