I have a table column type bytea. It is populated using hibernate and a field of type Serializable. Any ideas how I would be able to retrieve the values outside hibernate in a simple java standalone program? The values are of type string, double or integer.
the database is UTF8
while(res.next()){
byte[] byteArr = res.getBytes("value");
}
while (res.next()) {
byte[] byteArr = res.getBytes("value");
ByteArrayInputStream is = new ByteArrayInputStream(byteArr);
ObjectInputStream ois = new ObjectInputStream(is);
Serializable val = (Serializable) ois.readObject();
System.out.println(val);
}
Related
I have this bundle:
Bundle bundle = new Bundle();
bundle.putString("u", mp); // String mp
bundle.putSerializable("m", mealplan); // String[7][6][4][5] mealplan
save.putExtra("b", bundle);
I need to put it inside a blob column but I don't know how exactly.
Bundle objects support Parcels, but the Parcel.marshall() documentation says:
The data you retrieve here must not be placed in any kind of persistent storage (on local disk, across a network, etc). For that, you should use standard serialization or another kind of general serialization mechanism. The Parcel marshalled representation is highly optimized for local IPC, and as such does not attempt to maintain compatibility with data created in different versions of the platform.
The easist serialization mechanism probably is JSON, which is a readable text format.
To create a JSON string, you have to construct a tree of JSONObject/JSONArray objects:
// write
JSONObject json = new JSONObject();
json.put("u", mp);
JSONArray mealplan_json = new JSONArray();
mealplan_json.put(...); // fill arrays recursively
json.put("m", mealplan_json);
String text = json.toString();
// read
JSONObject json = new JSONObject(text);
mp = json.getString("u");
JSONArray mealplan_json = json.getJSONArray("m");
...
If you want to save space with a binary encoding, you have to use serialization, which supports basic types and any object that correctly implements java.io.Serializable:
// write
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(mp);
oos.writeObject(mealplan);
oos.close();
byte[] bytes = bos.toByteArray();
// read
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
mp = (String) ois.readObject();
mealplan = (String[][][][]) ois.readObject();
Please note that this binary serialization does not store any key names ("u", "m"), so you have to ensure that all versions of your app write and read the same objects in the same order.
If you want to have a key/value structure, you have to implement your own helper functions that write values with a separate key string in front, and that read an arbitrary number of key/value pairs into a map.
Alternatively, create your own serializable object that contains the desired elements (and take care that this class stays compatible in future versions of your app):
class MealPlanData implements Serializable {
String u;
String[][][][] mp;
};
If you have only a Bundle object and do not know its structure, you have to handle the keys/values manually:
// write
oos.writeInt(bundle.size());
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
oos.writeObject(key);
oos.writeObject(value);
}
// read
int size = ios.readInt();
Map<String, Object> map = new ArrayMap<String, Object>();
for (int i = 0; i < size; i++) {
String key = (String) ios.readObject();
Object value = ios.readObject();
map.put(key, value);
}
I'm using Spring, Hibernate and Postgres.
In one of my model class I have:
#Entity
class SomeData {
private Long dataId;
private String name;
private Integer[] data;
}
It is already used and I have data in database in above format.
"data" field is a bytea (visible in phppgadmin) type, one of the example values saved in db is:
��ur[Ljava.lang.Integer;������xpsr...
Problem is that now I need to change model to
String[] data;
But when I do that Hibernate can't read those data because it has type Integer.
My question - is it possible to convert somehow these Integer array objects to String array objects? Using some db tool, sql query or Hibernate?
You need to write a conversion algorithm to run once. Something like:
Connection c = ((SessionImplementor)entitymanager).connection();
boolean oldstate = c.getAutoCommit();
c.setAutoCommit(false);
Statement s = c.createStatement();
PreparedStatement ps = c.prepareStatement("UPDATE my_table SET data = ? WHERE id = ?");
ResultSet rs = s.executeQuery("SELECT id, data FROM my_table");
ByteArrayInputStream bais;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectInputStream ois;
ObjectOutputStream oos = new ObjectOutputStream(baos);
while (rs.next()) {
long id = rs.getLong(1);
byte[] bdata = rs.getBytes(2);
bais = new ByteArrayInputStream(bdata);
ois = new ObjectInputStream(bais);
Integer[] olddata = (Integer[]) ois.readObject();
String[] newdata = new String[olddata.length];
for (int i = 0; i < olddata.length; i++) {
Integer din = olddata[i];
String dout = null;
if (din != null) {
dout = din.toString();
}
newdata[i] = dout;
}
oos.writeObject(newdata);
oos.flush();
ps.setLong(1, id);
ps.setBytes(2, baos.toByteArray());
baos.reset();
}
c.commit();
c.setAutoCommit(oldstate);
If you want to do it through Hibernate, you'd need a secondary column, or you'd have to change it to Object[], run the conversion, then change it to String[], but that's not convenient for update on production, nor is it efficient, as you'd go through a lot of layers of validations and conversions inside Hibernate.
However, if you choose to use array types inside the database itself, I have a standalone module currently proposed that allows for it https://github.com/hibernate/hibernate-orm/pull/1499 . We don't have test-cases that don't work with it, but if you can find any that need fixing, that would help with getting it approved.
I have a code where I am converting array list to byte array and then saving that byte array as a BLOB in MySQL database. Below is code:-
Object temp = attributes.get(columnName);
if (temp instanceof List && temp != null) {
List extraAttributes = (ArrayList) temp;
resultStmt.setBytes(currentIndex, createByteArray(extraAttributes));
The method createByteArray is defined as below:
private byte [] createByteArray( Object obj)
{
byte [] bArray = null;
try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream objOstream = new ObjectOutputStream(baos);
objOstream.writeObject(obj);
bArray = baos.toByteArray();
}
catch (Exception e)
{
TraceDbLog.writeError("Problem in createByteArray", e);
}
return bArray;
}
Well the above code was written earlier for writing HashMap to BLOB i am using same for converting ArrayList if HashMap to BLOB.
The problem which is occurring in read code when i am reading the blob.
private Object readBytes (ResultSet rs, String columnName)
throws SQLException
{
ObjectInputStream ois = null;
byte [] newArray;
Object obj = null;
try
{
newArray = rs.getBytes(columnName);
ois = new ObjectInputStream (new ByteArrayInputStream(newArray));
obj = ois.readObject ();
}
In the read part the object is not coming as arrayList of hasMap and in debug perspective in eclipse eclipse is also not able to inspect the object which is coming.
I have also tried typecasting the object to List but still no success in getting the right response.
Please tell me whether there is any flaw in reading/writing the above BLOB.
I have added sample coding for convert ArrayList to byte[].
One reasonable way would be to use UTF-8 encoding like DataOutputStream does for each string in the list. For a string it writes 2 bytes for the length of the UTF-8 encoding followed by the UTF-8 bytes.
This would be portable if you're not using Java on the other end. Here's an example of encoding and decoding an ArrayList:
// example input list
List<String> list = new ArrayList<String>();
list.add("foo");
list.add("bar");
list.add("baz");
// write to byte array
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
for (String element : list) {
out.writeUTF(element);
}
byte[] bytes = baos.toByteArray();
// read from byte array
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
DataInputStream in = new DataInputStream(bais);
while (in.available() > 0) {
String element = in.readUTF();
System.out.println(element);
}
The easiest way is to convert it to json string and then to bytes
Gson gson = new Gson();
Type type = new TypeToken<List<Alarm>>() {}.getType();
String json = gson.toJson(list, type);
byte[] bytes = json.getBytes();
I stored a Vector<'String> into a BLOB field in a sqlite DB.
The problem is when I want to get that Vector, it has to be with cur.getBlob (method from a Cursor cur) and it returns a byte[], the question is, how can I get my vector from these byte[].
Thanks!!!
I do not have any experience with android but from java viewpoint this should work:
byte[] youByteArray;
ByteArrayInputStream in = new ByteArrayInputStream(youByteArray);
ObjectInputStream is = new ObjectInputStream(in);
// Will throw compiler warnings but should work fine.
Vector<String> yourVector = (Vector<String>) is.readObject();
References: http://asktom.oracle.com/pls/apex/f?p=100:11:0::::p11_question_id:1285601748584
Vector<byte[]> records = new Vector<byte[]>();
records.add(byteData);
I'm trying to save a java ArrayList in a database (H2) by setting it as a blob, for retrieval later. If this is a bad approach, please say - I haven't been able to find much information on this area.
I have a column of type Blob in the database, and Hibernate maps to this with java.sql.Blob. The code I'm struggling with is:
Drawings drawing = new Drawings();
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
oos = new ObjectOutputStream(bos);
oos.writeObject(plan.drawingPane21.pointList);
byte[] buff = bos.toByteArray();
Blob drawingBlob = null;
drawingBlob.setBytes(0, buff);
drawing.setDrawingObject(drawingBlob);
} catch (Exception e){
System.err.println(e);
}
The object I'm trying to save into a blob (plan.drawingPane21.pointList) is of type ArrayList<DrawingDot>, DrawingDot being a custom class implementing Serializable.
My code is failing on the line drawingBlob.setBytes(0, buff); with a NullPointerException.
Help appreciated.
In case anyone is having the same problem, I solved it by taking advantage of the SerialBlob class's constructor rather than using setBytes:
byte[] buff = bos.toByteArray();
Blob drawingBlob = null;
drawingBlob = new SerialBlob(buff);
drawing.setDrawingObject(drawingBlob);
You have never initialized the variable drawingBlob:
Blob drawingBlob = null;//<- not initialized
drawingBlob.setBytes(0, buff);//<- drawingBlob is null here.
My knowledge of Hibernate is very limited, but I believe that if the data type is mapped to a Blob then hibernate will perform the serialization for you, which makes sense as the standard way to set data in a blob is via the methods in a parametrized PreparedStatement.