package squirrel; import java.sql.*; import java.util.*; public class LocalStorage { private final Connection conn; public LocalStorage() { this.conn = Database.getConnection(); } // Save: serialize constructor arguments public void save(String key, T value) { try { var ctor = value.getClass().getDeclaredConstructors()[0]; ctor.setAccessible(true); var fields = value.getClass().getDeclaredFields(); List pairs = new ArrayList<>(); for (var f : fields) { f.setAccessible(true); Object v = f.get(value); pairs.add(f.getName() + "=" + (v == null ? "null" : v.toString())); } try (PreparedStatement ps = conn.prepareStatement( "INSERT INTO storage(key, data) VALUES(?, ?) " + "ON CONFLICT(key) DO UPDATE SET data=excluded.data" )) { ps.setString(1, key); ps.setString(2, String.join(";", pairs)); ps.executeUpdate(); } } catch (Exception e) { throw new RuntimeException("Save failed", e); } } // Load: reconstruct using the constructor of clazz @SuppressWarnings("unchecked") public T load(String key, Class clazz) { try (PreparedStatement ps = conn.prepareStatement( "SELECT data FROM storage WHERE key=?" )) { ps.setString(1, key); ResultSet rs = ps.executeQuery(); if (!rs.next()) return null; String data = rs.getString("data"); Map map = new LinkedHashMap<>(); for (String pair : data.split(";")) { if (pair.isBlank()) continue; int idx = pair.indexOf('='); if (idx == -1) continue; map.put(pair.substring(0, idx), pair.substring(idx + 1)); } var ctor = clazz.getDeclaredConstructors()[0]; ctor.setAccessible(true); Class[] paramTypes = ctor.getParameterTypes(); Object[] converted = new Object[paramTypes.length]; int i = 0; for (Class pt : paramTypes) { String raw = map.values().toArray(new String[0])[i]; if (pt == int.class || pt == Integer.class) { converted[i] = Integer.parseInt(raw); } else if (pt == long.class || pt == Long.class) { converted[i] = Long.parseLong(raw); } else if (pt == double.class || pt == Double.class) { converted[i] = Double.parseDouble(raw); } else if (pt == String.class) { converted[i] = raw; } else { throw new IllegalArgumentException("Unsupported param type: " + pt); } i++; } return (T) ctor.newInstance(converted); } catch (Exception e) { throw new RuntimeException("Load failed", e); } } public void flush() { try (Statement stmt = conn.createStatement()) { stmt.executeUpdate("DELETE FROM storage"); } catch (Exception e) { throw new RuntimeException("Flush failed", e); } } }