I wanted an RDBMS backed Map
, with it's keys and values immediately persisted to a relational database for use with a properties design pattern for prototype based programming.
I'm not sure if it'll be useful to anybody else, or even me for that matter, but I thought I'd put it out there anyway. The implementation, RdbmsMap
, implements the java.util.Map
interface and reads from, and writes to, a PostgreSQL database. The implementation supports key and values types of: null
, Boolean
, Integer
, Double
, String
and RdbmsMap
(the persistent Map class itself).
The ER diagram looks like this:
The PostgreSQL code to create this schema is:
rdbms-map.sql
CREATE TABLE map ( id serial NOT NULL, CONSTRAINT map_pkey PRIMARY KEY (id) ); CREATE TABLE entry ( id serial NOT NULL, map_id integer NOT NULL, key_type character(1) NOT NULL, value_type character(1) NOT NULL, CONSTRAINT entry_pkey PRIMARY KEY (id), CONSTRAINT entry_map_id_fkey FOREIGN KEY (map_id) REFERENCES map (id) ON DELETE CASCADE ); CREATE INDEX entry_key_type_idx ON entry (key_type); CREATE INDEX entry_value_type_idx ON entry (value_type); CREATE TABLE object_integer ( id serial NOT NULL, entry_id integer NOT NULL, map_id integer NOT NULL, type character(1) NOT NULL, value integer NOT NULL, CONSTRAINT object_integer_pkey PRIMARY KEY (id), CONSTRAINT object_integer_entry_id_fkey FOREIGN KEY (entry_id) REFERENCES entry (id) ON DELETE CASCADE, CONSTRAINT object_integer_map_id_fkey FOREIGN KEY (map_id) REFERENCES map (id) ON DELETE CASCADE ); CREATE INDEX object_integer_type_idx ON object_integer (type); CREATE INDEX object_integer_value_idx ON object_integer (value); CREATE TABLE object_boolean ( id serial NOT NULL, entry_id integer NOT NULL, map_id integer NOT NULL, type character(1) NOT NULL, value boolean NOT NULL, CONSTRAINT object_boolean_pkey PRIMARY KEY (id), CONSTRAINT object_boolean_entry_id_fkey FOREIGN KEY (entry_id) REFERENCES entry (id) ON DELETE CASCADE, CONSTRAINT object_boolean_map_id_fkey FOREIGN KEY (map_id) REFERENCES map (id) ON DELETE CASCADE ); CREATE INDEX object_boolean_type_idx ON object_boolean (type); CREATE INDEX object_boolean_value_idx ON object_boolean (value); CREATE TABLE object_numeric ( id serial NOT NULL, entry_id integer NOT NULL, map_id integer NOT NULL, type character(1) NOT NULL, value numeric NOT NULL, CONSTRAINT object_numeric_pkey PRIMARY KEY (id), CONSTRAINT object_numeric_entry_id_fkey FOREIGN KEY (entry_id) REFERENCES entry (id) ON DELETE CASCADE, CONSTRAINT object_numeric_map_id_fkey FOREIGN KEY (map_id) REFERENCES map (id) ON DELETE CASCADE ); CREATE INDEX object_numeric_type_idx ON object_numeric (type); CREATE INDEX object_numeric_value_idx ON object_numeric (value); CREATE TABLE object_text ( id serial NOT NULL, entry_id integer NOT NULL, map_id integer NOT NULL, type character(1) NOT NULL, value text NOT NULL, CONSTRAINT object_text_pkey PRIMARY KEY (id), CONSTRAINT object_text_entry_id_fkey FOREIGN KEY (entry_id) REFERENCES entry (id) ON DELETE CASCADE, CONSTRAINT object_text_map_id_fkey FOREIGN KEY (map_id) REFERENCES map (id) ON DELETE CASCADE ); CREATE INDEX object_text_type_idx ON object_text (type); CREATE INDEX object_text_value_idx ON object_text (value); CREATE TABLE object_null ( id serial NOT NULL, entry_id integer NOT NULL, map_id integer NOT NULL, type character(1) NOT NULL, CONSTRAINT object_null_pkey PRIMARY KEY (id), CONSTRAINT object_null_entry_id_fkey FOREIGN KEY (entry_id) REFERENCES entry (id) ON DELETE CASCADE, CONSTRAINT object_null_map_id_fkey FOREIGN KEY (map_id) REFERENCES map (id) ON DELETE CASCADE ); CREATE INDEX object_null_type_idx ON object_null (type); CREATE TABLE object_map ( id serial NOT NULL, entry_id integer NOT NULL, map_id integer NOT NULL, type character(1) NOT NULL, value integer NOT NULL, CONSTRAINT object_map_pkey PRIMARY KEY (id), CONSTRAINT object_map_entry_id_fkey FOREIGN KEY (entry_id) REFERENCES entry (id) ON DELETE CASCADE, CONSTRAINT object_map_map_id_fkey FOREIGN KEY (map_id) REFERENCES map (id) ON DELETE CASCADE, CONSTRAINT object_map_value_fkey FOREIGN KEY (value) REFERENCES map (id) ON DELETE CASCADE ); CREATE INDEX object_map_type_idx ON object_map (type);
The Map
implementation is:
RdbmsMap.java
package org.adrianwalker.rdbmsmap; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Set; public final class RdbmsMap<K, V> implements Map<K, V> { // object types private static final String OBJECT_NULL_TYPE = "0"; private static final String OBJECT_INTEGER_TYPE = "I"; private static final String OBJECT_BOOLEAN_TYPE = "B"; private static final String OBJECT_NUMERIC_TYPE = "N"; private static final String OBJECT_TEXT_TYPE = "T"; private static final String OBJECT_MAP_TYPE = "M"; // entry types private static final String ENTRY_KEY_TYPE = "K"; private static final String ENTRY_VALUE_TYPE = "V"; // object types private static final String OBJECT_TABLE = "object_table"; private static final String OBJECT_NULL_TABLE = "object_null"; private static final String OBJECT_INTEGER_TABLE = "object_integer"; private static final String OBJECT_BOOLEAN_TABLE = "object_boolean"; private static final String OBJECT_NUMERIC_TABLE = "object_numeric"; private static final String OBJECT_TEXT_TABLE = "object_text"; private static final String OBJECT_MAP_TABLE = "object_map"; // inserts private static final String INSERT_MAP = "insert into map(id) values(nextval('map_id_seq')) returning id"; private static final String INSERT_ENTRY = "insert into entry(id, map_id, key_type, value_type) values(nextval('entry_id_seq'), ?, ?, ?) returning id"; private static final String INSERT_OBJECT = "insert into " + OBJECT_TABLE + "(id, entry_id, map_id, type, value) values(nextval('" + OBJECT_TABLE + "_id_seq'), ?, ?, ?, ?) returning id"; // counts private static final String COUNT_ENTRIES = "select count(*) from entry where map_id = ?"; private static final String COUNT_OBJECT = "select count(*) from " + OBJECT_TABLE + " where map_id = ? and type = ? and value = ?"; // selects private static final String SELECT_ENTRIES = "select id, key_type, value_type from entry where map_id = ?"; private static final String SELECT_ENTRY_BY_OBJECT = "select value_type, id from entry where id = (select entry_id from " + OBJECT_TABLE + " where map_id = ? and type = ? and value = ?)"; private static final String SELECT_OBJECT_BY_ENTRY = "select value from " + OBJECT_TABLE + " where map_id = ? and type = ? and entry_id = ?"; private static final String SELECT_OBJECT = "select value from " + OBJECT_TABLE + " where map_id = ? and type = ?"; // deletes private static final String DELETE_ENTRIES = "delete from entry where map_id = ?"; private static final String DELETE_ENTRY_BY_OBJECT = "delete from entry where id = (select entry_id from " + OBJECT_TABLE + " where map_id = ? and type = ? and value = ?)"; // specific cases for nulls private static final String INSERT_OBJECT_NULL = "insert into " + OBJECT_NULL_TABLE + "(id, entry_id, map_id, type) values(nextval('" + OBJECT_NULL_TABLE + "_id_seq'), ?, ?, ?) returning id"; private static final String COUNT_OBJECT_NULL = "select count(*) from " + OBJECT_NULL_TABLE + " where map_id = ? and type = ?"; private static final String SELECT_ENTRY_BY_OBJECT_NULL = "select value_type, id from entry where id = (select entry_id from " + OBJECT_NULL_TABLE + " where map_id = ? and type = ?)"; private static final String SELECT_OBJECT_NULL_BY_ENTRY = "select null from " + OBJECT_NULL_TABLE + " where map_id = ? and type = ? and entry_id = ?"; private static final String SELECT_OBJECT_NULL = "select null from " + OBJECT_NULL_TABLE + " where map_id = ? and type = ?"; private static final String DELETE_ENTRY_BY_OBJECT_NULL = "delete from entry where id = (select entry_id from " + OBJECT_NULL_TABLE + " where map_id = ? and type = ?)"; private final Connection connection; private final int mapId; public RdbmsMap(final Connection connection) { this.connection = connection; try { this.mapId = inserMap(); } catch (final SQLException sqle) { throw new RuntimeException(sqle); } } private RdbmsMap(final Connection connection, final int mapId) { this.connection = connection; this.mapId = mapId; } public int getMapId() { return mapId; } @Override public void clear() { try { delete(); } catch (final SQLException sqle) { throw new RuntimeException(sqle); } } @Override public boolean containsKey(final Object key) { try { return countObjects(key, ENTRY_KEY_TYPE) > 0; } catch (final SQLException sqle) { throw new RuntimeException(sqle); } } @Override public boolean containsValue(final Object value) { try { return countObjects(value, ENTRY_VALUE_TYPE) > 0; } catch (final SQLException sqle) { throw new RuntimeException(sqle); } } @Override public Set<Entry<K, V>> entrySet() { try { return selectEntries(); } catch (final SQLException sqle) { throw new RuntimeException(sqle); } } @Override public V get(final Object key) { try { return select(key); } catch (final SQLException sqle) { throw new RuntimeException(sqle); } } @Override public Set<K> keySet() { try { return (Set<K>) selectObjects(ENTRY_KEY_TYPE); } catch (final SQLException sqle) { throw new RuntimeException(sqle); } } @Override public V put(final K key, final V value) { Object previousValue = remove(key); try { insert(key, value); } catch (final SQLException sqle) { throw new RuntimeException(sqle); } return (V) previousValue; } @Override public void putAll(final Map<? extends K, ? extends V> m) { for (Entry<? extends K, ? extends V> entry : m.entrySet()) { put(entry.getKey(), entry.getValue()); } } @Override public V remove(final Object key) { try { if (countObjects(key, ENTRY_KEY_TYPE) > 0) { V value = select(key); delete(key, ENTRY_KEY_TYPE); return value; } } catch (final SQLException sqle) { throw new RuntimeException(sqle); } return null; } @Override public int size() { try { return countEntries(); } catch (final SQLException sqle) { throw new RuntimeException(sqle); } } @Override public boolean isEmpty() { return size() == 0; } @Override public Collection<V> values() { try { return selectObjects(ENTRY_VALUE_TYPE); } catch (final SQLException sqle) { throw new RuntimeException(sqle); } } private PreparedStatement prepareStatement(final String sql) throws SQLException { return connection.prepareStatement(sql); } private int inserMap() throws SQLException { PreparedStatement insertMap = prepareStatement(INSERT_MAP); ResultSet result = insertMap.executeQuery(); if (!result.next()) { throw new RuntimeException(); } return result.getInt(1); } private int countEntries() throws SQLException { PreparedStatement countEntries = prepareStatement(COUNT_ENTRIES); countEntries.setInt(1, mapId); ResultSet result = countEntries.executeQuery(); if (!result.next()) { return 0; } return result.getInt(1); } private int countObjects(final Object obj, final String entryType) throws SQLException { String objectType = getType(obj); PreparedStatement countObject; if (objectType.equals(OBJECT_NULL_TYPE)) { countObject = prepareStatement(COUNT_OBJECT_NULL); } else if (objectType.equals(OBJECT_INTEGER_TYPE)) { countObject = prepareStatement(COUNT_OBJECT.replace(OBJECT_TABLE, OBJECT_INTEGER_TABLE)); countObject.setInt(3, (Integer) obj); } else if (objectType.equals(OBJECT_BOOLEAN_TYPE)) { countObject = prepareStatement(COUNT_OBJECT.replace(OBJECT_TABLE, OBJECT_BOOLEAN_TABLE)); countObject.setBoolean(3, (Boolean) obj); } else if (objectType.equals(OBJECT_NUMERIC_TYPE)) { countObject = prepareStatement(COUNT_OBJECT.replace(OBJECT_TABLE, OBJECT_NUMERIC_TABLE)); countObject.setDouble(3, (Double) obj); } else if (objectType.equals(OBJECT_TEXT_TYPE)) { countObject = prepareStatement(COUNT_OBJECT.replace(OBJECT_TABLE, OBJECT_TEXT_TABLE)); countObject.setString(3, (String) obj); } else if (objectType.equals(OBJECT_MAP_TYPE)) { countObject = prepareStatement(COUNT_OBJECT.replace(OBJECT_TABLE, OBJECT_MAP_TABLE)); countObject.setString(3, (String) obj); } else { return 0; } countObject.setInt(1, mapId); countObject.setString(2, entryType); countObject.executeQuery(); ResultSet result = countObject.executeQuery(); if (!result.next()) { return 0; } return result.getInt(1); } private V select(final Object key) throws SQLException { String keyType = getType(key); PreparedStatement selectEntry; if (keyType.equals(OBJECT_NULL_TYPE)) { selectEntry = prepareStatement(SELECT_ENTRY_BY_OBJECT_NULL); } else if (keyType.equals(OBJECT_INTEGER_TYPE)) { selectEntry = prepareStatement(SELECT_ENTRY_BY_OBJECT.replace(OBJECT_TABLE, OBJECT_INTEGER_TABLE)); selectEntry.setInt(3, (Integer) key); } else if (keyType.equals(OBJECT_BOOLEAN_TYPE)) { selectEntry = prepareStatement(SELECT_ENTRY_BY_OBJECT.replace(OBJECT_TABLE, OBJECT_BOOLEAN_TABLE)); selectEntry.setBoolean(3, (Boolean) key); } else if (keyType.equals(OBJECT_NUMERIC_TYPE)) { selectEntry = prepareStatement(SELECT_ENTRY_BY_OBJECT.replace(OBJECT_TABLE, OBJECT_NUMERIC_TABLE)); selectEntry.setDouble(3, (Double) key); } else if (keyType.equals(OBJECT_TEXT_TYPE)) { selectEntry = prepareStatement(SELECT_ENTRY_BY_OBJECT.replace(OBJECT_TABLE, OBJECT_TEXT_TABLE)); selectEntry.setString(3, (String) key); } else if (keyType.equals(OBJECT_MAP_TYPE)) { selectEntry = prepareStatement(SELECT_ENTRY_BY_OBJECT.replace(OBJECT_TABLE, OBJECT_MAP_TABLE)); selectEntry.setString(3, (String) key); } else { return null; } selectEntry.setInt(1, mapId); selectEntry.setString(2, ENTRY_KEY_TYPE); ResultSet result = selectEntry.executeQuery(); if (!result.next()) { return null; } String objectType = result.getString(1); int entryId = result.getInt(2); Object value = selectObject(objectType, ENTRY_VALUE_TYPE, entryId); return (V) value; } private Collection selectObjects(final String entryType, final String objectType) throws SQLException { Collection objs; if (entryType.equals(ENTRY_KEY_TYPE)) { objs = new HashSet(); } else if (entryType.equals(ENTRY_VALUE_TYPE)) { objs = new ArrayList(); } else { return null; } PreparedStatement selectObject; if (objectType.equals(OBJECT_NULL_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT_NULL); } else if (objectType.equals(OBJECT_INTEGER_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT.replace(OBJECT_TABLE, OBJECT_INTEGER_TABLE)); } else if (objectType.equals(OBJECT_BOOLEAN_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT.replace(OBJECT_TABLE, OBJECT_BOOLEAN_TABLE)); } else if (objectType.equals(OBJECT_NUMERIC_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT.replace(OBJECT_TABLE, OBJECT_NUMERIC_TABLE)); } else if (objectType.equals(OBJECT_TEXT_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT.replace(OBJECT_TABLE, OBJECT_TEXT_TABLE)); } else if (objectType.equals(OBJECT_MAP_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT.replace(OBJECT_TABLE, OBJECT_MAP_TABLE)); } else { return objs; } selectObject.setInt(1, mapId); selectObject.setString(2, entryType); ResultSet result = selectObject.executeQuery(); while (result.next()) { if (objectType.equals(OBJECT_NULL_TYPE)) { objs.add(null); } else if (objectType.equals(OBJECT_INTEGER_TYPE)) { objs.add(result.getInt(1)); } else if (objectType.equals(OBJECT_BOOLEAN_TYPE)) { objs.add(result.getBoolean(1)); } else if (objectType.equals(OBJECT_NUMERIC_TYPE)) { objs.add(result.getDouble(1)); } else if (objectType.equals(OBJECT_TEXT_TYPE)) { objs.add(result.getString(1)); } else if (objectType.equals(OBJECT_MAP_TYPE)) { objs.add(new RdbmsMap<K, V>(connection, result.getInt(1))); } } return objs; } private Collection selectObjects(final String entryType) throws SQLException { Collection objs = selectObjects(entryType, OBJECT_NULL_TYPE); objs.addAll(selectObjects(entryType, OBJECT_INTEGER_TYPE)); objs.addAll(selectObjects(entryType, OBJECT_BOOLEAN_TYPE)); objs.addAll(selectObjects(entryType, OBJECT_NUMERIC_TYPE)); objs.addAll(selectObjects(entryType, OBJECT_TEXT_TYPE)); objs.addAll(selectObjects(entryType, OBJECT_MAP_TYPE)); return objs; } private String getType(final Object obj) { String keyType; if (null == obj) { keyType = OBJECT_NULL_TYPE; } else if (obj instanceof Integer) { keyType = OBJECT_INTEGER_TYPE; } else if (obj instanceof Boolean) { keyType = OBJECT_BOOLEAN_TYPE; } else if (obj instanceof Number) { keyType = OBJECT_NUMERIC_TYPE; } else if (obj instanceof String) { keyType = OBJECT_TEXT_TYPE; } else if (obj instanceof RdbmsMap) { keyType = OBJECT_MAP_TYPE; } else { return null; } return keyType; } private int insertEntry(final K key, final V value) throws SQLException { String keyType = getType(key); String valueType = getType(value); PreparedStatement insertEntry = prepareStatement(INSERT_ENTRY); insertEntry.setInt(1, mapId); insertEntry.setString(2, keyType); insertEntry.setString(3, valueType); ResultSet result = insertEntry.executeQuery(); if (!result.next()) { return 0; } return result.getInt(1); } private void insertObject(final int entryId, final Object obj, final String entryType) throws SQLException { String objectType = getType(obj); PreparedStatement insertObject; if (objectType.equals(OBJECT_NULL_TYPE)) { insertObject = prepareStatement(INSERT_OBJECT_NULL); } else if (objectType.equals(OBJECT_INTEGER_TYPE)) { insertObject = prepareStatement(INSERT_OBJECT.replace(OBJECT_TABLE, OBJECT_INTEGER_TABLE)); insertObject.setInt(4, (Integer) obj); } else if (objectType.equals(OBJECT_BOOLEAN_TYPE)) { insertObject = prepareStatement(INSERT_OBJECT.replace(OBJECT_TABLE, OBJECT_BOOLEAN_TABLE)); insertObject.setBoolean(4, (Boolean) obj); } else if (objectType.equals(OBJECT_NUMERIC_TYPE)) { insertObject = prepareStatement(INSERT_OBJECT.replace(OBJECT_TABLE, OBJECT_NUMERIC_TABLE)); insertObject.setDouble(4, (Double) obj); } else if (objectType.equals(OBJECT_TEXT_TYPE)) { insertObject = prepareStatement(INSERT_OBJECT.replace(OBJECT_TABLE, OBJECT_TEXT_TABLE)); insertObject.setString(4, (String) obj); } else if (objectType.equals(OBJECT_MAP_TYPE)) { insertObject = prepareStatement(INSERT_OBJECT.replace(OBJECT_TABLE, OBJECT_MAP_TABLE)); insertObject.setInt(4, ((RdbmsMap) obj).mapId); } else { return; } insertObject.setInt(1, entryId); insertObject.setInt(2, mapId); insertObject.setString(3, entryType); insertObject.executeQuery(); } private void insert(final K key, final V value) throws SQLException { int entryId = insertEntry(key, value); insertObject(entryId, key, ENTRY_KEY_TYPE); insertObject(entryId, value, ENTRY_VALUE_TYPE); } private void delete(final Object obj, final String entryType) throws SQLException { String objectType = getType(obj); PreparedStatement deleteEntry; if (objectType.equals(OBJECT_NULL_TYPE)) { deleteEntry = prepareStatement(DELETE_ENTRY_BY_OBJECT_NULL); } else if (objectType.equals(OBJECT_INTEGER_TYPE)) { deleteEntry = prepareStatement(DELETE_ENTRY_BY_OBJECT.replace(OBJECT_TABLE, OBJECT_INTEGER_TABLE)); deleteEntry.setInt(3, (Integer) obj); } else if (objectType.equals(OBJECT_BOOLEAN_TYPE)) { deleteEntry = prepareStatement(DELETE_ENTRY_BY_OBJECT.replace(OBJECT_TABLE, OBJECT_BOOLEAN_TABLE)); deleteEntry.setBoolean(3, (Boolean) obj); } else if (objectType.equals(OBJECT_NUMERIC_TYPE)) { deleteEntry = prepareStatement(DELETE_ENTRY_BY_OBJECT.replace(OBJECT_TABLE, OBJECT_NUMERIC_TABLE)); deleteEntry.setDouble(3, (Double) obj); } else if (objectType.equals(OBJECT_TEXT_TYPE)) { deleteEntry = prepareStatement(DELETE_ENTRY_BY_OBJECT.replace(OBJECT_TABLE, OBJECT_TEXT_TABLE)); deleteEntry.setString(3, (String) obj); } else if (objectType.equals(OBJECT_MAP_TYPE)) { deleteEntry = prepareStatement(DELETE_ENTRY_BY_OBJECT.replace(OBJECT_TABLE, OBJECT_MAP_TABLE)); deleteEntry.setInt(3, ((RdbmsMap) obj).mapId); } else { return; } deleteEntry.setInt(1, mapId); deleteEntry.setString(2, entryType); deleteEntry.executeUpdate(); } private void delete() throws SQLException { PreparedStatement deleteEntries = prepareStatement(DELETE_ENTRIES); deleteEntries.setInt(1, mapId); deleteEntries.executeUpdate(); } private Object selectObject(final String objectType, final String entryType, final int entryId) throws SQLException { PreparedStatement selectObject; if (objectType.equals(OBJECT_NULL_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT_NULL_BY_ENTRY); } else if (objectType.equals(OBJECT_INTEGER_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT_BY_ENTRY.replace(OBJECT_TABLE, OBJECT_INTEGER_TABLE)); } else if (objectType.equals(OBJECT_BOOLEAN_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT_BY_ENTRY.replace(OBJECT_TABLE, OBJECT_BOOLEAN_TABLE)); } else if (objectType.equals(OBJECT_NUMERIC_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT_BY_ENTRY.replace(OBJECT_TABLE, OBJECT_NUMERIC_TABLE)); } else if (objectType.equals(OBJECT_TEXT_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT_BY_ENTRY.replace(OBJECT_TABLE, OBJECT_TEXT_TABLE)); } else if (objectType.equals(OBJECT_MAP_TYPE)) { selectObject = prepareStatement(SELECT_OBJECT_BY_ENTRY.replace(OBJECT_TABLE, OBJECT_MAP_TABLE)); } else { return null; } selectObject.setInt(1, mapId); selectObject.setString(2, entryType); selectObject.setInt(3, entryId); ResultSet result = selectObject.executeQuery(); if (!result.next()) { return null; } Object value; if (objectType.equals(OBJECT_NULL_TYPE)) { value = null; } else if (objectType.equals(OBJECT_INTEGER_TYPE)) { value = result.getInt(1); } else if (objectType.equals(OBJECT_BOOLEAN_TYPE)) { value = result.getBoolean(1); } else if (objectType.equals(OBJECT_NUMERIC_TYPE)) { value = result.getDouble(1); } else if (objectType.equals(OBJECT_TEXT_TYPE)) { value = result.getString(1); } else if (objectType.equals(OBJECT_MAP_TYPE)) { value = new RdbmsMap<K, V>(connection, result.getInt(1)); } else { return null; } return value; } private Set<Entry<K, V>> selectEntries() throws SQLException { Set<Entry<K, V>> entries = new HashSet<Entry<K, V>>(); PreparedStatement selectEntries = prepareStatement(SELECT_ENTRIES); selectEntries.setInt(1, mapId); ResultSet result = selectEntries.executeQuery(); while (result.next()) { int entryId = result.getInt(1); String keyType = result.getString(2); String valueType = result.getString(3); Entry<K, V> entry = new AbstractMap.SimpleEntry<K, V>( (K) selectObject(keyType, ENTRY_KEY_TYPE, entryId), (V) selectObject(valueType, ENTRY_VALUE_TYPE, entryId)); entries.add(entry); } return entries; } }
For examples and tests check out the source code.
Source Code
- Code available in GitHub - rdbms-map