How to deep serialize object using ObjectOutputStream.writeObject()+Base64 (Java)? - java

I need to serialize an Object in java. Currently I'm doing it by using this code, which does:
ObjectOutputStream.writeObject(obj);
Base64 encode the obj
And reversing the process.
It works fine for primitive types inside the class, such as long and int.
However, all String objects inside that object become null. I'd need them to be included as well. Is there any way to do that?
Edit: code I'm using
// Modified from source: https://stackoverflow.com/questions/134492/how-to-serialize-an-object-into-a-string
public static Object FromString( String s )
{
Object o = null;
try {
byte[] data = Base64.getDecoder().decode(s);
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(data));
o = ois.readObject();
ois.close();
}
catch(Exception e)
{
System.out.println(e);
}
return o;
}
// Modified from source: https://stackoverflow.com/questions/134492/how-to-serialize-an-object-into-a-string
public static String ToString( Serializable o )
{
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
}
catch(Exception e)
{
System.out.println(e);
}
return Base64.getEncoder().encodeToString(baos.toByteArray());
}
EDIT: Pojo
public class SignedTimestamp implements Serializable {
private Long obj;
private byte[] signature;
private String signatureAsAString;
}
Output on the other application (receiving the data and deserializing):
obj = 1494609033621;
signature = null;
signatureAsAString = null;

