I've used Hessian for a while but just noticed the following behavior. If you serialize a java.lang.Character in Hessian, it deserializes as a String.
public class TestHessianChar {
public static void main(String... args) throws IOException {
// Serialize
Character c = new Character('x');
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Hessian2Output hessian2Output = new Hessian2Output( byteArrayOutputStream );
hessian2Output.startMessage();
hessian2Output.writeObject(c);
hessian2Output.completeMessage();
hessian2Output.close();
byte[] dataBytes = byteArrayOutputStream.toByteArray();
// Deserialize
Hessian2Input hessian2Input = new Hessian2Input( new ByteArrayInputStream( dataBytes ) );
hessian2Input.startMessage();
Object o = hessian2Input.readObject();
hessian2Input.completeMessage();
hessian2Input.close();
System.out.println(o.getClass().getName());
}
}
Output for this code is:
java.lang.String
I'm assuming it has something to do with language-independent serialization of primitives, but it's rather annoying. I am writing a JMS driver and need to distinguish between char and String, since the spec demands different behavior. I'm considering writing my own class to represent a char (and give up auto-boxing), but I wanted to know if there is a proper way to get Hessian to treat a Character as a Character before I start going through such contortions.
Related
Up to now, I've been using Protocol Buffers to serialize and deserialize objects using the code-generated classes.
Now I am attempting to serialize and deserialize a single 64-bit integer. The problem is, I'm getting different results in Java and C#.
Here's how I'm doing it in Java....
private static byte[] convertLongToByteArray(long value) throws IOException {
int size = CodedOutputStream.computeInt64SizeNoTag(value);
byte[] buffer = new byte[size];
CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(buffer);
codedOutputStream.writeInt64NoTag(value);
codedOutputStream.flush();
codedOutputStream.checkNoSpaceLeft();
return buffer;
}
And here's how I'm doing this in C#, using protobuf.net:
public void SerializeLongValue()
{
long n = 9876;
byte[] memoryBuffer = null;
using (MemoryStream destination = new MemoryStream())
{
ProtoBuf.Serializer.Serialize(destination, n);
destination.Flush();
memoryBuffer = destination.ToArray();
}
using (MemoryStream source = new MemoryStream(memoryBuffer))
{
long result = ProtoBuf.Serializer.Deserialize<long>(source);
Assert.AreEqual(n, result);
}
}
The java code converted the number 9876 to [0x94, 0x4D]
The C# code converted the number 9876 to [0x08, 0x94, 0x4D]
How do I do this so that both com.google.protobuf and protobuf.net produce identical outputs?
The protobuf.net method ProtoBuf.Serializer.Serialize forces a field header (field number=1) into the stream. That's the only way you can perform a serialization; this method invokes a number of internal methods which are not publicly available.
The solution I'm using is to change the Java code to also include a field header.
Here is my new Java code.
private static byte[] convertLongToByteArray(long value) throws IOException {
int size = CodedOutputStream.computeTagSize(1) + CodedOutputStream.computeInt64SizeNoTag(value);
byte[] buffer = new byte[size];
CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(buffer);
codedOutputStream.writeInt64(1, value);
codedOutputStream.flush();
codedOutputStream.checkNoSpaceLeft();
return buffer;
}
public static long convertByteArrayToLong(byte[] byteArray) throws IOException {
CodedInputStream codedInputStream = CodedInputStream.newInstance(byteArray);
codedInputStream.readTag();
return codedInputStream.readInt64();
}
The changes I've made are:
When computing the required buffer size, include a tag size
Instead of CodedOutputStream.WriteInt64NoTag, call CodedOutputStream.WriteInt64
When reading back, call CodedOutputStream.ReadTag before calling CodedOutputStream.ReadInt64
I have a Java object that is serializable. I need to let another Java webapp do something with this object. I'm currently using this setup to transfer the object:
Use a ByteArrayOutputStream baos
Put the baos in an ObjectOutputStream oos
Write the object using the oos, and get the byte[] from the baos
Use a Base64 encoder to encode the byte[] to another byte[]
send the bytes using a httpurlconnection (POST method)
at the receiving end, I do steps 1 to 4 backwards to get my object back.
This works! However, I'm not sure what step 4, the BASE64 encoding is really doing here. Can't I just send the plain bytes in request's body? What are advantages / safety measures that I get with using the Base64 encoding/decoding?
Here's the relevant code snippet described in step 1-4 I found in this other question.
/** Read the object from Base64 string. */
private static Object fromString( String s ) throws IOException, ClassNotFoundException {
byte [] data = Base64.getDecoder().decode( s );
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( data ) );
Object o = ois.readObject();
ois.close();
return o;
}
/** Write the object to a Base64 string. */
private static String toString( Serializable o ) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream( baos );
oos.writeObject( o );
oos.close();
return Base64.getEncoder().encodeToString(baos.toByteArray());
}
}
The purpose of Base64 is to convert a byte array into a human readable (and universally compatible) format.
Because the underlying stream sends data via bytes, and there is no risk of losing data (eg printing to console a control character is not copy/pasteable), there is no point in converting the bytes to Base64. You get no benefits except for possible future compatibility if you change your network protocol to something else that suffers from being unable to transmit non-printable chars.
I was trying to serialize and deserialize a gov.nist.javax.sip.stack.SIPDialog object into Cassandra. But the equals comparison on the deserialized object fails when I compare it with the original SIPDialog object I serialized. SO looks like I am missing something here in serialisation. I am using a ByteArraySerializer to read/write the bytes into Cassandra.
//Saving Dialog
MutationBatch mutationBatch = createMutator();
byte[] dialogBytes = SIPDialogEntity.serializeDialog(dialog);
mutationBatch.withRow(SIPDIALOGS, dialogId)
.putColumn("dialog".getBytes(),dialogBytes,null);
mutationBatch.execute();
public static byte[] serializeDialog(SIPDialog dialog) throws IOException {
ByteArrayOutputStream bStream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bStream);
oos.writeObject(dialog);
oos.close();
byte[] bytes = bStream.toByteArray();
bStream.close();
return bytes;
}
//Reading Dialog
Column<byte[]> result;
result = getKeySpace().prepareQuery(SIPDIALOGS).getKey(dialogId).getColumn("dialog").execute().getResult();
sipDialog = SIPDialogEntity.deserializeDialog(result.getByteArrayValue());
public static SIPDialog deserializeDialog(byte[] byteArrayDialog) throws IOException, ClassNotFoundException {
System.out.println("DEBUG Reading Dialog Bytes:" + byteArrayDialog );
ByteArrayInputStream bStream = new ByteArrayInputStream(byteArrayDialog);
ObjectInputStream ois = new ObjectInputStream(bStream);
SIPDialog dialog = (SIPDialog) ois.readObject();
ois.close();
bStream.close();
return dialog;
}
The SIPDialog class doesn't override the equals method which is why it fails the comparison. Please open an issue in jain sip at http://java.net/jira/browse/JSIP
hmmmm, If SipDialog is your class, you could just skip all the work and use PlayOrm for cassandra ;). Then you don't need to deal with serializing/deserializing.
If it is not your class, I think I will get them to add a way to add 3rd party beans to be converted to an entity much like Guice does in a binding file so it can bind to an entity that can be saved by PlayOrm. IF you open a ticket on PlayOrm with a request, we could get the feature in probably in as little as 1 week.
I know that in J2ME I can get a byte[] object from a String object by using the getBytes() method. My question is : is it possible to get a byte[] object from any other class type ? In addition : is it possible to get a byte[] object from a user-defined class object ?
Is it possible to get a byte[] object from any other class type ?
Some classes may implement a simular service.
Is it possible to get a byte[] object from a user-defined class object ?
Not without you writing the conversion yourself.
Example how to do it yourself (just note that the DataOutputStream handles the conversion, for example which byte order that is used):
ByteArrayOutputStream out = new ByteArrayOutputStream();
{
// conversion from "yourObject" to byte[]
DataOutputStream dos = new DataOuputStream(out);
dos.writeInt(yourObject.intProperty);
dos.writeByte(yourObject.byteProperty);
dos.writeFloat(yourObject.floatProperty);
dos.writeChars(yourObject.stringProperty);
dos.close();
}
byte[] byteArray = out.toByteArray();
I'm a C++ programmer and have a need to set up some UDP communications between a java android app and the C++ server running on a PC.
I have structure that I need to receive on the PC that consists of the following:
int
int
float
Unfortunately I'm totally at a loss as to how I can do this with Java.
I need to create a DatagramPacket but the constructor only takes a byte array. Now with C++ this would be an easy cast from a struct to a char*. However casting like this is not possible with Java.
I've create a simple class that has the above fields in it. That seems to be fine. My remaining issue is how to turn that into a byte array. Can anyone help a Java noob on this front?
Cheers!
Edit: I've created a function in the class that does the following
public byte[] GetBytes() throws IOException
{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream( byteOut );
dataOut.writeInt( Integer.reverseBytes( int1) );
dataOut.writeInt( Integer.reverseBytes( int2 ) );
dataOut.writeFloat( float1 );
return byteOut.toByteArray();
}
Is there a better way to do this?
I'd rather not use the google protocol buffer mentioned in Steve's answer because, while its interesting, it would require too many changes to other platform implementations that I'd really rather not do.
You can use Google protocol buffers as a language-independent way to serialize structures for transmission and receipt. Both Java and C++ are available out of the box, and Jon Skeet has written a production-ready C# implementation.
I see a couple of examples of Protobuf in use on Android, including this.
Another, maybe simpler approach comes from Javolution.struct: http://javolution.org/target/site/apidocs/javolution/io/Struct.html
public static class Student extends Struct {
public final Enum32<Gender> gender = new Enum32<Gender>(Gender.values());
public final UTF8String name = new UTF8String(64);
public final Date birth = inner(new Date());
public final Float32[] grades = array(new Float32[10]);
public final Reference32<Student> next = new Reference32<Student>();
}
class UDPMessage extends Struct {
Student student = inner(new Student());
...
}
...
public void run() {
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
UDPMessage message = new UDPMessage();
message.setByteBuffer(ByteBuffer.wrap(bytes), 0);
// packet and message are now two different views of the same data.
while (isListening) {
multicastSocket.receive(packet);
int xxx = message.xxx.get();
... // Process message fields directly.
}
}
Quite ugly piece of code, but still prettier than dealing directly with JNI buffers or already-mentioned Google protocol buffers.