Blob object not working properly even though the class is seralized - java

I have class which is seralized and does convert a very large amount of data object to blob to save it to database.In the same class there is decode method to convert blob to the actual object.Following is the code for encode and decode of the object.
private byte[] encode(ScheduledReport schedSTDReport)
{
byte[] bytes = null;
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(schedSTDReport);
oos.flush();
oos.close();
bos.close();
//byte [] data = bos.toByteArray();
//ByteArrayOutputStream baos = new ByteArrayOutputStream();
//GZIPOutputStream out = new GZIPOutputStream(baos);
//XMLEncoder encoder = new XMLEncoder(out);
//encoder.writeObject(schedSTDReport);
//encoder.close();
bytes = bos.toByteArray();
//GZIPOutputStream out = new GZIPOutputStream(bos);
//out.write(bytes);
//bytes = bos.toByteArray();
}
catch (Exception e)
{
_log.error("Exception caught while encoding/zipping Scheduled STDReport", e);
}
decode(bytes);
return bytes;
}
/*
* Decode the report definition blob back to the
* ScheduledReport object.
*/
private ScheduledReport decode(byte[] bytes)
{
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ScheduledReport sSTDR = null;
try
{
ObjectInputStream ois = new ObjectInputStream(bais);
//GZIPInputStream in = new GZIPInputStream(bais);
//XMLDecoder decoder = new XMLDecoder(in);
sSTDR = (ScheduledReport)ois.readObject();//decoder.readObject();
//decoder.close();
}
catch (Exception e)
{
_log.error("IOException caught while decoding/unzipping Scheduled STDReport", e);
}
return sSTDR;
}
The problem here is whenver I change something else in this class
means any other method,a new class version is created and so the new version the class is unable to decode the originally encoded blob object. The object which I am passing for encode is also seralized object but this problem exists. Any ideas thanks