I have just tested your code, and it's working okay.
I've created a source named SignedTimeStamp.java:
import java.io.*;
public class SignedTimestamp implements Serializable {
private Long obj;
private byte[] signature;
private String signatureAsAString;
public SignedTimestamp(Long obj, byte[] signature, String signatureAsAString) {
this.obj = obj;
this.signature = signature;
this.signatureAsAString = signatureAsAString;
}
public Long getObj() {
return this.obj;
}
public byte[] getSignature() {
return this.signature;
}
public String getSignatureAsAString() {
return this.signatureAsAString;
}
}
And declared another called Serializables.java, containing your code:
import java.io.;
import java.util.;
public class Serializables {
public static Object FromString(String s) {
Object o = null;
try {
byte[] data = Base64.getDecoder().decode(s);
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(data));
o = ois.readObject();
ois.close();
}
catch(Exception e)
{
System.out.println(e);
}
return o;
}
// Modified from source: http://stackoverflow.com/questions/134492/how-to-serialize-an-object-into-a-string
public static String ToString( Serializable o ) {
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
}
catch(Exception e)
{
System.out.println(e);
}
return Base64.getEncoder().encodeToString(baos.toByteArray());
}
}
Then, I created one main class in Serialize.java:
public class Serialize {
public static void main(String[] args) throws Exception {
SignedTimestamp o = new SignedTimestamp(100L, new byte[]{ (byte) 128 }, "Hello, world!");
System.out.println(Serializables.ToString(o));
}
}
Which returned me this result:
sh-4.3$ java Serialize
rO0ABXNyAA9TaWduZWRUaW1lc3RhbXCGTHiJ+JenzgIAA0wAA29ianQAEExqYXZhL2xhbmcvTG9uZztbAAlzaWduYXR1cmV0AAJbQkwAEnNpZ25hdHVyZUFzQVN0cmluZ3QAEkxqYXZhL2xhbmcvU3RyaW5nO3hwc3IADmphdmEubGFuZy
5Mb25nO4vkkMyPI98CAAFKAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAAAAABkdXIAAltCrPMX+AYIVOACAAB4cAAAAAGAdAANSGVsbG8sIHdvcmxkIQ==
sh-4.3$
Then, I created another main class in Deserialize.java:
public class Deserialize {
public static void main(String[] args) throws Exception {
String serialized =
"rO0ABXNyAA9TaWduZWRUaW1lc3RhbXCGTHiJ+JenzgIAA0wAA29ianQAEExqYXZhL2xhbmcvTG9uZztbAAlzaWduYXR1cmV0AAJbQkwAEnNpZ25hdHVyZUFzQVN0cmluZ3QAEkxqYXZhL2xhbmcvU3RyaW5nO3hwc3IADmphdmEubGFuZy" +
"5Mb25nO4vkkMyPI98CAAFKAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAAAAABkdXIAAltCrPMX+AYIVOACAAB4cAAAAAGAdAANSGVsbG8sIHdvcmxkIQ==";
SignedTimestamp o = (SignedTimestamp) Serializables.FromString(serialized);
System.out.println(o.getObj());
System.out.println(o.getSignature());
System.out.println(o.getSignatureAsAString());
}
}
And it returns this:
sh-4.3$ java Deserialize
100
[B#6bc7c054
Hello, world!
sh-4.3$
So, all in all, the code seems to be working perfectly.
How did you test your code? Perhaps the mistake is there.

I dont see any problem in that code. Please post your code so that we will dig further.
tried from my end:
Encoded serialized version
rO0ABXNyAAhFbXBsb3llZTLR4JLRYAw9AgAESQAGbnVtYmVyTAAHYWRkcmVzc3QAEkxqYXZhL2xhbmcvU3RyaW5nO0wADWFkZHJlc3NPYmplY3R0AAlMQWRkcmVzcztMAARuYW1lcQB+AAF4cAAAAGV0ABlQaG9ra2EgS3VhbiwgQW1iZWh0YSBQZWVyc3IAB0FkZHJlc3MkcEtPHXHTqQIAAUwACGFkZHJMaW5lcQB+AAF4cHEAfgAEdAAJUmV5YW4gQWxp
Reconstituted object
Employee [name=Reyan Ali, address=Phokka Kuan, Ambehta Peer, number=101, addressObject=Address [addrLine=Phokka Kuan, Ambehta Peer]]

Related

Java Object Serialization: serialize a Hashtable, then deserialize it in a HashMap

Java object serialization: I serialized this type of Hashtable for example of (Integer,Employee) and when I deserialize this, I would like to put the output in a HashMap. Is this possible? Because I get the java.lang.ClassCastException
public class Employee implements Serializable {
private static final long serialVersionUID = -7260877684654746408L;
private String name;
private int age;
Employee(String n, int a) {
name=n;
age=a;
}
public String toString() {
return "Name: "+name+". "+"Age: "+age+".";
}
}
public class Test {
public static void main(String[] args) {
Hashtable<Integer, Employee> ht = new Hashtable<Integer, Employee>() {
{
put(1, new Employee("John", 37));
put(2, new Employee("Julia", 36));
}
};
//HashMap<Integer,Employee> hm = new HashMap<Integer,Employee>();
try {
FileOutputStream outSer = new FileOutputStream("outSer.ser");
ObjectOutputStream os = new ObjectOutputStream(outSer);
os.writeObject(ht);
os.close();
FileInputStream input = new FileInputStream("outSer.ser");
ObjectInputStream ois = new ObjectInputStream(input);
HashMap<Integer,Employee> hm= (HashMap<Integer, Employee>)ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Is this possible?
Yes. But not the way you coded it. You would have to create your own HashMap and load it from the HashTable:
HashMap<Integer,Employee> hm= new HashMap<>((HashTable<Integer, Employee>)ois.readObject());

How to serialize a java object with not Serializable fields inside it into byte array and deserialize the array to get the original object

Greetings to the community, I recently came up with an issue in serialization and deserialization in my java project. I have an object of a class containing other objects as fields.
I would like to store the state of the object into a byte array and then deserialize the byte array and get back the original object.However,the objects consisting my object's fields are not Serializable(came from third party library) so had to declare them as transient in first place.
Now my object is serialized and deserialized but as was to be expected it's fields are null because of the transient declaration i mentioned before.I have tried to create locally into my Serialization class all the elements and assign to them the original ones values and continue the process but it didnt had any difference. I quote below part of my code, Any ideas ? Thanks beforehand :)
Here is the class of my object with it's fields
public class AbePublicKey implements java.io.Serializable{
private static final long serialVersionUID = 7526472295622776147L;
public transient Element g;
public transient Element h;
public transient Element f;
public transient Element e_g_g_hat_alpha;
}
Here is my Serializer function
public byte[] PublicKeytoByteArray(AbePublicKey publickey) throws IOException {
KeyAuthority keyauthority = new KeyAuthority();
byte[] bytes = null;
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
publickey.setElements(g, h, f, e_g_g_hat_alpha);
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(publickey);
oos.flush();
bytes = bos.toByteArray();
} finally {
if (oos != null)
oos.close();
}
if (bos != null) {
bos.close();
}
}
return bytes;
}
Here is my Deserializer function
public static AbePublicKey PublicKeyBytestoObject(byte[] publickeybytes) throws IOException, ClassNotFoundException {
AbePublicKey obj = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
bis = new ByteArrayInputStream(publickeybytes);
ois = new ObjectInputStream(bis);
obj = (AbePublicKey) ois.readObject();
} finally {
if (bis != null) {
bis.close();
}
if (ois != null) {
ois.close();
}
}
return obj;
}
If you want control over how an object is Serialized, implement the Externalizable interface and the associated readExternal and writeExternal methods. This gives you full control over how an object is serialized.
Clearly you can't serialize a class that contains fields that are not serializable. But you can perhaps write enough data to recreate the objects on your own.
If you are able to copy the values needed into new Serializable CustomElement objects inside your class, it should make a difference. Use copy constructors ( if available), or even reflection if you have enough information available.
You could wrap your Element fields in a class that is Serializable so that you can write them. This solution assumes you're able to call the necessary setters or constructor to recreate the Element after you read it.
Here is an example:
Very basic Element that is not Serializable
public class Element {
private String value;
public Element(){
value = null;
}
public Element(String value){
setValue(value);
}
public void setValue(String value){
this.value = value;
}
public String getValue(){
return value;
}
}
Now a very basic wrapper class that is Serializable
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
public class SerializableElement implements Serializable{
// Generated ID
private static final long serialVersionUID = -6751688345227423403L;
private transient Element element;
public SerializableElement(Element el)
{
element = el;
}
private void writeObject(java.io.ObjectOutputStream out)
throws IOException{
out.writeObject(element.getValue());
}
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException{
String elementValue = (String)in.readObject();
element = new Element(elementValue);
}
private void readObjectNoData()
throws ObjectStreamException{
element = null;
}
public Element getElement(){
return element;
}
}
Finally a main class to run the serializing and deserializing logic (slightly modified from what you posted) :
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializeMain {
public static void main(String[] args) {
SerializableElement serializableElement = new SerializableElement(
new Element("test value"));
try {
byte[] serializedData = storeElement(serializableElement);
SerializableElement loadedElement = loadElement(serializedData);
System.out.println("loadedElement.element.value: "
+ loadedElement.getElement().getValue());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static byte[] storeElement(SerializableElement sElement)
throws IOException {
byte[] bytes = null;
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(sElement);
oos.flush();
bytes = bos.toByteArray();
} finally {
if (oos != null) {
oos.close();
}
if (bos != null) {
bos.close();
}
}
return bytes;
}
public static SerializableElement loadElement(byte[] byteData)
throws IOException, ClassNotFoundException {
SerializableElement obj = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
bis = new ByteArrayInputStream(byteData);
ois = new ObjectInputStream(bis);
obj = (SerializableElement) ois.readObject();
} finally {
if (bis != null) {
bis.close();
}
if (ois != null) {
ois.close();
}
}
return obj;
}
}

LocalClassIncompatible when serializing Java standard class

I'm having problems to serialize a custom serializable object with a generated SerialVersionUID, since i get an InvalidClassException when trying to deserialize this objetc with the following error:
< com.assistantindustries.test.Prueba; local class incompatible:
stream classdesc serialVersionUID = 6090585534595974753, local class
serialVersionUID = 6090585536173033057>
I made a junit class for testing it and this error keeps happening. Here's the code for the test:
public class TestSerializacion {
public String pruebaToString(Serializable prueba){
ByteArrayOutputStream bs= new ByteArrayOutputStream();
ObjectOutputStream os = null;
try {
os = new ObjectOutputStream (bs);
os.writeObject(prueba);
os.close();
} catch (IOException e) {
e.printStackTrace();
}
return bs.toString();
}
public static Prueba getPruebaFromString(String prueba){
ByteArrayInputStream bs= new ByteArrayInputStream(prueba.getBytes());
ObjectInputStream is = null;
Prueba unObjetoSerializable = null;
try {
is = new ObjectInputStream(bs);
unObjetoSerializable = (Prueba)is.readObject();
is.close();
} catch (ClassNotFoundException | IOException e1) {
e1.printStackTrace();
}
return unObjetoSerializable;
}
#Test
public void testBasico(){
int i=453;
Prueba prueba=new Prueba(i);
String toSend=pruebaToString(prueba);
Prueba recibida=getPruebaFromString(toSend);
assertEquals(prueba.getPhrase(),recibida.getPhrase());
}
}
And the Class:
public class Prueba implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6090585536173033057L;
ArrayList<String> texts;
public Prueba(int semilla) {
Random r=new Random(semilla);
this.texts = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
char[] palabra=new char[10];
for (int j = 0; j < palabra.length; j++) {
palabra[j]=(char) (r.nextInt(256));
}
texts.add(new String(palabra));
}
}
public synchronized ArrayList<String> getTexts() {
return texts;
}
public synchronized void setTexts(ArrayList<String> texts) {
this.texts = texts;
}
public String getPhrase(){
String total="";
for(String s:this.texts){
total.concat(s);
}
return total;
}
}
All the answers I found about similar problems were solved by defining the serialVersionUID, but it is already defined in this class
Any help would be greatly appreciated! Thanks in advance!
Repeat after me. String is not a container for binary data. Write out 100 times. You shouldn't convert the result of serialization to a String. and back again. Pass it around as a byte[] array.

