changeset 904:6e38be537e2a

Register data-class with categories. Reviewed-by: vanaltj http://icedtea.classpath.org/pipermail/thermostat/2013-January/005069.html
author Roman Kennke <rkennke@redhat.com>
date Thu, 10 Jan 2013 21:47:29 +0100
parents 4de458324cf9
children 6da66da9e8ac
files common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/CpuStatDAO.java host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/MemoryStatDAO.java host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Category.java storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java storage/core/src/test/java/com/redhat/thermostat/storage/core/CategoryTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoQuery.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoCursorTest.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoQueryTest.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/VmClassStatDAO.java vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/VmCpuStatDAO.java vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/VmGcStatDAO.java vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDAO.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/VmMemoryStatDAO.java vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java web/common/src/main/java/com/redhat/thermostat/web/common/WebQuery.java web/common/src/main/java/com/redhat/thermostat/web/common/WebRemove.java web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryTest.java web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java
diffstat 61 files changed, 296 insertions(+), 328 deletions(-) [+]
line wrap: on
line diff
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -49,7 +49,7 @@
     static final Key<Boolean> ALIVE_KEY = new Key<>("alive", false);
     static final Key<String> CONFIG_LISTEN_ADDRESS = new Key<>("configListenAddress", false);
 
-    static final Category CATEGORY = new Category("agent-config",
+    static final Category<AgentInformation> CATEGORY = new Category<>("agent-config", AgentInformation.class,
             Key.AGENT_ID,
             START_TIME_KEY,
             STOP_TIME_KEY,
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -65,7 +65,7 @@
 
     @Override
     public List<AgentInformation> getAllAgentInformation() {
-        Query<AgentInformation> query = storage.createQuery(CATEGORY, AgentInformation.class);
+        Query<AgentInformation> query = storage.createQuery(CATEGORY);
         Cursor<AgentInformation> agentCursor = query.execute();
 
         List<AgentInformation> results = new ArrayList<>();
@@ -79,7 +79,7 @@
 
     @Override
     public List<AgentInformation> getAliveAgents() {
-        Query<AgentInformation> query = storage.createQuery(CATEGORY, AgentInformation.class);
+        Query<AgentInformation> query = storage.createQuery(CATEGORY);
         query.where(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true);
 
         Cursor<AgentInformation> agentCursor = query.execute();
@@ -95,7 +95,7 @@
 
     @Override
     public AgentInformation getAgentInformation(HostRef agentRef) {
-        Query<AgentInformation> query = storage.createQuery(CATEGORY, AgentInformation.class);
+        Query<AgentInformation> query = storage.createQuery(CATEGORY);
         query.where(Key.AGENT_ID, Criteria.EQUALS, agentRef.getAgentId());
         query.limit(1);
         return query.execute().next();
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -51,7 +51,7 @@
     static final Key<List<Integer>> PIDS_TO_MONITOR = new Key<>("pids", false);
     static final Key<Integer> ORDER_VALUE = new Key<>("orderValue", false);
 
-    static final Category CATEGORY = new Category("backend-info",
+    static final Category<BackendInformation> CATEGORY = new Category<>("backend-info", BackendInformation.class,
             Key.AGENT_ID,
             BACKEND_NAME,
             BACKEND_DESCRIPTION,
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -62,7 +62,7 @@
     @Override
     public List<BackendInformation> getBackendInformation(HostRef host) {
         // Sort by order value
-        Query<BackendInformation> query = storage.createQuery(CATEGORY, BackendInformation.class);
+        Query<BackendInformation> query = storage.createQuery(CATEGORY);
         query.where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId());
 
         List<BackendInformation> results = new ArrayList<>();
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -51,7 +51,7 @@
     static Key<String> cpuModelKey = new Key<>("cpuModel", false);
     static Key<Long> hostMemoryTotalKey = new Key<>("totalMemory", false);
 
-    static final Category hostInfoCategory = new Category("host-info",
+    static final Category<HostInfo> hostInfoCategory = new Category<>("host-info", HostInfo.class,
             Key.AGENT_ID, hostNameKey, osNameKey, osKernelKey,
             cpuCountKey, cpuModelKey, hostMemoryTotalKey);
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -63,7 +63,7 @@
 
     @Override
     public HostInfo getHostInfo(HostRef ref) {
-        Query<HostInfo> query = storage.createQuery(hostInfoCategory, HostInfo.class);
+        Query<HostInfo> query = storage.createQuery(hostInfoCategory);
         query.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId());
         query.limit(1);
         HostInfo result = query.execute().next();
@@ -79,7 +79,7 @@
 
     @Override
     public Collection<HostRef> getHosts() {
-        Query<HostInfo> allHosts = storage.createQuery(hostInfoCategory, HostInfo.class);
+        Query<HostInfo> allHosts = storage.createQuery(hostInfoCategory);
         return getHosts(allHosts);
     }
 
@@ -88,7 +88,7 @@
         List<HostRef> hosts = new ArrayList<>();
         List<AgentInformation> agentInfos = agentInfoDao.getAliveAgents();
         for (AgentInformation agentInfo : agentInfos) {
-            Query<HostInfo> filter = storage.createQuery(hostInfoCategory, HostInfo.class);
+            Query<HostInfo> filter = storage.createQuery(hostInfoCategory);
             filter.where(Key.AGENT_ID, Criteria.EQUALS, agentInfo.getAgentId());
             hosts.addAll(getHosts(filter));
         }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java	Thu Jan 10 21:47:29 2013 +0100
@@ -50,13 +50,11 @@
 public class HostLatestPojoListGetter<T extends TimeStampedPojo> {
 
     private final Storage storage;
-    private final Category cat;
-    private final Class<T> resultClass;
+    private final Category<T> cat;
 
-    public HostLatestPojoListGetter(Storage storage, Category cat, Class<T> resultClass) {
+    public HostLatestPojoListGetter(Storage storage, Category<T> cat) {
         this.storage = storage;
         this.cat = cat;
-        this.resultClass = resultClass;
     }
 
     public List<T> getLatest(HostRef hostRef, long since) {
@@ -75,7 +73,7 @@
     }
 
     protected Query<T> buildQuery(HostRef hostRef, long since) {
-        Query<T> query = storage.createQuery(cat, resultClass);
+        Query<T> query = storage.createQuery(cat);
         query.where(Key.AGENT_ID, Criteria.EQUALS, hostRef.getAgentId());
         query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since);
         query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -48,7 +48,7 @@
     static Key<String> ip4AddrKey = new Key<>("ip4Addr", false);
     static Key<String> ip6AddrKey = new Key<>("ip6Addr", false);
 
-    static final Category networkInfoCategory = new Category("network-info",
+    static final Category<NetworkInterfaceInfo> networkInfoCategory = new Category<>("network-info", NetworkInterfaceInfo.class,
             Key.AGENT_ID, ifaceKey, ip4AddrKey, ip6AddrKey);
 
     public List<NetworkInterfaceInfo> getNetworkInterfaces(HostRef ref);
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -58,7 +58,7 @@
 
     @Override
     public List<NetworkInterfaceInfo> getNetworkInterfaces(HostRef ref) {
-        Query<NetworkInterfaceInfo> allHostNetworkInterfaces = storage.createQuery(networkInfoCategory, NetworkInterfaceInfo.class);
+        Query<NetworkInterfaceInfo> allHostNetworkInterfaces = storage.createQuery(networkInfoCategory);
         allHostNetworkInterfaces.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId());
 
         Cursor<NetworkInterfaceInfo> cursor = allHostNetworkInterfaces.execute();
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -61,7 +61,7 @@
     static final Key<Long> startTimeKey = new Key<>("startTimeStamp", false);
     static final Key<Long> stopTimeKey = new Key<>("stopTimeStamp", false);
 
-    static final Category vmInfoCategory = new Category("vm-info",
+    static final Category<VmInfo> vmInfoCategory = new Category<>("vm-info", VmInfo.class,
             Key.AGENT_ID, Key.VM_ID, vmPidKey, runtimeVersionKey, javaHomeKey,
             mainClassKey, commandLineKey,
             vmArgumentsKey, vmNameKey, vmInfoKey, vmVersionKey,
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -60,7 +60,7 @@
 
     @Override
     public VmInfo getVmInfo(VmRef ref) {
-        Query<VmInfo> findMatchingVm = storage.createQuery(vmInfoCategory, VmInfo.class);
+        Query<VmInfo> findMatchingVm = storage.createQuery(vmInfoCategory);
         findMatchingVm.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgent().getAgentId());
         findMatchingVm.where(Key.VM_ID, Criteria.EQUALS, ref.getId());
         findMatchingVm.limit(1);
@@ -80,7 +80,7 @@
     }
 
     private Query<VmInfo> buildQuery(HostRef host) {
-        Query<VmInfo> query = storage.createQuery(vmInfoCategory, VmInfo.class);
+        Query<VmInfo> query = storage.createQuery(vmInfoCategory);
         query.where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId());
         return query;
     }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java	Thu Jan 10 21:47:29 2013 +0100
@@ -50,13 +50,11 @@
 public class VmLatestPojoListGetter<T extends TimeStampedPojo> {
 
     private final Storage storage;
-    private final Category cat;
-    private final Class<T> resultClass;
+    private final Category<T> cat;
 
-    public VmLatestPojoListGetter(Storage storage, Category cat, Class<T> resultClass) {
+    public VmLatestPojoListGetter(Storage storage, Category<T> cat) {
         this.storage = storage;
         this.cat = cat;
-        this.resultClass = resultClass;
     }
 
     public List<T> getLatest(VmRef vmRef, long since) {
@@ -75,7 +73,7 @@
     }
 
     protected Query<T> buildQuery(VmRef vmRef, long since) {
-        Query<T> query = storage.createQuery(cat, resultClass);
+        Query<T> query = storage.createQuery(cat);
         query.where(Key.AGENT_ID, Criteria.EQUALS, vmRef.getAgent().getAgentId());
         query.where(Key.VM_ID, Criteria.EQUALS, vmRef.getId());
         query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since);
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -40,7 +40,6 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -121,7 +120,7 @@
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
         when(query.execute()).thenReturn(agentCursor);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         AgentInfoDAOImpl dao = new AgentInfoDAOImpl(storage);
 
         List<AgentInformation> allAgentInfo = dao.getAllAgentInformation();
@@ -142,13 +141,13 @@
 
         Query query = mock(Query.class);
         Storage storage = mock(Storage.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(agentCursor);
 
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
         List<AgentInformation> aliveAgents = dao.getAliveAgents();
 
-        verify(storage).createQuery(AgentInfoDAO.CATEGORY, AgentInformation.class);
+        verify(storage).createQuery(AgentInfoDAO.CATEGORY);
         verify(query).where(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true);
         verify(query).execute();
         verifyNoMoreInteractions(query);
@@ -171,7 +170,7 @@
         when(query.execute()).thenReturn(cursor);
 
         Storage storage = mock(Storage.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
 
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
 
@@ -187,7 +186,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         Cursor cursor = mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(agentInfo1).thenReturn(null);
@@ -196,7 +195,7 @@
 
         AgentInformation computed = dao.getAgentInformation(agentRef);
 
-        verify(storage).createQuery(AgentInfoDAO.CATEGORY, AgentInformation.class);
+        verify(storage).createQuery(AgentInfoDAO.CATEGORY);
         verify(query).where(Key.AGENT_ID, Criteria.EQUALS, agentInfo1.getAgentId());
         verify(query).limit(1);
         verify(query).execute();
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -137,14 +137,14 @@
 
         Query query = mock(Query.class);
         Storage storage = mock(Storage.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(backendCursor);
 
         BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
 
         List<BackendInformation> result = dao.getBackendInformation(agentref);
 
-        verify(storage).createQuery(BackendInfoDAO.CATEGORY, BackendInformation.class);
+        verify(storage).createQuery(BackendInfoDAO.CATEGORY);
         verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
         verify(query).execute();
         verifyNoMoreInteractions(query);
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -98,7 +98,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         HostInfo info = new HostInfo(HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
         Cursor cursor = mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
@@ -135,7 +135,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
         
         return storage;
@@ -173,7 +173,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
         
         return storage;
@@ -218,7 +218,7 @@
 
         assertEquals(1, hosts.size());
         assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
-        verify(storage).createQuery(HostInfoDAO.hostInfoCategory, HostInfo.class);
+        verify(storage).createQuery(HostInfoDAO.hostInfoCategory);
     }
     
     private Pair<Storage, AgentInfoDAO> setupForSingleAliveHost() {
@@ -255,7 +255,7 @@
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
         
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor1);
 
         AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
@@ -278,7 +278,7 @@
         assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
         assertTrue(hosts.contains(new HostRef("456", "fluffhost2")));
         assertTrue(hosts.contains(new HostRef("678", "fluffhost3")));
-        verify(storage, atLeast(3)).createQuery(HostInfoDAO.hostInfoCategory, HostInfo.class);
+        verify(storage, atLeast(3)).createQuery(HostInfoDAO.hostInfoCategory);
     }
     
     private Pair<Storage, AgentInfoDAO> setupForAliveHost3() {
@@ -329,7 +329,7 @@
         
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor1).thenReturn(cursor2).thenReturn(cursor3);
         
         AgentInfoDAO agentDao = mock(AgentInfoDAO.class);
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -66,7 +66,7 @@
     private static final String CATEGORY_NAME = "hostcategory";
     // Make this one static so we don't get IllegalStateException from trying
     // to make category of same name while running tests in same classloader.
-    private static final Category cat =  new Category(CATEGORY_NAME);
+    private static final Category<CpuStat> cat =  new Category<>(CATEGORY_NAME, CpuStat.class);
 
     private static long t1 = 1;
     private static long t2 = 5;
@@ -99,13 +99,13 @@
     public void testBuildQuery() {
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when (storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when (storage.createQuery(any(Category.class))).thenReturn(query);
 
-        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, CpuStat.class);
+        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat);
         query = getter.buildQuery(ref, 123);
 
         assertNotNull(query);
-        verify(storage).createQuery(cat, CpuStat.class);
+        verify(storage).createQuery(cat);
         verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l);
         verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
         verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
@@ -117,15 +117,15 @@
         Storage storage = mock(Storage.class);
         Query ignored = mock(Query.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(ignored).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(ignored).thenReturn(query);
 
-        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, CpuStat.class);
+        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat);
         ignored = getter.buildQuery(ref,Long.MIN_VALUE); // Ignore first return value.
 
         query = getter.buildQuery(ref, Long.MIN_VALUE);
 
         assertNotNull(query);
-        verify(storage, times(2)).createQuery(cat, CpuStat.class);
+        verify(storage, times(2)).createQuery(cat);
         verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
         verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
         verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
@@ -141,10 +141,10 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
 
-        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, CpuStat.class);
+        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat);
 
         List<CpuStat> stats = getter.getLatest(ref, Long.MIN_VALUE);
 
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -53,9 +53,9 @@
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query;
+import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
 
 public class NetworkInterfaceInfoDAOTest {
@@ -91,7 +91,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -125,7 +125,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         VmInfo expected = new VmInfo(vmId, startTime, stopTime, jVersion, jHome, mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs, props, env, libs);
         Cursor cursor = mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
@@ -149,7 +149,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         Cursor cursor = mock(Cursor.class);
         when(query.execute()).thenReturn(cursor);
         
@@ -194,7 +194,7 @@
 
       Storage storage = mock(Storage.class);
       Query query = mock(Query.class);
-      when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+      when(storage.createQuery(any(Category.class))).thenReturn(query);
       when(query.execute()).thenReturn(singleVMCursor);
       return storage;
   }
@@ -228,7 +228,7 @@
 
       Storage storage = mock(Storage.class);
       Query query = mock(Query.class);
-      when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+      when(storage.createQuery(any(Category.class))).thenReturn(query);
       when(query.execute()).thenReturn(multiVMsCursor);
       return storage;
   }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -66,7 +66,7 @@
     private static final String CATEGORY_NAME = "vmcategory";
     // Make this one static so we don't get IllegalStateException from trying
     // to make category of same name while running tests in same classloader.
-    private static final Category cat =  new Category(CATEGORY_NAME);
+    private static final Category<VmClassStat> cat =  new Category<>(CATEGORY_NAME, VmClassStat.class);
 
     private static long t1 = 1;
     private static long t2 = 5;
@@ -93,13 +93,13 @@
     public void testBuildQuery() {
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
 
-        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, VmClassStat.class);
+        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat);
         query = getter.buildQuery(vmRef, 123l);
 
         assertNotNull(query);
-        verify(storage).createQuery(cat, VmClassStat.class);
+        verify(storage).createQuery(cat);
         verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
         verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_PID);
         verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l);
@@ -112,14 +112,14 @@
         Storage storage = mock(Storage.class);
         Query ignored = mock(Query.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(ignored).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(ignored).thenReturn(query);
 
-        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, VmClassStat.class);
+        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat);
         getter.buildQuery(vmRef, Long.MIN_VALUE); // Ignore first return value.
         query = getter.buildQuery(vmRef, Long.MIN_VALUE);
 
         assertNotNull(query);
-        verify(storage, times(2)).createQuery(cat, VmClassStat.class);
+        verify(storage, times(2)).createQuery(cat);
         verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
         verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_PID);
         verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
@@ -136,14 +136,14 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
 
-        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, VmClassStat.class);
+        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat);
 
         List<VmClassStat> stats = getter.getLatest(vmRef, t2);
 
-        verify(storage).createQuery(cat, VmClassStat.class);
+        verify(storage).createQuery(cat);
         verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
         verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_PID);
         verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, t2);
--- a/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/CpuStatDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/CpuStatDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -48,7 +48,7 @@
 
     static Key<List<Double>> cpuLoadKey = new Key<>("perProcessorUsage", false);
 
-    static final Category cpuStatCategory = new Category("cpu-stats",
+    static final Category<CpuStat> cpuStatCategory = new Category<>("cpu-stats", CpuStat.class,
             Key.AGENT_ID, Key.TIMESTAMP, cpuLoadKey);
 
     List<CpuStat> getLatestCpuStats(HostRef ref, long since);
--- a/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -54,7 +54,7 @@
     CpuStatDAOImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(cpuStatCategory);
-        this.getter = new HostLatestPojoListGetter<>(storage, cpuStatCategory, CpuStat.class);
+        this.getter = new HostLatestPojoListGetter<>(storage, cpuStatCategory);
     }
 
     @Override
--- a/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -93,7 +93,7 @@
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(cpuStat);
 
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
         when(hostRef.getAgentId()).thenReturn("system");
 
@@ -128,7 +128,7 @@
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(cpuStat);
 
-        when(storage.createQuery(CpuStatDAO.cpuStatCategory, CpuStat.class)).thenReturn(query);
+        when(storage.createQuery(CpuStatDAO.cpuStatCategory)).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
         when(hostRef.getAgentId()).thenReturn("system");
 
--- a/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/MemoryStatDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/MemoryStatDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -54,7 +54,7 @@
     static Key<Long> memorySwapFreeKey = new Key<>("swapFree", false);
     static Key<Long> memoryCommitLimitKey = new Key<>("commitLimit", false);
 
-    static final Category memoryStatCategory = new Category("memory-stats",
+    static final Category<MemoryStat> memoryStatCategory = new Category<>("memory-stats", MemoryStat.class,
             Key.AGENT_ID, Key.TIMESTAMP, memoryTotalKey, memoryFreeKey, memoryBuffersKey,
             memoryCachedKey, memorySwapTotalKey, memorySwapFreeKey, memoryCommitLimitKey);
 
--- a/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -54,7 +54,7 @@
     MemoryStatDAOImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(memoryStatCategory);
-        this.getter = new HostLatestPojoListGetter<>(storage, memoryStatCategory, MemoryStat.class);
+        this.getter = new HostLatestPojoListGetter<>(storage, memoryStatCategory);
     }
 
     @Override
--- a/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -103,7 +103,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
@@ -112,7 +112,7 @@
         MemoryStatDAO dao = new MemoryStatDAOImpl(storage);
         List<MemoryStat> memoryStats = dao.getLatestMemoryStats(hostRef, Long.MIN_VALUE);
 
-        verify(storage).createQuery(MemoryStatDAO.memoryStatCategory, MemoryStat.class);
+        verify(storage).createQuery(MemoryStatDAO.memoryStatCategory);
         verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
         verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system");
         verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Category.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Category.java	Thu Jan 10 21:47:29 2013 +0100
@@ -42,15 +42,20 @@
 import java.util.Map;
 import java.util.Objects;
 
+import com.redhat.thermostat.storage.model.Pojo;
+
 /**
  * A bag of data
  */
-public class Category {
+public class Category<T extends Pojo> {
+
     private String name;
     private final Map<String, Key<?>> keys;
+    private transient Class<T> dataClass;
+    private String dataClassName;
 
     public Category() {
-        this(null);
+        this(null, null);
     }
 
     /**
@@ -60,20 +65,21 @@
      *
      * @throws IllegalArgumentException if a Category is created with a name that has been used before
      */
-    public Category(String name, Key<?>... keys) {
+    public Category(String name, Class<T> dataClass, Key<?>... keys) {
         Map<String, Key<?>> keysMap = new HashMap<String, Key<?>>();
         for (Key<?> key : keys) {
             keysMap.put(key.getName(), key);
         }
         this.keys = Collections.unmodifiableMap(keysMap);
         setName(name);
+        setDataClass(dataClass);
     }
 
     public String getName() {
         return name;
     }
 
-    public void setName(String name) {
+    private void setName(String name) {
         if (Categories.contains(name)) {
             throw new IllegalStateException();
         }
@@ -85,6 +91,29 @@
         }
     }
 
+    private void setDataClass(Class<T> dataClass) {
+        this.dataClass = dataClass;
+        if (dataClass != null) {
+            dataClassName = dataClass.getName();
+        }
+    }
+
+    public Class<T> getDataClass() {
+        if (dataClass == null && dataClassName != null) {
+            initializeDataClassFromName();
+        }
+        return dataClass;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void initializeDataClassFromName() {
+        try {
+            dataClass = (Class<T>) Class.forName(dataClassName);
+        } catch (ClassNotFoundException e) {
+            throw new StorageException(e);
+        }
+    }
+
     public synchronized Collection<Key<?>> getKeys() {
         return keys.values();
     }
@@ -105,7 +134,7 @@
         if (! (o instanceof Category)) {
             return false;
         }
-        Category other = (Category) o;
+        Category<?> other = (Category<?>) o;
         return Objects.equals(name, other.name) && Objects.equals(keys, other.keys);
     }
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Thu Jan 10 21:47:29 2013 +0100
@@ -128,20 +128,20 @@
     }
 
     @Override
-    public Add createAdd(Category into) {
+    public Add createAdd(Category<?> into) {
         QueuedAdd add = new QueuedAdd();
         add.setCategory(into);
         return add;
     }
 
     @Override
-    public Replace createReplace(Category into) {
+    public Replace createReplace(Category<?> into) {
         QueuedReplace replace = new QueuedReplace();
         replace.setCategory(into);
         return replace;
     }
 
-    private void replaceImpl(final Category category, final Pojo pojo) {
+    private void replaceImpl(final Category<?> category, final Pojo pojo) {
         
         executor.execute(new Runnable() {
             
@@ -156,7 +156,7 @@
 
     }
 
-    private void addImpl(final Category category, final Pojo pojo) {
+    private void addImpl(final Category<?> category, final Pojo pojo) {
         
         executor.execute(new Runnable() {
             
@@ -228,12 +228,12 @@
     }
 
     @Override
-    public <T extends Pojo> Query<T> createQuery(Category category, Class<T> resultClass) {
-        return delegate.createQuery(category, resultClass);
+    public <T extends Pojo> Query<T> createQuery(Category<T> category) {
+        return delegate.createQuery(category);
     }
 
     @Override
-    public Update createUpdate(Category category) {
+    public Update createUpdate(Category<?> category) {
         QueuedUpdate update = new QueuedUpdate(delegate.createUpdate(category));
         return update;
     }
@@ -263,7 +263,7 @@
     }
 
     @Override
-    public void registerCategory(final Category category) {
+    public void registerCategory(final Category<?> category) {
         delegate.registerCategory(category);
     }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Thu Jan 10 21:47:29 2013 +0100
@@ -52,12 +52,12 @@
 
     String getAgentId();
 
-    void registerCategory(Category category);
+    void registerCategory(Category<?> category);
 
     Connection getConnection();
 
-    Add createAdd(Category category);
-    Replace createReplace(Category category);
+    Add createAdd(Category<?> category);
+    Replace createReplace(Category<?> category);
 
     void removePojo(Remove remove);
 
@@ -66,15 +66,15 @@
      */
     void purge();
 
-    long getCount(Category category);
+    long getCount(Category<?> category);
 
     void saveFile(String filename, InputStream data);
 
     InputStream loadFile(String filename);
 
-    <T extends Pojo> Query<T> createQuery(Category category, Class<T> resultClass);
+    <T extends Pojo> Query<T> createQuery(Category<T> category);
 
-    Update createUpdate(Category category);
+    Update createUpdate(Category<?> category);
     Remove createRemove();
 
 
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/CategoryTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/CategoryTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -44,22 +44,25 @@
 
 import org.junit.Test;
 
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.model.Pojo;
 
 public class CategoryTest {
 
+    private static class TestObj implements Pojo {
+        // Dummy class for testing.
+    }
+
     @Test
     public void testGetKey() {
         Key<String> key1 = new Key<String>("key1", false);
-        Category category = new Category("testGetKey", key1);
+        Category<TestObj> category = new Category<>("testGetKey", TestObj.class, key1);
         assertEquals(key1, category.getKey("key1"));
     }
 
     @Test
     public void testGetNonExistingKey() {
         Key<String> key1 = new Key<String>("key1", false);
-        Category category = new Category("testGetNonExistingKey", key1);
+        Category<TestObj> category = new Category<>("testGetNonExistingKey", TestObj.class, key1);
         assertNull(category.getKey("key2"));
     }
 
@@ -69,7 +72,7 @@
         Key<String> key2 = new Key<String>("key2", false);
         Key<String> key3 = new Key<String>("key3", false);
         Key<String> key4 = new Key<String>("key4", false);
-        Category category = new Category("testGetKeys", key1, key2, key3, key4);
+        Category<TestObj> category = new Category<>("testGetKeys", TestObj.class, key1, key2, key3, key4);
         assertEquals(4, category.getKeys().size());
         assertTrue(category.getKeys().contains(key1));
         assertTrue(category.getKeys().contains(key2));
@@ -82,7 +85,7 @@
         Key<String> key1 = new Key<String>("key1", false);
         Key<String> key2 = new Key<String>("key2", false);
         Key<String> key3 = new Key<String>("key3", false);
-        Category category = new Category("verifyThatKeysAreUnmodifiable", key1, key2, key3);
+        Category<TestObj> category = new Category<>("verifyThatKeysAreUnmodifiable", TestObj.class, key1, key2, key3);
 
         Collection<Key<?>> keys = category.getKeys();
 
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -175,14 +175,13 @@
     private Storage delegateStorage;
     private Add delegateAdd;
     private Replace delegateReplace;
-    private Query delegateQuery;
+    private Query<?> delegateQuery;
 
     private TestExecutor executor;
     private TestExecutor fileExecutor;
 
     @SuppressWarnings("rawtypes")
     private Cursor expectedResults;
-    private TestPojo expectedResult;
     private InputStream expectedFile;
 
     @SuppressWarnings("unchecked")
@@ -200,10 +199,9 @@
         when(delegateStorage.createAdd(any(Category.class))).thenReturn(delegateAdd);
         when(delegateStorage.createReplace(any(Category.class))).thenReturn(delegateReplace);
         when(delegateStorage.createRemove()).thenReturn(remove);
-        when(delegateStorage.createQuery(any(Category.class), any(Class.class))).thenReturn(delegateQuery);
+        when(delegateStorage.createQuery(any(Category.class))).thenReturn(delegateQuery);
         expectedResults = mock(Cursor.class);
         when(delegateQuery.execute()).thenReturn(expectedResults);
-        expectedResult = new TestPojo();
         when(delegateStorage.getCount(any(Category.class))).thenReturn(42l);
         expectedFile = mock(InputStream.class);
         when(delegateStorage.loadFile(anyString())).thenReturn(expectedFile);
@@ -215,7 +213,6 @@
     @After
     public void tearDown() {
         expectedFile = null;
-        expectedResult = null;
         expectedResults = null;
         queuedStorage = null;
         delegateStorage = null;
@@ -226,7 +223,7 @@
 
     @Test
     public void testInsert() {
-        Category category = mock(Category.class);
+        Category<?> category = mock(Category.class);
         Pojo pojo = mock(Pojo.class);
 
         Put put = queuedStorage.createReplace(category);
@@ -252,7 +249,7 @@
         Update delegateUpdate = mock(Update.class);
         when(delegateStorage.createUpdate(any(Category.class))).thenReturn(delegateUpdate);
 
-        Category category = mock(Category.class);
+        Category<?> category = mock(Category.class);
 
         Update update = queuedStorage.createUpdate(category);
         verify(delegateStorage).createUpdate(category);
@@ -306,9 +303,10 @@
 
     @Test
     public void testFindAllPojos() {
-        Category category = mock(Category.class);
-        Query query = queuedStorage.createQuery(category, TestPojo.class);
-        verify(delegateStorage).createQuery(category, TestPojo.class);
+        @SuppressWarnings("unchecked")
+        Category<TestPojo> category = mock(Category.class);
+        Query<TestPojo> query = queuedStorage.createQuery(category);
+        verify(delegateStorage).createQuery(category);
         verifyNoMoreInteractions(delegateStorage);
 
         Cursor<TestPojo> result = query.execute();
@@ -321,7 +319,7 @@
 
     @Test
     public void testGetCount() {
-        Category category = mock(Category.class);
+        Category<?> category = mock(Category.class);
 
         long result = queuedStorage.getCount(category);
         assertEquals(42, result);
@@ -384,7 +382,7 @@
     @Test
     public void testRegisterCategory() {
 
-        Category category = mock(Category.class);
+        Category<?> category = mock(Category.class);
 
         queuedStorage.registerCategory(category);
 
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoQuery.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoQuery.java	Thu Jan 10 21:47:29 2013 +0100
@@ -51,20 +51,20 @@
     private MongoStorage storage;
     private BasicDBObject query = new BasicDBObject();
     private boolean hasClauses = false;
-    private Category category;
+    private Category<T> category;
     private Class<T> resultClass;
 
-    MongoQuery(MongoStorage storage, Category category, Class<T> resultClass) {
+    MongoQuery(MongoStorage storage, Category<T> category) {
         this.storage = storage;
         this.category = category;
-        this.resultClass = resultClass;
+        this.resultClass = category.getDataClass();
     }
 
-    public Category getCategory() {
+    public Category<T> getCategory() {
         return category;
     }
 
-    public void setCategory(Category category) {
+    public void setCategory(Category<T> category) {
         this.category = category;
     }
 
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Thu Jan 10 21:47:29 2013 +0100
@@ -132,26 +132,26 @@
     }
 
     @Override
-    public Add createAdd(Category into) {
+    public Add createAdd(Category<?> into) {
         MongoAdd add = new MongoAdd();
         add.setCategory(into);
         return add;
     }
 
     @Override
-    public Replace createReplace(Category into) {
+    public Replace createReplace(Category<?> into) {
         MongoReplace replace = new MongoReplace();
         replace.setCategory(into);
         return replace;
     }
 
-    private void addImpl(final Category cat, final Pojo pojo) {
+    private void addImpl(final Category<?> cat, final Pojo pojo) {
         DBCollection coll = getCachedCollection(cat);
         DBObject toInsert = preparePut(pojo);
         coll.insert(toInsert);
     }
 
-    private void replaceImpl(final Category cat, final Pojo pojo) {
+    private void replaceImpl(final Category<?> cat, final Pojo pojo) {
         DBCollection coll = getCachedCollection(cat);
         DBObject toInsert = preparePut(pojo);
 
@@ -176,7 +176,7 @@
     }
 
     void updatePojo(MongoUpdate mongoUpdate) {
-        Category cat = mongoUpdate.getCategory();
+        Category<?> cat = mongoUpdate.getCategory();
         DBCollection coll = getCachedCollection(cat);
         DBObject query = mongoUpdate.getQuery();
         DBObject values = mongoUpdate.getValues();
@@ -188,13 +188,13 @@
         assert (remove instanceof MongoRemove);
         MongoRemove mongoRemove = (MongoRemove) remove;
         DBObject query = mongoRemove.getQuery();
-        Category category = mongoRemove.getCategory();
+        Category<?> category = mongoRemove.getCategory();
         DBCollection coll = getCachedCollection(category);
 
         coll.remove(query);
     }
 
-    private DBCollection getCachedCollection(Category category) {
+    private DBCollection getCachedCollection(Category<?> category) {
         String collName = category.getName();
         DBCollection coll = collectionCache.get(collName);
         if (coll == null && db.collectionExists(collName)) {
@@ -206,7 +206,7 @@
     // TODO: This method is only temporary to enable tests, until we come up with a better design,
     // in particular, the collection should be stored in the category itself. It must not be called
     // from production code.
-    void mapCategoryToDBCollection(Category category, DBCollection coll) {
+    void mapCategoryToDBCollection(Category<?> category, DBCollection coll) {
         collectionCache.put(category.getName(), coll);
     }
 
@@ -220,7 +220,7 @@
     }
     
     @Override
-    public void registerCategory(Category category) {
+    public void registerCategory(Category<?> category) {
         String name = category.getName();
         if (collectionCache.containsKey(name)) {
             throw new IllegalStateException("Category may only be associated with one backend.");
@@ -236,12 +236,12 @@
     }
 
     @Override
-    public <T extends Pojo> Query<T> createQuery(Category category, Class<T> resultClass) {
-        return new MongoQuery(this, category, resultClass);
+    public <T extends Pojo> Query<T> createQuery(Category<T> category) {
+        return new MongoQuery<T>(this, category);
     }
 
     @Override
-    public Update createUpdate(Category category) {
+    public Update createUpdate(Category<?> category) {
         return new MongoUpdate(this, category);
     }
 
@@ -250,8 +250,7 @@
         return new MongoRemove();
     }
 
-    <T extends Pojo> Cursor<T> findAllPojos(Query<T> query, Class<T> resultClass) {
-        MongoQuery mongoQuery =  checkAndCastQuery(query);
+    <T extends Pojo> Cursor<T> findAllPojos(MongoQuery<T> mongoQuery, Class<T> resultClass) {
         DBCollection coll = getCachedCollection(mongoQuery.getCategory());
         DBCursor dbCursor;
         if (mongoQuery.hasClauses()) {
@@ -263,7 +262,7 @@
         return new MongoCursor<T>(dbCursor, resultClass);
     }
 
-    private DBCursor applySortAndLimit(MongoQuery query, DBCursor dbCursor) {
+    private DBCursor applySortAndLimit(MongoQuery<?> query, DBCursor dbCursor) {
         BasicDBObject orderBy = new BasicDBObject();
         List<Sort> sorts = query.getSorts();
         for (Sort sort : sorts) {
@@ -278,17 +277,8 @@
     }
 
 
-    private MongoQuery checkAndCastQuery(Query query) {
-        if (!(query instanceof MongoQuery)) {
-            throw new IllegalArgumentException("MongoStorage can only handle MongoQuery");
-        }
-
-        return (MongoQuery) query;
-
-    }
-
     @Override
-    public long getCount(Category category) {
+    public long getCount(Category<?> category) {
         DBCollection coll = getCachedCollection(category);
         if (coll != null) {
             return coll.getCount();
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoCursorTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoCursorTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -52,13 +52,10 @@
 import com.mongodb.BasicDBObject;
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Entity;
-import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Persist;
 import com.redhat.thermostat.storage.model.BasePojo;
-import com.redhat.thermostat.storage.mongodb.internal.MongoCursor;
 
 public class MongoCursorTest {
 
@@ -102,13 +99,6 @@
         }
     }
 
-    private static final Key<String> key1 = new Key<>("key1", false);
-    private static final Key<String> key2 = new Key<>("key2", false);
-    private static final Key<String> key3 = new Key<>("key3", false);
-    private static final Key<String> key4 = new Key<>("key4", false);
-
-    private static final Category testCategory = new Category("MongoCursorTest", key1, key2, key3, key4);
-
     private DBCursor dbCursor;
     private Cursor<TestClass> cursor;
 
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoQueryTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoQueryTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -48,16 +48,21 @@
 import com.mongodb.DBObject;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Query.Criteria;
+import com.redhat.thermostat.storage.model.Pojo;
 
 public class MongoQueryTest {
 
+    private static class TestClass implements Pojo {
+        
+    }
+
     private static MongoStorage storage;
-    private static Category category;
+    private static Category<TestClass> category;
 
     @BeforeClass
     public static void setUp() {
         storage = mock(MongoStorage.class);
-        category = new Category("some-collection");
+        category = new Category<>("some-collection", TestClass.class);
     }
 
     @AfterClass
@@ -69,14 +74,14 @@
     @Test
     public void testEmptyQuery() {
         
-        MongoQuery query = new MongoQuery(storage, category, String.class);
+        MongoQuery<TestClass> query = new MongoQuery<>(storage, category);
         DBObject mongoQuery = query.getGeneratedQuery();
         assertTrue(mongoQuery.keySet().isEmpty());
     }
 
     @Test
     public void testCollectionName() {
-        MongoQuery query = new MongoQuery(storage, category, String.class);
+        MongoQuery<TestClass> query = new MongoQuery<>(storage, category);
         assertEquals("some-collection", query.getCategory().getName());
     }
 
@@ -117,7 +122,7 @@
     }
 
     private DBObject generateSimpleWhereQuery(String key, Criteria criteria, Object value) {
-        MongoQuery query = new MongoQuery(storage, category, String.class);
+        MongoQuery<TestClass> query = new MongoQuery<>(storage, category);
         query.where(key, criteria, value);
         return query.getGeneratedQuery();
     }
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -144,8 +144,8 @@
     private static final Key<String> key3 = new Key<>("key3", false);
     private static final Key<String> key4 = new Key<>("key4", false);
     private static final Key<String> key5 = new Key<>("key5", false);
-    private static final Category testCategory = new Category("MongoStorageTest", key1, key2, key3, key4, key5);
-    private static final Category emptyTestCategory = new Category("MongoEmptyCategory");
+    private static final Category<TestClass> testCategory = new Category<>("MongoStorageTest", TestClass.class, key1, key2, key3, key4, key5);
+    private static final Category<TestClass> emptyTestCategory = new Category("MongoEmptyCategory", TestClass.class);
 
     private StartupConfiguration conf;
     private Mongo m;
@@ -207,7 +207,7 @@
     public void verifyFindAllReturnsCursor() throws Exception {
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
-        Query query = storage.createQuery(testCategory, TestClass.class);
+        Query query = storage.createQuery(testCategory);
         Cursor<TestClass> cursor = query.execute();
         assertNotNull(cursor);
     }
@@ -216,7 +216,7 @@
     public void verifyFindAllCallsDBCollectionFind() throws Exception {
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
-        Query query = storage.createQuery(testCategory, TestClass.class);
+        Query query = storage.createQuery(testCategory);
         query.where(key1, Criteria.EQUALS, "fluff");
         query.execute();
         verify(testCollection).find(any(DBObject.class));
@@ -244,7 +244,7 @@
         MongoStorage storage = makeStorage();
         // TODO find a way to test this that isn't just testing MongoCursor
         // Because we mock the DBCollection, the contents of this query don't actually determine the result.
-        Query query = storage.createQuery(testCategory, TestClass.class);
+        Query query = storage.createQuery(testCategory);
         Cursor<TestClass> cursor = query.execute();
 
         verifyDefaultCursor(cursor);
@@ -256,7 +256,7 @@
         MongoStorage storage = makeStorage();
         // TODO find a way to test this that isn't just testing MongoCursor
         // Because we mock the DBCollection, the contents of this query don't actually determine the result.
-        Query query = storage.createQuery(testCategory, TestClass.class);
+        Query query = storage.createQuery(testCategory);
         query.sort(key1, Query.SortDirection.ASCENDING);
         query.limit(3);
 
@@ -274,7 +274,7 @@
     public void verifyFindAllFromCategoryCallsDBCollectionFindAll() throws Exception {
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
-        Query query = storage.createQuery(testCategory, TestClass.class);
+        Query query = storage.createQuery(testCategory);
         query.execute();
         verify(testCollection).find();
     }
@@ -283,7 +283,7 @@
     public void verifyFindAllFromCategoryReturnsCorrectCursor() throws Exception {
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
-        Query query = storage.createQuery(testCategory, TestClass.class);
+        Query query = storage.createQuery(testCategory);
         Cursor<TestClass> cursor = query.execute();
 
         verifyDefaultCursor(cursor);
@@ -310,7 +310,7 @@
         PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
         MongoStorage storage = makeStorage();
         storage.getConnection().connect();
-        long count = storage.getCount(new Category("NonExistent"));
+        long count = storage.getCount(new Category("NonExistent", TestClass.class));
         assertEquals(0, count);
     }
 
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java	Thu Jan 10 21:47:29 2013 +0100
@@ -58,8 +58,8 @@
     static final Key<Boolean> THREAD_ALLOCATED_MEMORY_KEY = new Key<Boolean>(THREAD_ALLOCATED_MEMORY, false);
     static final Key<List<String>> SUPPORTED_FEATURES_LIST_KEY = new Key<List<String>>(SUPPORTED_FEATURES_LIST, false);
 
-    static final Category THREAD_CAPABILITIES =
-            new Category("vm-thread-capabilities", Key.AGENT_ID, Key.VM_ID,
+    static final Category<VMThreadCapabilities> THREAD_CAPABILITIES =
+            new Category<>("vm-thread-capabilities", VMThreadCapabilities.class, Key.AGENT_ID, Key.VM_ID,
                          SUPPORTED_FEATURES_LIST_KEY);
 
 
@@ -71,8 +71,8 @@
     static final String DAEMON_THREADS = "currentDaemonThreads";
     static final Key<Long> DAEMON_THREADS_KEY = new Key<Long>(DAEMON_THREADS, false);
     
-    static final Category THREAD_SUMMARY =
-            new Category("vm-thread-summary", Key.AGENT_ID, Key.VM_ID,
+    static final Category<ThreadSummary> THREAD_SUMMARY =
+            new Category<>("vm-thread-summary", ThreadSummary.class, Key.AGENT_ID, Key.VM_ID,
                          Key.TIMESTAMP,
                          LIVE_THREADS_KEY, DAEMON_THREADS_KEY);
     
@@ -95,8 +95,8 @@
     static final String THREAD_WAIT_COUNT = "threadWaitCount";
     static final Key<Long> THREAD_WAIT_COUNT_KEY = new Key<Long>(THREAD_WAIT_COUNT, false);
     
-    static final Category THREAD_INFO =
-            new Category("vm-thread-info", Key.AGENT_ID, Key.VM_ID,
+    static final Category<ThreadInfoData> THREAD_INFO =
+            new Category<>("vm-thread-info", ThreadInfoData.class, Key.AGENT_ID, Key.VM_ID,
                          Key.TIMESTAMP, THREAD_NAME_KEY, THREAD_ID_KEY,
                          THREAD_STATE_KEY,
                          THREAD_CPU_TIME_KEY,
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -65,7 +65,7 @@
 
     @Override
     public VMThreadCapabilities loadCapabilities(VmRef vm) {
-        Query<VMThreadCapabilities> query = storage.createQuery(THREAD_CAPABILITIES, VMThreadCapabilities.class);
+        Query<VMThreadCapabilities> query = storage.createQuery(THREAD_CAPABILITIES);
         query.where(Key.VM_ID, Query.Criteria.EQUALS, vm.getId());
         query.where(Key.AGENT_ID, Query.Criteria.EQUALS, vm.getAgent().getAgentId());
         query.limit(1);
@@ -91,7 +91,7 @@
     public ThreadSummary loadLastestSummary(VmRef ref) {
         ThreadSummary summary = null;
 
-        Query<ThreadSummary> query = prepareQuery(THREAD_SUMMARY, ThreadSummary.class, ref);
+        Query<ThreadSummary> query = prepareQuery(THREAD_SUMMARY, ref);
         query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
         query.limit(1);
         Cursor<ThreadSummary> cursor = query.execute();
@@ -107,7 +107,7 @@
         
         List<ThreadSummary> result = new ArrayList<>();
         
-        Query<ThreadSummary> query = prepareQuery(THREAD_SUMMARY, ThreadSummary.class, ref);
+        Query<ThreadSummary> query = prepareQuery(THREAD_SUMMARY, ref);
         query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
         query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since);
 
@@ -131,7 +131,7 @@
     public List<ThreadInfoData> loadThreadInfo(VmRef ref, long since) {
         List<ThreadInfoData> result = new ArrayList<>();
         
-        Query<ThreadInfoData> query = prepareQuery(THREAD_INFO, ThreadInfoData.class, ref);
+        Query<ThreadInfoData> query = prepareQuery(THREAD_INFO, ref);
         query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since);
         query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
         
@@ -144,12 +144,12 @@
         return result;
     }
     
-    private <T extends Pojo> Query<T> prepareQuery(Category category, Class<T> resultClass, VmRef vm) {
-        return prepareQuery(category, resultClass, vm.getIdString(), vm.getAgent().getAgentId());
+    private <T extends Pojo> Query<T> prepareQuery(Category<T> category, VmRef vm) {
+        return prepareQuery(category, vm.getIdString(), vm.getAgent().getAgentId());
     }
 
-    private <T extends Pojo> Query<T> prepareQuery(Category category, Class<T> resultClass, String vmId, String agentId) {
-        Query<T> query = storage.createQuery(category, resultClass);
+    private <T extends Pojo> Query<T> prepareQuery(Category<T> category, String vmId, String agentId) {
+        Query<T> query = storage.createQuery(category);
         query.where(Key.AGENT_ID, Query.Criteria.EQUALS, agentId);
         query.where(Key.VM_ID, Query.Criteria.EQUALS, Integer.valueOf(vmId));
         return query;
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -76,7 +76,7 @@
     public void testLoadVMCapabilities() {
         Query query = mock(Query.class);
         Storage storage = mock(Storage.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         VmRef ref = mock(VmRef.class);
         when(ref.getId()).thenReturn(42);
         
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/VmClassStatDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/VmClassStatDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -47,8 +47,8 @@
 
     static final Key<Long> loadedClassesKey = new Key<>("loadedClasses", false);
 
-    static final Category vmClassStatsCategory = new Category(
-            "vm-class-stats", Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, loadedClassesKey);
+    static final Category<VmClassStat> vmClassStatsCategory = new Category<>(
+            "vm-class-stats", VmClassStat.class, Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, loadedClassesKey);
 
     public List<VmClassStat> getLatestClassStats(VmRef ref, long since);
 
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -53,7 +53,7 @@
     VmClassStatDAOImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(vmClassStatsCategory);
-        this.getter = new VmLatestPojoListGetter<>(storage, vmClassStatsCategory, VmClassStat.class);
+        this.getter = new VmLatestPojoListGetter<>(storage, vmClassStatsCategory);
     }
 
     @Override
--- a/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -90,7 +90,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
--- a/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/VmCpuStatDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/VmCpuStatDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -47,7 +47,7 @@
 
     static final Key<Double> vmCpuLoadKey = new Key<>("cpuLoad", false);
 
-    static final Category vmCpuStatCategory = new Category("vm-cpu-stats",
+    static final Category<VmCpuStat> vmCpuStatCategory = new Category<>("vm-cpu-stats", VmCpuStat.class,
             Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, vmCpuLoadKey);
 
     public abstract List<VmCpuStat> getLatestVmCpuStats(VmRef ref, long since);
--- a/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -53,7 +53,7 @@
     VmCpuStatDAOImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(vmCpuStatCategory);
-        this.getter = new VmLatestPojoListGetter<>(storage, vmCpuStatCategory, VmCpuStat.class);
+        this.getter = new VmLatestPojoListGetter<>(storage, vmCpuStatCategory);
     }
 
     @Override
--- a/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -96,7 +96,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
@@ -110,7 +110,7 @@
         VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage);
         List<VmCpuStat> vmCpuStats = dao.getLatestVmCpuStats(vmRef, Long.MIN_VALUE);
 
-        verify(storage).createQuery(VmCpuStatDAO.vmCpuStatCategory, VmCpuStat.class);
+        verify(storage).createQuery(VmCpuStatDAO.vmCpuStatCategory);
         verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
         verify(query).where(Key.AGENT_ID, Criteria.EQUALS, vmRef.getAgent().getAgentId());
         verify(query).where(Key.VM_ID, Criteria.EQUALS, vmRef.getId());
--- a/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/VmGcStatDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/VmGcStatDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -50,7 +50,7 @@
     /** time in microseconds */
     static final Key<Long> wallTimeKey = new Key<>("wallTime", false);
 
-    static final Category vmGcStatCategory = new Category("vm-gc-stats",
+    static final Category<VmGcStat> vmGcStatCategory = new Category<>("vm-gc-stats", VmGcStat.class,
             Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, collectorKey,
             runCountKey, wallTimeKey);
 
--- a/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -53,7 +53,7 @@
     VmGcStatDAOImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(vmGcStatCategory);
-        getter = new VmLatestPojoListGetter<>(storage, vmGcStatCategory, VmGcStat.class);
+        getter = new VmLatestPojoListGetter<>(storage, vmGcStatCategory);
     }
 
     @Override
--- a/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -94,7 +94,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
 
         HostRef hostRef = mock(HostRef.class);
@@ -108,7 +108,7 @@
         VmGcStatDAO dao = new VmGcStatDAOImpl(storage);
         List<VmGcStat> vmGcStats = dao.getLatestVmGcStats(vmRef, Long.MIN_VALUE);
 
-        verify(storage).createQuery(VmGcStatDAO.vmGcStatCategory, VmGcStat.class);
+        verify(storage).createQuery(VmGcStatDAO.vmGcStatCategory);
         verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE);
         verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system");
         verify(query).where(Key.VM_ID, Criteria.EQUALS, 321);
--- a/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -52,7 +52,7 @@
     static final Key<String> heapDumpIdKey = new Key<String>("heapDumpId", false);
     static final Key<String> histogramIdKey = new Key<String>("histogramId", false);
 
-    public static final Category heapInfoCategory = new Category("vm-heap-info", Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, heapIdKey, heapDumpIdKey, histogramIdKey);
+    public static final Category<HeapInfo> heapInfoCategory = new Category<>("vm-heap-info", HeapInfo.class, Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, heapIdKey, heapDumpIdKey, histogramIdKey);
 
     void putHeapInfo(HeapInfo heapInfo, File heapDumpFile, ObjectHistogram histogramData) throws IOException;
 
--- a/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -110,7 +110,7 @@
 
     @Override
     public Collection<HeapInfo> getAllHeapInfo(VmRef vm) {
-        Query<HeapInfo> query = storage.createQuery(heapInfoCategory, HeapInfo.class);
+        Query<HeapInfo> query = storage.createQuery(heapInfoCategory);
         query.where(Key.AGENT_ID, Criteria.EQUALS, vm.getAgent().getAgentId());
         query.where(Key.VM_ID, Criteria.EQUALS, vm.getId());
         Cursor<HeapInfo> cursor = query.execute();
@@ -140,7 +140,7 @@
 
     @Override
     public HeapInfo getHeapInfo(String heapId) {
-        Query<HeapInfo> query = storage.createQuery(heapInfoCategory, HeapInfo.class);
+        Query<HeapInfo> query = storage.createQuery(heapInfoCategory);
         query.where(heapIdKey, Criteria.EQUALS, heapId);
         query.limit(1);
         HeapInfo found = null;
--- a/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -97,7 +97,7 @@
 
         when(storage.getAgentId()).thenReturn("test");
         query = mock(Query.class); 
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
 
         dao = new HeapDAOImpl(storage);
         
--- a/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/VmMemoryStatDAO.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/VmMemoryStatDAO.java	Thu Jan 10 21:47:29 2013 +0100
@@ -48,7 +48,7 @@
 
     static final Key<Generation[]> generationsKey = new Key<>("generations", false);
 
-    static final Category vmMemoryStatsCategory = new Category("vm-memory-stats",
+    static final Category<VmMemoryStat> vmMemoryStatsCategory = new Category<>("vm-memory-stats", VmMemoryStat.class,
             Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, generationsKey);
 
     public VmMemoryStat getLatestMemoryStat(VmRef ref);
--- a/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Thu Jan 10 21:47:29 2013 +0100
@@ -57,12 +57,12 @@
     VmMemoryStatDAOImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(vmMemoryStatsCategory);
-        getter = new VmLatestPojoListGetter<>(storage, vmMemoryStatsCategory, VmMemoryStat.class);
+        getter = new VmLatestPojoListGetter<>(storage, vmMemoryStatsCategory);
     }
 
     @Override
     public VmMemoryStat getLatestMemoryStat(VmRef ref) {
-        Query<VmMemoryStat> query = storage.createQuery(vmMemoryStatsCategory, VmMemoryStat.class);
+        Query<VmMemoryStat> query = storage.createQuery(vmMemoryStatsCategory);
         query.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgent().getAgentId());
         query.where(Key.VM_ID, Criteria.EQUALS, ref.getId());
         query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING);
--- a/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -91,7 +91,7 @@
 
         storage = mock(Storage.class);
         query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
 
         cursor = mock(Cursor.class);
         when(query.execute()).thenReturn(cursor);
@@ -155,7 +155,7 @@
 
         Storage storage = mock(Storage.class);
         Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class), any(Class.class))).thenReturn(query);
+        when(storage.createQuery(any(Category.class))).thenReturn(query);
         when(query.execute()).thenReturn(cursor);
 
         VmMemoryStatDAO impl = new VmMemoryStatDAOImpl(storage);
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Thu Jan 10 21:47:29 2013 +0100
@@ -281,7 +281,7 @@
         @Override
         public void apply() {
             int categoryId = getCategoryId(getCategory());
-            putImpl(new WebInsert(categoryId, false, getPojo().getClass().getName()), getPojo());
+            putImpl(new WebInsert(categoryId, false), getPojo());
         }
         
     }
@@ -291,7 +291,7 @@
         @Override
         public void apply() {
             int categoryId = getCategoryId(getCategory());
-            putImpl(new WebInsert(categoryId, true, getPojo().getClass().getName()), getPojo());
+            putImpl(new WebInsert(categoryId, true), getPojo());
         }
         
     }
@@ -306,20 +306,23 @@
 
     private class WebQueryImpl<T extends Pojo> extends WebQuery<T> {
 
-        WebQueryImpl(int categoryId, Class<T> resultClass) {
-            super(categoryId, resultClass);
+        private transient Class<T> dataClass;
+
+        WebQueryImpl(int categoryId, Class<T> dataClass) {
+            super(categoryId);
+            this.dataClass = dataClass;
         }
 
         @Override
         public Cursor<T> execute() {
-            return findAllPojos(this, getResultClass());
+            return findAllPojos(this, dataClass);
         }
     }
 
     private String endpoint;
     private UUID agentId;
 
-    private Map<Category, Integer> categoryIds;
+    private Map<Category<?>, Integer> categoryIds;
     private Gson gson;
     // package private for testing
     DefaultHttpClient httpClient;
@@ -429,7 +432,7 @@
     }
 
     @Override
-    public void registerCategory(Category category) throws StorageException {
+    public void registerCategory(Category<?> category) throws StorageException {
         NameValuePair nameParam = new BasicNameValuePair("name",
                 category.getName());
         NameValuePair categoryParam = new BasicNameValuePair("category",
@@ -445,8 +448,8 @@
     }
 
     @Override
-    public <T extends Pojo> Query<T> createQuery(Category category, Class<T> resultClass) {
-        return new WebQueryImpl(categoryIds.get(category), resultClass);
+    public <T extends Pojo> Query<T> createQuery(Category<T> category) {
+        return new WebQueryImpl<>(categoryIds.get(category), category.getDataClass());
     }
 
     @Override
@@ -455,24 +458,19 @@
     }
 
     @Override
-    public Update createUpdate(Category category) {
+    public Update createUpdate(Category<?> category) {
         WebUpdateImpl updateImpl = new WebUpdateImpl();
         updateImpl.setCategoryId(categoryIds.get(category));
         return updateImpl;
     }
 
     @SuppressWarnings("unchecked")
-    private <T extends Pojo> Cursor<T> findAllPojos(Query query,
-            Class<T> resultClass) throws StorageException {
-        ((WebQuery) query).setResultClassName(resultClass.getName());
-        NameValuePair queryParam = new BasicNameValuePair("query",
-                gson.toJson(query));
+    private <T extends Pojo> Cursor<T> findAllPojos(WebQuery<T> query, Class<T> resultClass) throws StorageException {
+        NameValuePair queryParam = new BasicNameValuePair("query", gson.toJson(query));
         List<NameValuePair> formparams = Arrays.asList(queryParam);
-        try (CloseableHttpEntity entity = post(endpoint + "/find-all",
-                formparams)) {
+        try (CloseableHttpEntity entity = post(endpoint + "/find-all", formparams)) {
             Reader reader = getContentAsReader(entity);
-            T[] result = (T[]) gson.fromJson(reader,
-                    Array.newInstance(resultClass, 0).getClass());
+            T[] result = (T[]) gson.fromJson(reader, Array.newInstance(resultClass, 0).getClass());
             return new WebCursor<T>(result);
         }
     }
@@ -488,12 +486,10 @@
     }
 
     @Override
-    public long getCount(Category category) throws StorageException {
-        NameValuePair categoryParam = new BasicNameValuePair("category",
-                gson.toJson(categoryIds.get(category)));
+    public long getCount(Category<?> category) throws StorageException {
+        NameValuePair categoryParam = new BasicNameValuePair("category", gson.toJson(categoryIds.get(category)));
         List<NameValuePair> formparams = Arrays.asList(categoryParam);
-        try (CloseableHttpEntity entity = post(endpoint + "/get-count",
-                formparams)) {
+        try (CloseableHttpEntity entity = post(endpoint + "/get-count", formparams)) {
             Reader reader = getContentAsReader(entity);
             long result = gson.fromJson(reader, Long.class);
             return result;
@@ -514,14 +510,14 @@
     }
 
     @Override
-    public Add createAdd(Category into) {
+    public Add createAdd(Category<?> into) {
         WebAdd add = new WebAdd();
         add.setCategory(into);
         return add;
     }
 
     @Override
-    public Replace createReplace(Category into) {
+    public Replace createReplace(Category<?> into) {
         WebReplace replace = new WebReplace();
         replace.setCategory(into);
         return replace;
@@ -643,7 +639,7 @@
         // Nothing to do here.
     }
 
-    int getCategoryId(Category category) {
+    int getCategoryId(Category<?> category) {
         return categoryIds.get(category);
     }
 
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -113,7 +113,7 @@
     private String requestURI;
     private int responseStatus;
 
-    private static Category category;
+    private static Category<TestObj> category;
     private static Key<String> key1;
     private static Key<Integer> key2;
 
@@ -123,7 +123,7 @@
     public static void setupCategory() {
         key1 = new Key<>("property1", true);
         key2 = new Key<>("property2", true);
-        category = new Category("test", key1);
+        category = new Category<>("test", TestObj.class, key1);
     }
 
     @AfterClass
@@ -231,7 +231,7 @@
         responseBody = gson.toJson(Arrays.asList(obj1, obj2));
 
         Key<String> key1 = new Key<>("property1", true);
-        Query<TestObj> query = storage.createQuery(category, TestObj.class);
+        Query<TestObj> query = storage.createQuery(category);
         query.where(key1, Criteria.EQUALS, "fluff");
 
         Cursor<TestObj> results = query.execute();
@@ -240,7 +240,7 @@
         String line = URLDecoder.decode(bufRead.readLine(), "UTF-8");
         String[] parts = line.split("=");
         assertEquals("query", parts[0]);
-        WebQuery restQuery = gson.fromJson(parts[1], WebQuery.class);
+        WebQuery<?> restQuery = gson.fromJson(parts[1], WebQuery.class);
 
         assertEquals(42, restQuery.getCategoryId());
         List<Qualifier<?>> qualifiers = restQuery.getQualifiers();
@@ -282,12 +282,11 @@
         WebInsert insert = gson.fromJson(parts[1], WebInsert.class);
         assertEquals(42, insert.getCategoryId());
         assertEquals(true, insert.isReplace());
-        assertEquals(TestObj.class.getName(), insert.getPojoClass());
 
         parts = params[1].split("=");
         assertEquals(2, parts.length);
         assertEquals("pojo", parts[0]);
-        Object resultObj = gson.fromJson(parts[1], Class.forName(insert.getPojoClass()));
+        Object resultObj = gson.fromJson(parts[1], TestObj.class);
 
         // Set agentId on expected object, because we expect WebStorage to insert it for us.
         obj.setAgentId(agentId.toString());
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java	Thu Jan 10 21:47:29 2013 +0100
@@ -42,15 +42,13 @@
 
     private int categoryId;
     private boolean replace;
-    private String pojoClass;
 
     public WebInsert() {
     }
 
-    public WebInsert(int categoryId, boolean replace, String pojoClass) {
+    public WebInsert(int categoryId, boolean replace) {
         this.categoryId = categoryId;
         this.replace = replace;
-        this.pojoClass = pojoClass;
     }
 
     public int getCategoryId() {
@@ -61,14 +59,6 @@
         this.categoryId = categoryId;
     }
 
-    public String getPojoClass() {
-        return pojoClass;
-    }
-
-    public void setPojoClass(String pojoClass) {
-        this.pojoClass = pojoClass;
-    }
-
     public boolean isReplace() {
         return replace;
     }
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebQuery.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebQuery.java	Thu Jan 10 21:47:29 2013 +0100
@@ -39,10 +39,8 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 import com.redhat.thermostat.storage.core.AbstractQuery;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.model.Pojo;
@@ -50,19 +48,16 @@
 public class WebQuery<T extends Pojo> extends AbstractQuery<T> {
 
     private List<Qualifier<?>> qualifiers;
-    private String resultClassName;
-    private transient Class<T> resultClass;
 
     private int categoryId;
 
     public WebQuery() {
-        this(-1, null);
+        this(-1);
     }
 
-    public WebQuery(int categoryId, Class<T> resultClass) {
+    public WebQuery(int categoryId) {
         qualifiers = new ArrayList<>();
         this.categoryId = categoryId;
-        this.resultClass = resultClass;
     }
 
     public int getCategoryId() {
@@ -74,7 +69,7 @@
     }
 
     @Override
-    public <T> void where(Key<T> key, Criteria criteria, T value) {
+    public <S> void where(Key<S> key, Criteria criteria, S value) {
         qualifiers.add(new Qualifier<>(key, criteria, value));
     }
 
@@ -86,18 +81,6 @@
         this.qualifiers = qualifiers;
     }
 
-    public String getResultClassName() {
-        return resultClassName;
-    }
-
-    public void setResultClassName(String resultClassName) {
-        this.resultClassName = resultClassName;
-    }
-
-    public Class<T> getResultClass() {
-        return resultClass;
-    }
-
     @Override
     public Cursor<T> execute() {
         // This should only ever be called when created from WebStorage, which provides its own subclass.
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebRemove.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebRemove.java	Thu Jan 10 21:47:29 2013 +0100
@@ -47,7 +47,7 @@
 
 public class WebRemove implements Remove {
 
-    private transient Map<Category, Integer> categoryIds;
+    private transient Map<Category<?>, Integer> categoryIds;
     private int categoryId;
     private List<Qualifier<?>> qualifiers;
 
@@ -56,7 +56,7 @@
         this(null);
     }
 
-    public WebRemove(Map<Category, Integer> categoryIds) {
+    public WebRemove(Map<Category<?>, Integer> categoryIds) {
         qualifiers = new ArrayList<>();
         this.categoryIds = categoryIds;
     }
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -10,6 +10,7 @@
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query.Criteria;
+import com.redhat.thermostat.storage.model.Pojo;
 
 /*
  * Copyright 2012 Red Hat, Inc.
@@ -49,13 +50,17 @@
 
 public class WebQueryTest {
 
+    private static class TestObj implements Pojo {
+        
+    }
+
     @Test
     public void test() {
         Key<String> key1 = new Key<>("testkey", true);
-        Category category = new Category("test", key1);
+        Category<TestObj> category = new Category<>("test", TestObj.class, key1);
         Map<Category,Integer> categoryIdMap = new HashMap<>();
         categoryIdMap.put(category, 42);
-        WebQuery query = new WebQuery(42, String.class);
+        WebQuery query = new WebQuery(42);
         query.where(key1, Criteria.EQUALS, "fluff");
 
         List<Qualifier<?>> qualifiers = query.getQualifiers();
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Thu Jan 10 21:47:29 2013 +0100
@@ -70,7 +70,6 @@
 import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.StorageException;
 import com.redhat.thermostat.storage.core.Update;
 import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.web.common.Qualifier;
@@ -101,7 +100,7 @@
     private int currentCategoryId;
 
     private Map<String, Integer> categoryIds;
-    private Map<Integer, Category> categories;
+    private Map<Integer, Category<?>> categories;
 
     public void init() {
         gson = new GsonBuilder().registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()).create();
@@ -206,7 +205,7 @@
         try {
             String categoryParam = req.getParameter("category");
             int categoryId = gson.fromJson(categoryParam, Integer.class);
-            Category category = categories.get(categoryId);
+            Category<?> category = getCategoryFromId(categoryId);
             long result = storage.getCount(category);
             resp.setStatus(HttpServletResponse.SC_OK);
             resp.setContentType("application/json");
@@ -225,8 +224,8 @@
         if (categoryIds.containsKey(categoryName)) {
             id = categoryIds.get(categoryName);
         } else {
-            // The following has the side effect of registering the newly deserialized Category in the Categories clas.
-            Category category = gson.fromJson(categoryParam, Category.class);
+            // The following has the side effect of registering the newly deserialized Category in the Categories class.
+            Category<?> category = gson.fromJson(categoryParam, Category.class);
             storage.registerCategory(category);
 
             id = currentCategoryId;
@@ -246,21 +245,18 @@
             resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
             return;
         }
-        try {
-            String insertParam = req.getParameter("insert");
-            WebInsert insert = gson.fromJson(insertParam, WebInsert.class);
-            Class<? extends Pojo> pojoCls = (Class<? extends Pojo>) Class.forName(insert.getPojoClass());
-            String pojoParam = req.getParameter("pojo");
-            Pojo pojo = gson.fromJson(pojoParam, pojoCls);
-            int categoryId = insert.getCategoryId();
-            Category category = getCategoryFromId(categoryId);
-            Put targetPut = insert.isReplace() ? storage.createReplace(category) : storage.createAdd(category);
-            targetPut.setPojo(pojo);
-            targetPut.apply();
-            resp.setStatus(HttpServletResponse.SC_OK);
-        } catch (ClassNotFoundException ex) {
-            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-        }
+
+        String insertParam = req.getParameter("insert");
+        WebInsert insert = gson.fromJson(insertParam, WebInsert.class);
+        int categoryId = insert.getCategoryId();
+        Category<?> category = getCategoryFromId(categoryId);
+        Class<? extends Pojo> pojoCls = category.getDataClass();
+        String pojoParam = req.getParameter("pojo");
+        Pojo pojo = gson.fromJson(pojoParam, pojoCls);
+        Put targetPut = insert.isReplace() ? storage.createReplace(category) : storage.createAdd(category);
+        targetPut.setPojo(pojo);
+        targetPut.apply();
+        resp.setStatus(HttpServletResponse.SC_OK);
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
@@ -316,45 +312,35 @@
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
     private void findAll(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        try {
-            String queryParam = req.getParameter("query");
-            WebQuery query = gson.fromJson(queryParam, WebQuery.class);
-            Class resultClass = Class.forName(query.getResultClassName());
-            Query targetQuery = constructTargetQuery(query);
-            ArrayList resultList = new ArrayList();
-            Cursor result = targetQuery.execute();
-            while (result.hasNext()) {
-                resultList.add(result.next());
-            }
-            writeResponse(resp, resultList.toArray());
-        } catch (ClassNotFoundException e) {
-            e.printStackTrace();
-            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "result class not found");
+        String queryParam = req.getParameter("query");
+        WebQuery query = gson.fromJson(queryParam, WebQuery.class);
+        Query targetQuery = constructTargetQuery(query);
+        ArrayList resultList = new ArrayList();
+        Cursor result = targetQuery.execute();
+        while (result.hasNext()) {
+            resultList.add(result.next());
         }
+        writeResponse(resp, resultList.toArray());
     }
 
-    private Query constructTargetQuery(WebQuery<? extends Pojo> query) {
+    private Query<?> constructTargetQuery(WebQuery<? extends Pojo> query) {
         int categoryId = query.getCategoryId();
-        Category category = getCategoryFromId(categoryId);
-        try {
-            Class<? extends Pojo> resultClass = (Class<? extends Pojo>) Class.forName(query.getResultClassName());
-            Query targetQuery = storage.createQuery(category, resultClass);
-            List<Qualifier<?>> qualifiers = query.getQualifiers();
-            for (Qualifier q : qualifiers) {
-                targetQuery.where(q.getKey(), q.getCriteria(), q.getValue());
-            }
-            for (Sort s : query.getSorts()) {
-                targetQuery.sort(s.getKey(), s.getDirection());
-            }
-            targetQuery.limit(query.getLimit());
-            return targetQuery;
-        } catch (ClassNotFoundException ex) {
-            throw new StorageException(ex);
+        Category<?> category = getCategoryFromId(categoryId);
+
+        Query<?> targetQuery = storage.createQuery(category);
+        List<Qualifier<?>> qualifiers = query.getQualifiers();
+        for (Qualifier q : qualifiers) {
+            targetQuery.where(q.getKey(), q.getCriteria(), q.getValue());
         }
+        for (Sort s : query.getSorts()) {
+            targetQuery.sort(s.getKey(), s.getDirection());
+        }
+        targetQuery.limit(query.getLimit());
+        return targetQuery;
     }
 
-    private Category getCategoryFromId(int categoryId) {
-        Category category = categories.get(categoryId);
+    private Category<?> getCategoryFromId(int categoryId) {
+        Category<?> category = categories.get(categoryId);
         return category;
     }
 
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Thu Jan 10 15:09:23 2013 +0100
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Thu Jan 10 21:47:29 2013 +0100
@@ -133,13 +133,13 @@
 
     private static Key<String> key1;
     private static Key<Integer> key2;
-    private static Category category;
+    private static Category<TestClass> category;
 
     @BeforeClass
     public static void setupCategory() {
         key1 = new Key<>("key1", true);
         key2 = new Key<>("key2", false);
-        category = new Category("test", key1, key2);
+        category = new Category<>("test", TestClass.class, key1, key2);
     }
 
     @AfterClass
@@ -211,7 +211,7 @@
         when(cursor.next()).thenReturn(expected1).thenReturn(expected2);
 
         Query mockQuery = mock(Query.class);
-        when(mockStorage.createQuery(any(Category.class), any(Class.class))).thenReturn(mockQuery);
+        when(mockStorage.createQuery(any(Category.class))).thenReturn(mockQuery);
         when(mockQuery.execute()).thenReturn(cursor);
 
         String endpoint = getEndpoint();
@@ -223,11 +223,10 @@
         conn.setDoOutput(true);
         Map<Category,Integer> categoryIdMap = new HashMap<>();
         categoryIdMap.put(category, categoryId);
-        WebQuery query = new WebQuery(categoryId, TestClass.class);
+        WebQuery query = new WebQuery(categoryId);
         query.where(key1, Criteria.EQUALS, "fluff");
         query.sort(key1, SortDirection.DESCENDING);
         query.limit(42);
-        query.setResultClassName(TestClass.class.getName());
         Gson gson = new Gson();
         OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
         String body = "query=" + URLEncoder.encode(gson.toJson(query), "UTF-8");
@@ -268,7 +267,7 @@
 
         conn.setDoOutput(true);
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        WebInsert insert = new WebInsert(categoryId, true, TestClass.class.getName());
+        WebInsert insert = new WebInsert(categoryId, true);
         Gson gson = new Gson();
         OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
         out.write("insert=");
@@ -305,7 +304,7 @@
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
         conn.setDoOutput(true);
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        Map<Category,Integer> categoryIds = new HashMap<>();
+        Map<Category<?>,Integer> categoryIds = new HashMap<>();
         categoryIds.put(category, categoryId);
         WebRemove remove = new WebRemove(categoryIds).from(category).where(key1, "test");
         Gson gson = new Gson();