How to send a string array using sockets and objectoutputstream - java

I have this to send string or integer but if i want to send a string array what should i use?
// A string ("Hello, World").
out.write("Hello, World".getBytes());
// An integer (123).
out.write(ByteBuffer.allocate(4).putInt(123).array());
Thanks in advance

Just write the array
ObjectOutputStream out = ...
String[] array = ...
out.writeObject(array);
If you're using ObjectOutputStream, there's no need to muck about with byte arrays - the class provides high-level methods to read and write entire objects.
Similarly:
out.writeInt(123);
out.writeObject("Hello, World");
You only need to use the write(byte[]) methods if you're using the raw, low-level OutputStream class.

Related

Java write a byte array with given ObjectOutputStream

I have a serializable class with custom writeObject() and readObject() methods.
When an object serializes, it needs to write two byte arrays, one after another. When something deserializes it, it needs to read those two arrays.
This is my code:
private void writeObject (final ObjectOutputStream out) throws IOException {
..
out.writeByte(this.signature.getV()); //one byte
out.writeObject(this.signature.getR()); //an array of bytes
out.writeObject(this.signature.getS()); //an array of bytes
out.close();
}
private void readObject (final ObjectInputStream in) throws IOException, ClassNotFoundException {
..
v = in.readByte();
r = (byte[])in.readObject();
s = (byte[])in.readObject();
this.signature = new Sign.SignatureData(v, r, s); //creating a new object because
//sign.signaturedata
// is not serializable
in.close();
}
When the object is being deserialized (readObject method) it throws an EOFException and all three variables are null/undefined.
Relating to question title, I saw a class called ByteArrayOutputStream, but to use it, it has to be enclosed in a ObjectOutputStream, which I cannot do, ad I have an OutputStream given and must write with it.
1. How do one properly write a byte array using objectOutputStream and properly reads it using ObjectInputStream?
2. Why the code above throws an EOFException without reading even one variable?
EDIT: I need to clarify: the readObject() and writeObject() are called by jvm itself while deserializing and serializing the object.
The second thing is, the SignatureData is a subclass to Sign, that comes from a third-party library - and that's why it's not serializable.
The third thing is, the problem probably lies in the reading and writing byte arrays by ObjectInput/ObjectOutput streams, not in the Sign.SignatureData class.

Google Protobuf ByteString vs. Byte[]