equivalent to python's shelve module in Java

Is there any module in Java equivalent to python's shelve module? I need this to achieve dictionary like taxonomic data access. Dictionary-like taxonomic data access is a powerful way to save Python objects in a persistently easy access database format. I need something for the same purpose but in Java.
I also needed this, so I wrote one. A bit late, but maybe it'll help.
It doesn't implement the close() method, but just use sync() since it only hold the file open when actually writing it.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
public class Shelf extends HashMap<String, Object> {
private static final long serialVersionUID = 7127639025670585367L;
private final File file;
public static Shelf open(File file) {
Shelf shelf = null;
try {
if (file.exists()) {
final FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
shelf = (Shelf) ois.readObject();
ois.close();
fis.close();
} else {
shelf = new Shelf(file);
shelf.sync();
}
} catch (Exception e) {
// TODO: handle errors
}
return shelf;
}
// Shelf objects can only be created or opened by the Shelf.open method
private Shelf(File file) {
this.file = file;
sync();
}
public void sync() {
try {
final FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(this);
oos.close();
fos.close();
} catch (Exception e) {
// TODO: handle errors
}
}
// Simple Test Case
public static void main(String[] args) {
Shelf shelf = Shelf.open(new File("test.obj"));
if (shelf.containsKey("test")) {
System.out.println(shelf.get("test"));
} else {
System.out.println("Creating test string. Run the program again.");
shelf.put("test", "Hello Shelf!");
shelf.sync();
}
}
}
You could use a serialisation library like Jackson which serialises POJOs to JSON.
An example from the tutorial:
Jackson's org.codehaus.jackson.map.ObjectMapper "just works" for
mapping JSON data into plain old Java objects ("POJOs"). For example,
given JSON data
{
"name" : { "first" : "Joe", "last" : "Sixpack" },
"gender" : "MALE",
"verified" : false,
"userImage" : "Rm9vYmFyIQ=="
}
It takes two lines of Java to turn it into a User instance:
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
User user = mapper.readValue(new File("user.json"), User.class);
Where the User class looks something like this (from an entry on Tatu's blog):
public class User {
public enum Gender { MALE, FEMALE };
public static class Name {
private String _first, _last;
public String getFirst() { return _first; }
public String getLast() { return _last; }
public void setFirst(String s) { _first = s; }
public void setLast(String s) { _last = s; }
}
private Gender _gender;
private Name _name;
private boolean _isVerified;
private byte[] _userImage;
public Name getName() { return _name; }
public boolean isVerified() { return _isVerified; }
public Gender getGender() { return _gender; }
public byte[] getUserImage() { return _userImage; }
public void setName(Name n) { _name = n; }
public void setVerified(boolean b) { _isVerified = b; }
public void setGender(Gender g) { _gender = g; }
public void setUserImage(byte[] b) { _userImage = b; }
}

Java: accessing a List of Strings as an InputStream

Is there any way InputStream wrapping a list of UTF-8 String? I'd like to do something like:
InputStream in = new XyzInputStream( List<String> lines )
You can read from a ByteArrayOutputStream and you can create your source byte[] array using a ByteArrayInputStream.
So create the array as follows:
List<String> source = new ArrayList<String>();
source.add("one");
source.add("two");
source.add("three");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (String line : source) {
baos.write(line.getBytes());
}
byte[] bytes = baos.toByteArray();
And reading from it is as simple as:
InputStream in = new ByteArrayInputStream(bytes);
Alternatively, depending on what you're trying to do, a StringReader might be better.
You can concatenate all the lines together to create a String then convert it to a byte array using String#getBytes and pass it into ByteArrayInputStream. However this is not the most efficient way of doing it.
In short, no, there is no way of doing this using existing JDK classes. You could, however, implement your own InputStream that read from a List of Strings.
EDIT: Dave Web has an answer above, which I think is the way to go. If you need a reusable class, then something like this might do:
public class StringsInputStream<T extends Iterable<String>> extends InputStream {
private ByteArrayInputStream bais = null;
public StringsInputStream(final T strings) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
for (String line : strings) {
outputStream.write(line.getBytes());
}
bais = new ByteArrayInputStream(outputStream.toByteArray());
}
#Override
public int read() throws IOException {
return bais.read();
}
#Override
public int read(byte[] b) throws IOException {
return bais.read(b);
}
#Override
public int read(byte[] b, int off, int len) throws IOException {
return bais.read(b, off, len);
}
#Override
public long skip(long n) throws IOException {
return bais.skip(n);
}
#Override
public int available() throws IOException {
return bais.available();
}
#Override
public void close() throws IOException {
bais.close();
}
#Override
public synchronized void mark(int readlimit) {
bais.mark(readlimit);
}
#Override
public synchronized void reset() throws IOException {
bais.reset();
}
#Override
public boolean markSupported() {
return bais.markSupported();
}
public static void main(String[] args) throws Exception {
List source = new ArrayList();
source.add("foo ");
source.add("bar ");
source.add("baz");
StringsInputStream<List<String>> in = new StringsInputStream<List<String>>(source);
int read = in.read();
while (read != -1) {
System.out.print((char) read);
read = in.read();
}
}
}
This basically an adapter for ByteArrayInputStream.
You can create some kind of IterableInputStream
public class IterableInputStream<T> extends InputStream {
public static final int EOF = -1;
private static final InputStream EOF_IS = new InputStream() {
#Override public int read() throws IOException {
return EOF;
}
};
private final Iterator<T> iterator;
private final Function<T, byte[]> mapper;
private InputStream current;
public IterableInputStream(Iterable<T> iterable, Function<T, byte[]> mapper) {
this.iterator = iterable.iterator();
this.mapper = mapper;
next();
}
#Override
public int read() throws IOException {
int n = current.read();
while (n == EOF && current != EOF_IS) {
next();
n = current.read();
}
return n;
}
private void next() {
current = iterator.hasNext()
? new ByteArrayInputStream(mapper.apply(iterator.next()))
: EOF_IS;
}
}
To use it
public static void main(String[] args) throws IOException {
Iterable<String> strings = Arrays.asList("1", "22", "333", "4444");
try (InputStream is = new IterableInputStream<String>(strings, String::getBytes)) {
for (int b = is.read(); b != -1; b = is.read()) {
System.out.print((char) b);
}
}
}
In my case I had to convert a list of string in the equivalent file (with a line feed for each line).
This was my solution:
List<String> inputList = Arrays.asList("line1", "line2", "line3");
byte[] bytes = inputList.stream().collect(Collectors.joining("\n", "", "\n")).getBytes();
InputStream inputStream = new ByteArrayInputStream(bytes);
You can do something similar to this:
https://commons.apache.org/sandbox/flatfile/xref/org/apache/commons/flatfile/util/ConcatenatedInputStream.html
It just implements the read() method of InputStream and has a list of InputStreams it is concatenating. Once it reads an EOF it starts reading from the next InputStream. Just convert the Strings to ByteArrayInputStreams.
you can also do this way create a Serializable List
List<String> quarks = Arrays.asList(
"up", "down", "strange", "charm", "top", "bottom"
);
//serialize the List
//note the use of abstract base class references
try{
//use buffering
OutputStream file = new FileOutputStream( "quarks.ser" );
OutputStream buffer = new BufferedOutputStream( file );
ObjectOutput output = new ObjectOutputStream( buffer );
try{
output.writeObject(quarks);
}
finally{
output.close();
}
}
catch(IOException ex){
fLogger.log(Level.SEVERE, "Cannot perform output.", ex);
}
//deserialize the quarks.ser file
//note the use of abstract base class references
try{
//use buffering
InputStream file = new FileInputStream( "quarks.ser" );
InputStream buffer = new BufferedInputStream( file );
ObjectInput input = new ObjectInputStream ( buffer );
try{
//deserialize the List
List<String> recoveredQuarks = (List<String>)input.readObject();
//display its data
for(String quark: recoveredQuarks){
System.out.println("Recovered Quark: " + quark);
}
}
finally{
input.close();
}
}
catch(ClassNotFoundException ex){
fLogger.log(Level.SEVERE, "Cannot perform input. Class not found.", ex);
}
catch(IOException ex){
fLogger.log(Level.SEVERE, "Cannot perform input.", ex);
}
I'd like to propose my simple solution:
public class StringListInputStream extends InputStream {
private final List<String> strings;
private int pos = 0;
private byte[] bytes = null;
private int i = 0;
public StringListInputStream(List<String> strings) {
this.strings = strings;
this.bytes = strings.get(0).getBytes();
}
#Override
public int read() throws IOException {
if (pos >= bytes.length) {
if (!next()) return -1;
else return read();
}
return bytes[pos++];
}
private boolean next() {
if (i + 1 >= strings.size()) return false;
pos = 0;
bytes = strings.get(++i).getBytes();
return true;
}
}

Categories