Yup, Java binary serialization is pretty brittle :(
You can add a static serialVersionUID field to the class so that you can control the version numbers... this should prevent problems due to adding methods. You'll still run into potential issues when fields are added though. See the JavaDocs for Serializable for some more details.
You might want to consider using another serialization format such as Protocol Buffers to give you more control though.

You can implement java.io.Externalizable so that you are able to control what is serialized and expected in deserialization.

Related

How can I create a truststore from a base64 encoded String?

I have a String that is encoded in base64, I need to take this string, decode it and create a truststore file, but when I do that, the final file is not valid. Here is my code:
public static void buildFile() {
String exampleofencoded = "asdfasdfasdfadfa";
File file = new File("folder/file.jks");
try (FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos))
{
Base64.Decoder decoder = Base64.getDecoder();
String decodedString =new String(decoder.decode(exampleofencoded).getBytes());
dos.writeBytes(decodedString);
}
catch (IOException e) {
System.out.println("Error creating file");
}
catch(NullPointerException e) {
System.out.println(e.getMessage();
}
}
The problem is two-fold.
You're converting a byte[] array to String, which is a lossy operation for actual binary data for most character sets (except maybe iso-8859-1).
You're using DataOutputStream, which is not a generic output stream, but intended for a specific serialization format of primitive types. And specifically its writeBytes method comes with an important caveat ("Each character in the string is written out, in sequence, by discarding its high eight bits."), which is one more reason why only using iso-8859-1 will likely work.
Instead, write the byte array directly to the file
public static void buildFile() {
String exampleofencoded = "asdfasdfasdfadfa";
File file = new File("folder/file.jks");
try (FileOutputStream fos = Files.newOutputStream(file.toPath()) {
Base64.Decoder decoder = Base64.getDecoder();
byte[] decodedbytes = decoder.decode(exampleofencoded);
fos.write(decodedbytes);
} catch (IOException e) {
System.out.println("Error creating file");
}
}
As an aside, you shouldn't catch NullPointerException in your code, it is almost always a problem that can be prevented by careful programming and/or validation of inputs. I would usually also advise against catch the IOException here and only printing it. It is probably better to propagate that exception as well, and let the caller handle it.

Using bytes to save object data from table to database in java

After some research it seems that I should be modifying my Object into bytes before sending. As my code is rather extensive i will give it in demonstrative pieces. I have the problem that nothing happens on successful completion of the program.
SAVE and SET variables are named in the following manner within the private void
int count = jTable1.getRowCount();
for(int i=0;i<count;i++){
//SET0
SET0 = new Object[1][count];
SET0[0][i] = txt.getText();
ByteArrayOutputStream baosSET0 = new ByteArrayOutputStream();
ObjectOutputStream oosSET0 = new ObjectOutputStream(baosSET0);
oosSET0.writeObject(SET0.toString());
byte[] SET0asBytes = baosSET0.toByteArray();
ByteArrayInputStream baisSET0 = new ByteArrayInputStream(SET0asBytes);
AND
SAVE = new Object[1][count];
SAVE[0][i] = jTable1.getModel().getValueAt(i,0);
ByteArrayOutputStream baosSAVE = new ByteArrayOutputStream();
ObjectOutputStream oosSAVE = new ObjectOutputStream(baosSAVE);
oosSAVE.writeObject(SAVE.toString());
byte[] SAVEasBytes = baosSAVE.toByteArray();
ByteArrayInputStream baisSAVE = new ByteArrayInputStream(SAVEasBytes);
Which leads into my SQL query:
String sqla1 = "INSERT INTO MIT(MTY_KOD,MTY_TYY,MTY_ALU,MTY_PAR1,MTY_PAR2,MTY_TOL,MTY_KAN,MTY_DATE) values(?,?,?,?,?,?,?,?);";
try{
pst = conn.prepareStatement(sqla1);
pst.setBinaryStream(1, baisSET0 , SET0asBytes.length);
pst.setBinaryStream(2, baisSET2, SET2asBytes.length);
pst.setBinaryStream(3, baisSET1, SET1asBytes.length);
pst.setBinaryStream(4, baisSAVE, SAVEasBytes.length);
pst.setBinaryStream(5, baisSAVE3, SAVE3asBytes.length);
pst.setBinaryStream(6, baisSAVE5, SAVE5asBytes.length);
pst.setBinaryStream(7, baisSET3, SET3asBytes.length);
pst.setBinaryStream(8, baisSET2, SET2asBytes.length);
pst.executeUpdate();}
catch (Exception e) {
System.out.println(e);
}
Event is triggered from:
if(txt.getText().isEmpty()){
}else{
try{
INSERT();}
catch(IOException ex){
System.out.println(ex);
}
}
The error i get is:
com.microsoft.sqlserver.jdbc.SQLServerException: The stream value is not the specified length. The specified length was 35, the actual length is 0.
Can anyone direct me on how to fix this error... or a different method of saving the information? Thank you.
I suspect you need to close your ObjectOutputStream.
From the doc:
FileOutputStream fos = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeInt(12345);
oos.writeObject("Today");
oos.writeObject(new Date());
oos.close(); // <-- my emphasis!

Reliably convert any object to String and then back again

Is there a reliable way to convert any object to a String and then back again to the same Object? I've seen some examples of people converting them using toString() and then passing that value into a constructor to reconstruct the object again but not all objects have a constructor like this so that method wont work for all cases. What way will?
Yes, it is called serialization!
String serializedObject = "";
// serialize the object
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream so = new ObjectOutputStream(bo);
so.writeObject(myObject);
so.flush();
serializedObject = bo.toString();
} catch (Exception e) {
System.out.println(e);
}
// deserialize the object
try {
byte b[] = serializedObject.getBytes();
ByteArrayInputStream bi = new ByteArrayInputStream(b);
ObjectInputStream si = new ObjectInputStream(bi);
MyObject obj = (MyObject) si.readObject();
} catch (Exception e) {
System.out.println(e);
}
This is the code:
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream so = new ObjectOutputStream(bo);
so.writeObject(stringList);
so.flush();
redisString = new String(Base64.encode(bo.toByteArray()));
}
catch (Exception e) {
e.printStackTrace();
}
try {
byte b[] = Base64.decode(redisString.getBytes());
ByteArrayInputStream bi = new ByteArrayInputStream(b);
ObjectInputStream si = new ObjectInputStream(bi);
List<String> stringList2 = (List<String>)si.readObject();
System.out.println(stringList2.get(1));
}
catch (Exception e) {
e.printStackTrace();
}
Serialize to byte array, convert to Base64. Then decode Base64 back to byte array and deserialize.
None will work in all cases. An object may, e.g., contain references to other JVMs handling their state, and this state may be not available for you to restore.
Additional problems you're going to meet will include open streams, listening sockets, and almost anything else from the outer world.
There's no need to repeat that most at least two of Java core engineers say that serialization was one of the greatest mistakes a single worst feature in Java, that is, after finalization. (I do love serialization nevertheless, it's handy. But it won't always work.)
One way is to use JSON. For implementation specific in Java, the answer might be given in this post:
java code corresponding to Newtonsoft.Json.JsonConvert.SerializeObject(Object source,Newtonsoft.Json.JsonSerializerSettings()) in .net?
Using JSON is reliable enough that it's used for web application development (Ajax).
Yes, it is Serialization You can use, ObjectInputStream.readObject and ObjectOutputStream.writeObject. Please see below example:
MyClass myClass = new MyClass();
FileOutputStream fileStream = new FileOutputStream("myObjectFile.txt");
ObjectOutputStream os = new ObjectOutputStream(fileStream);
os.writeObject(os);
os.close();
FileInputStream fileInStream = new FileInputStream("myObjectFile.txt");
ObjectInputStream ois = new ObjectInputStream(fileInStream);
MyClass myClass2 = ois.readObject();
ois.close();
You can use SerializationUtils from org.apache.commons.
It provides the methods serialize and deserialize

Java: how to serialize a 3rd party library produced Java Object?

So I am using a proprietary java library in a project which I don't have access to source code.
It throws a Message object, and obviously I can't implement Serializable. It's generated throughout runtime.
what are my options? Is there a way to serialize the Message object into a byte array and back into the object?
UPDATE: I was able to serialize the object to JSON (http://code.google.com/p/json-io/) but couldn't convert it back to an object as it returns null. So I am trying to convert it to byte array using the code below. Still not working.
public byte[] toByteArray (Object obj)
{
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
oos.close();
bos.close();
bytes = bos.toByteArray ();
}
catch (IOException ex) {
//TODO: Handle the exception
}
return bytes;
}
public Object toObject (byte[] bytes)
{
Object obj = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream (bytes);
ObjectInputStream ois = new ObjectInputStream (bis);
obj = ois.readObject();
}
catch (IOException ex) {
//TODO: Handle the exception
}
catch (ClassNotFoundException ex) {
//TODO: Handle the exception
}
return obj;
}
You could write a wrapper that is serializable and stores everything you need to recreate the Message object.
XStream is one way to go.
Sure, you just can't use the java.lang.Serializable mechanism.
Choose any format: XML, JSON, protocol buffer, or something else that might work for you.
Now you're responsible for both ends of the conversation: serialization and deserialization.
If the object is a Java bean, you can use java.beans.XMLEncoder and java.beans.XMLDecoder for serialization.

collection of objects to bytes format and then vice versa in java

I have a collection of objects which i need to store in byte format and then afterwards i have to convert the data which in bytes back into collection of objects.I need the answer in java.
For eg I have an array of objects(any type) then i have to convert this array to byte array in java and then vice versa.
Please if possible suggest me the collection to use and the methods which support it.
Assuming that Foo implements Serializable, just do
List<Foo> list = createItSomehow();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
try {
oos.writeObject(list);
} finally {
oos.close();
}
byte[] bytes = baos.toByteArray();
// ...
And the other way round:
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
List<Foo> list = null;
try {
list = (List<Foo>) ois.readObject();
} finally {
ois.close();
}
// ...
Instead of ByteArrayOutputStream and ByteArrayInputStream you can of course also supply FileOutputStream and FileInputStream respectively to write/read it to/from file.
See also:
The Java Tutorials - Essential Classes - Basic I/O - Object Streams

Categories