Cache en la aplicación / widget GWT con HTML5 localStorage

stoy tratando de incorporar un caché de datos para uno de mis widgets de GWT.
Tengo una interfaz / clase de fuente de datos que recupera algunos datos de mi backend a través deRequestBuilder y JSON. Como visualizo el widget varias veces, solo quiero recuperar los datos una vez.

Así que traté de venir con un caché de aplicaciones. El enfoque ingenuo es utilizar unaHashMap en un objeto singleton para almacenar los datos. Sin embargo, también quiero hacer uso de localStorage / sessionStorage de HTML5 si es compatible.
HTML5 localStorage solo admite valores de cadena. Entonces tengo que convertir mi objeto en JSON y almacenarlo como una cadena. Sin embargo, de alguna manera no puedo encontrar una manera limpia y agradable de hacer esto. esto es lo que tengo hasta ahora.

Defino una interfaz con dos funciones:fetchStatsList() recupera la lista de estadísticas que se pueden mostrar en el widget yfetchStatsData() recupera los datos reales.

public interface DataSource {
    public void fetchStatsData(Stat stat,FetchStatsDataCallback callback);
    public void fetchStatsList(FetchStatsListCallback callback);
}

LosStat class es una clase simple de JavaScript Overlay JavaScriptObject) con algunos captadores (getName (), etc.) Tengo una implementación normal no almacenable en cachéRequestBuilderDataSource de mi DataSource que se parece a lo siguiente:

public class RequestBuilderDataSource implements DataSource {
    @Override
    public void fetchStatsList(final FetchStatsListCallback callback) {
         // create RequestBuilderRequest, retrieve response and parse JSON 
        callback.onFetchStatsList(stats);
    }

    @Override
    public void fetchStatsData(List<Stat> stats,final FetchStatsDataCallback callback) {
        String url = getStatUrl(stats);
        //create RequestBuilderRquest, retrieve response and parse JSON
        callback.onFetchStats(dataTable); //dataTable is of type DataTable
    }
}

ejé fuera la mayor parte del código para RequestBuilder, ya que es bastante sencill

Esto funciona de forma inmediata, sin embargo, la lista de estadísticas y también los datos se recuperan cada vez que se comparten los datos entre cada instancia de widge

Para admitir el almacenamiento en caché, agrego unCache interfaz y dos implementaciones de caché (una para HTML5 localStorage y otra para HashMap):

public interface Cache {
    void put(Object key, Object value);
    Object get(Object key);
    void remove(Object key);
    void clear();
}

Agrego una nueva claseRequestBuilderCacheDataSource que extiende elRequestBuilderDataSource y toma unCache instancia en su constructor.

public class RequestBuilderCacheDataSource extends RequestBuilderDataSource {

    private final Cache cache;

    publlic RequestBuilderCacheDataSource(final Cache cache) {
        this.cache = cache;
    }

    @Override
    public void fetchStatsList(final FetchStatsListCallback callback) {
       Object value = cache.get("list");
       if (value != null) {
           callback.fetchStatsList((List<Stat>)value);
       }
       else {
           super.fetchStatsList(stats,new FetchStatsListCallback() {
               @Override
               public void onFetchStatsList(List<Stat>stats) {
                   cache.put("list",stats);
                   callback.onFetchStatsList(stats);
               }
           });
           super.fetchStatsList(callback);
       }
    }

    @Override
    public void fetchStatsData(List<Stat> stats,final FetchStatsDataCallback callback) {
        String url = getStatUrl(stats);
        Object value = cache.get(url);
        if (value != null) {
            callback.onFetchStatsData((DataTable)value); 
        }
        else {
            super.fetchStatsData(stats,new FetchStatsDataCallback() {
                @Override
                public void onFetchStatsData(DataTable dataTable) {
                    cache.put(url,dataTable);
                    callback.onFetchStatsData(dataTable);
                }
            });
        }
    }
}