I am working with google protobuf in Java.
I see that it is possible to serialize a protobuf message to String, byte[], ByteString, etc:
(Source: https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/MessageLite)
I don't know what a ByteString is. I got the following definition from the the protobuf API documentation (source: https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/ByteString):
"Immutable sequence of bytes. Substring is supported by sharing the reference to the immutable underlying bytes, as with String."
It is not clear to me how a ByteString is different from a String or byte[].
Can somebody please explain?
Thanks.
You can think of ByteString as an immutable byte array. That's pretty much it. It's a byte[] which you can use in a protobuf. Protobuf does not let you use Java arrays because they're mutable.
ByteString exists because String is not suitable for representing arbitrary sequences of bytes. String is specifically for character data.
The protobuf MessageLite Interface provides toByteArray() and toByteString() methods. If ByteString is an immutable byte[], would the byte representation of a message represented by both ByteString and byte[] be the same?
Sort of. If you call toByteArray() you'll get the same value as if you were to call toByteString().toByteArray(). Compare the implementation of the two methods, in AbstractMessageLite:
public ByteString toByteString() {
try {
final ByteString.CodedBuilder out =
ByteString.newCodedBuilder(getSerializedSize());
writeTo(out.getCodedOutput());
return out.build();
} catch (IOException e) {
throw new RuntimeException(
"Serializing to a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public byte[] toByteArray() {
try {
final byte[] result = new byte[getSerializedSize()];
final CodedOutputStream output = CodedOutputStream.newInstance(result);
writeTo(output);
output.checkNoSpaceLeft();
return result;
} catch (IOException e) {
throw new RuntimeException(
"Serializing to a byte array threw an IOException " +
"(should never happen).", e);
}
}
A ByteString gives you the ability to perform more operations on the underlying data without having to copy the data into a new structure. For instance, if you wanted to provide a subset of bytes in a byte[] to another method, you would need to supply it with a start index and an end index. You can also concatenate ByteStrings without having to create a new data structure and manually copy the data.
However, with a ByteString you can give the method a subset of that data without the method knowing anything about the underlying storage. Just like a a substring of a normal String.
A String is for representing text and is not a good way to store binary data (as not all binary data has a textual equivalent unless you encode it in a manner that does: e.g. hex or Base64).

Sending two different type of arrays over TCP

I'm currently writing a network application that has to be able to send one 2D array of ints and one regular array of objects over a TCP connection.
My first, and only, solution so far is using ByteArrayOutputStream and ObjectOutputStream but this will only work if I send a specific type of array that I typecast back on the other side.
Now this would work
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(2dArray);
Byte[] send = baos.toByteArray();
But I can only use this if I only send 2d int-arrays since i need to typcast this on the other end and, as previously stated, I want to be able to send both 2d and regular arrays of different types.
Is there something other then ObjectOutputStream that can be used for this?
When you receive an object on the remote side you can check which kind of an object it is. For example you can write:
Object received = in.readObject();
if (received instanceof int[]) {
// received 1d array
int[] array1D = (int[]) received;
} else if (received instanceof int[][]) {
// received 2d array
int[][] array2D = (int[][]) received;
}
If you use something else for communication you'll still have to indicate the type of array you are sending in some way, so you'll always have the same problem.

Java - Concatenating Two OutputStreams

Is it possible to concatenate two OutputStreams (of the same type, stored as OutputStreams) without converting either to a string? If so, how?
So, If you have OutputStream A, and OutputStream B, and you want to concatenate them so that you end up with the stuff from A, followed by the stuff from B, you could convert B into an InputStream (a task that has likely been explained over 9000 times in this forum), and then Read data from this new InputStream, and write it to A. There: A generic answer for a generic question. Good luck!
A short example:
private void test(Document xmlDoc) throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
String s1 = "header";
outputStream.write(s1.getBytes());
ByteArrayOutputStream bodySubTree = (ByteArrayOutputStream) xmlToOutStream(xmlDoc);
outputStream.write(bodySubTree.toByteArray());
String s2 = "footer";
outputStream.write(s2.getBytes());
}

How to convert a non serializable object to byte array?

I'm trying to use javax.crypto.Cipher.doFinal(byte[]) method to encrypt an object. But, for security reasons, the object cannot be serializable.
So, how to convert the object to byte array without serialization?
--update
is using serialization the only way to use this Cipher method? Because as I know important data should not be serializable.
I used com.fasterxml.jackson.databind.ObjectMapper.
private static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.writeValue(os, obj);
return os.toByteArray();
}
You just serialize each of it's components. Recurse. Eventually you end up with native objects that you can serialize.
If you implement this by implementing java's serialization methods, java will ensure that you do not serialize any object twice and will take care of references for you.
In short, make the object serializable.
Solved,
instead of use a getByteArray() to call Cipher.doFinal(), I'll use Cipher.doFinal() inside the class, with a getEncryptedByteArray() method; so I serialize the data inside the class without making the class itself serializable, and the return result will be encrypted.
Any objection to this approach will be considered.. :)
Here is a simple example of serializing a class to a byte array.
public Class Foo {
private boolean isHappy;
private short happyCount;
private Bar bar;
public byte[] serializeData () throws IOException
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream( stream );
out.writeBoolean(isHappy);
out.writeShort( slope );
// Serialize bar which will just append to this byte stream
bar.doSerializeData(out);
// Return the serialized object.
byte[] data = stream.toByteArray();
// Clean up.
stream.close();
return data;
}
}
Of course, a lot of the details in your case depend on your class structure but hopefully this gets you pointed in the right direction.
To deserialize you just need to reverse the above.
java.beans.XMLEncoder/Decoder.

Categories