Implement LocalStorage class for data serialization and deserialization with database integration
This commit is contained in:
parent
bd61b1f2a3
commit
6ef835fd31
95
src/squirrel/LocalStorage.java
Normal file
95
src/squirrel/LocalStorage.java
Normal file
@ -0,0 +1,95 @@
|
||||
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 <T> void save(String key, T value) {
|
||||
try {
|
||||
var ctor = value.getClass().getDeclaredConstructors()[0];
|
||||
ctor.setAccessible(true);
|
||||
|
||||
var fields = value.getClass().getDeclaredFields();
|
||||
List<String> 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> T load(String key, Class<T> 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<String, String> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user