ásicamente, la nueva clase buscará el valor en elCache y si no se encuentra, llamará a la función de recuperación en la clase principal e interceptará la devolución de llamada para ponerla en la memoria caché y luego llamará a la devolución de llamada real.
Entonces, para admitir tanto el almacenamiento local HTML5 como el almacenamiento JS HashMap normal, creé dos implementaciones de miCache interfaz

JS HashMap storage:

public class DefaultcacheImpl implements Cache {
    private HashMap<Object, Object> map;

    public DefaultCacheImpl() {
        this.map = new HashMap<Object, Object>();
    }

    @Override
    public void put(Object key, Object value) {
        if (key == null) {
            throw new NullPointerException("key is null");
        }
        if (value == null) {
            throw new NullPointerException("value is null");
        }
        map.put(key, value);
    }

    @Override
    public Object get(Object key) {
        // Check for null as Cache should not store null values / keys
        if (key == null) {
            throw new NullPointerException("key is null");
        }
        return map.get(key);
    }

    @Override
    public void remove(Object key) {
        map.remove(key);
    }

    @Override
    public void clear() {
       map.clear();
    }
}

HTML5 localStorage:

public class LocalStorageImpl implements Cache{

    public static enum TYPE {LOCAL,SESSION} 
    private TYPE type;
    private Storage cacheStorage = null;

    public LocalStorageImpl(TYPE type) throws Exception {
        this.type = type;
        if (type == TYPE.LOCAL) {
            cacheStorage = Storage.getLocalStorageIfSupported();
        }
        else {
            cacheStorage = Storage.getSessionStorageIfSupported();
        }
        if (cacheStorage == null) {
            throw new Exception("LocalStorage not supported");
        }
    }


    @Override
    public void put(Object key, Object value) {
        //Convert Object (could be any arbitrary object) into JSON
        String jsonData = null;
        if (value instanceof List) {   // in case it is a list of Stat objects
            JSONArray array = new JSONArray();
            int index = 0;
            for (Object val:(List)value) {
                array.set(index,new JSONObject((JavaScriptObject)val));
                index = index +1;
            }
            jsonData = array.toString();
        }
        else  // in case it is a DataTable
        {
            jsonData = new JSONObject((JavaScriptObject) value).toString();
        }
        cacheStorage.setItem(key.toString(), jsonData);
    }

    @Override
    public Object get(Object key) {
        if (key == null) {
            throw new NullPointerException("key is null");
        }
        String jsonDataString = cacheStorage.getItem(key.toString());
        if (jsonDataString == null) {
            return null;
        }
        Object data = null;
        Object jsonData = JsonUtils.safeEval(jsonDataString);
        if (!key.equals("list")) 
            data = DataTable.create((JavaScriptObject)data);
        else if (jsonData instanceof JsArray){
            JsArray<GenomeStat> jsonStats = (JsArray<GenomeStat>)jsonData;
            List<GenomeStat> stats = new ArrayList<GenomeStat>();
            for (int i = 0;i<jsonStats.length();i++) {
                stats.add(jsonStats.get(i));
            }
            data = (Object)stats;
        }
        return data;
    }

    @Override
    public void remove(Object key) {
        cacheStorage.removeItem(key.toString());
    }

    @Override
    public void clear() {
        cacheStorage.clear();
    }

    public TYPE getType() {
        return type;
    }
}

La publicación se hizo un poco larga, pero espero aclare lo que intento alcanzar. Se reduce a dos preguntas:

Retroalimentación sobre el diseño / arquitectura de este enfoque (por ejemplo, subclasificar RequestBilderDataSource para la función de caché, etc.). ¿Se puede mejorar esto (esto probablemente esté más relacionado con el diseño general que específicamente con GWT).Con elDefaultCacheImpl es realmente fácil de almacenar y recuperar cualquier objeto arbitrario. ¿Cómo puedo lograr lo mismo con localStorage donde tengo que convertir y analizar JSON? Estoy usando unaDataTable que requiere llamar aDataTable.create(JavaScriptObject jso) función para trabajar. ¿Cómo puedo resolver esto sin muchos if / else e instancias de cheques?