akka Serialization ByteBuffer - java.lang.UnsupportedOperationException - java

I need some help to serialize an Entity to send it by Akka Remote.
This is the serializer class:
#Override
public void toBinary(Object o, ByteBuffer buf) {
byte[] bytes = null;
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(o);
oos.flush();
bytes = bos.toByteArray();
}
catch(Exception e){
//System.out.println(e.getStackTrace());
e.printStackTrace();
}
buf.put(bytes);
}
#Override
public Object fromBinary(ByteBuffer buf, String manifest) {
Object obj = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
bis = new ByteArrayInputStream(buf.array());
ois = new ObjectInputStream(bis);
obj = ois.readObject();
}
catch(Exception e){
//System.out.println(e.getStackTrace());
e.printStackTrace();
}
return obj;
}
Im getting the following exception in line 5
java.lang.UnsupportedOperationException
at java.nio.ByteBuffer.array(ByteBuffer.java:994)
at serializers.ExampleByteBufSerializer.fromBinary(ExampleByteBufSerializer.java:67)
at akka.serialization.Serialization.deserializeByteBuffer(Serialization.scala:190)
at akka.remote.MessageSerializer$.deserializeForArtery(MessageSerializer.scala:91)
at akka.remote.artery.Deserializer$$anon$3.onPush(Codecs.scala:620)
at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:499)
at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:401)
at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:571)
at akka.stream.impl.fusing.GraphInterpreterShell$AsyncInput.execute(ActorGraphInterpreter.scala:457)
at akka.stream.impl.fusing.GraphInterpreterShell.processEvent(ActorGraphInterpreter.scala:546)
at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:725)
at akka.stream.impl.fusing.ActorGraphInterpreter$$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:740)
at akka.actor.Actor$class.aroundReceive(Actor.scala:513)
at akka.stream.impl.fusing.ActorGraphInterpreter.aroundReceive(ActorGraphInterpreter.scala:650)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:527)
at akka.actor.ActorCell.invoke(ActorCell.scala:496)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257)
at akka.dispatch.Mailbox.run(Mailbox.scala:224)
at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
This is the message Im sending to the remote actor:
public class Message2Serialize implements Serializable {
String nombre;
public Message2Serialize(String nombre) {
this.nombre = nombre;
}
public Message2Serialize() {
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
}
The weird thing is that it works in one way, if we send the message using this it works fine in the receptor:
ActorSelection selection = getContext().system().actorSelection("akka://applicationremote#localhost:25521/user/actors.MessageReceiverActor");
selection.tell(message2Serialize, getSelf());
But when we replay to the sender actor using getSender().tell(m, getSelf()); then we got the exception.
We are using Java 1.8 and akka-remote_2.11:2.5.3
Thanks in advance!
Rodri

javadoc extract
#throws UnsupportedOperationException. If this buffer is not backed by an accessible array
the ByteBuffer seems not to be completely initialized...
furthermore the javadoc also says what to do
Invoke the {#link #hasArray hasArray} method before invoking this
method in order to ensure that this buffer has an accessible backing
array.

By changing this line:
bis = newByteArrayInputStream(arr); to
byte[] arr = new byte[buf.remaining()];
buf.get(arr);
bis = new ByteArrayInputStream(arr);
It works, but Im not sure why.

Related

Strange EOFexception while do readObject() in deserialization

I am trying to process an object on the server with UDP. I serialize it, send it to the server. On the server, I deserialize, modify, then serialize back to send back to the client. On the client I get it, and when I try to readObject () I get an EOF exception. Please help, what could be the problem? I didn't find the answer anywhere.
This is client:
public class Client {
public static void main(String[] args) {
Help help = new Help("WTF");
try {
byte[] objByteArray = serialize(help);
DatagramSocket ds = new DatagramSocket();
InetAddress host = InetAddress.getLocalHost();
int port = 6789;
int objLength = objByteArray.length;
DatagramPacket dp = new DatagramPacket(objByteArray, objLength, host, port);
ds.send(dp);
dp = new DatagramPacket(objByteArray, objLength);
ds.receive(dp);
byte[] new_arr = objByteArray;
Help deserializedObj = (Help) deserialize(objByteArray);
System.out.println(deserializedObj.getData());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SocketException e) {
throw new RuntimeException(e);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
}
}
public static byte[] serialize(Object obj) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)){
oos.writeObject(obj);
byte[] objByteArray = baos.toByteArray();
return objByteArray;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static Object deserialize(byte[] arr) throws IOException, ClassNotFoundException {
Object result = null;
try (ByteArrayInputStream bais = new ByteArrayInputStream(arr);
ObjectInputStream ois = new ObjectInputStream(bais)){
result = ois.readObject();
}
catch (IOException e){
}
return result;
}
}
And this is Server:
public class Server {
public static void main(String[] args) throws IOException {
String filepath = System.getProperty("user.dir") + "\\src\\Server\\Data\\Collection.json";
CollectionManager.setFilePath(filepath);
byte[] arr = new byte[100000];
DatagramSocket ds = new DatagramSocket(6789);
DatagramPacket dp = new DatagramPacket(arr, arr.length);
ds.receive(dp);
try {
Help deserializedObj = (Help) deserialize(arr);
deserializedObj.setData("Server finished work!");
System.out.println("Done!");
byte[] serializedObj = serialize(deserializedObj);
InetAddress host = dp.getAddress();
int port = dp.getPort();
dp = new DatagramPacket(serializedObj, serializedObj.length, host, port);
ds.send(dp);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public static byte[] serialize(Object obj) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)){
oos.writeObject(obj);
byte[] objByteArray = baos.toByteArray();
return objByteArray;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static Object deserialize(byte[] arr) throws IOException, ClassNotFoundException {
Object result = null;
try (ByteArrayInputStream bais = new ByteArrayInputStream(arr);
ObjectInputStream ois = new ObjectInputStream(bais)){
result = ois.readObject();
}
catch (IOException e){
}
return result;
}
}
And also the classes:
public class Help extends Command implements Serializable {
public Help(String name){
super.setName(name);
}
private String data;
public void setData(String s){
data = s;
}
public String getData(){
return data;
}
#Override
public void execute() {
}
}
The problem was that the packet sent from the server is larger than the original one, therefore, on the client, we must receive data into the buffer with a margin, and from there try to read the data.
This is an edited Client code:
byte[] buffer = new byte[1024];
dp = new DatagramPacket(buffer, buffer.length);
ds.receive(dp);

Why my DatagramChannel socket can't read my custom object?

I'm developing a real time application in Java with communication between one server and one client with UDP socket.
It worked fine when i send and receive string but when i tried to receive a custom class Message. i got this error :java.io.StreamCorruptedException: invalid stream header: 00000000
at line message = (Message) objectInputStream.readObject(); in the "receiveMessage" function
I don't know why i have this error.
My Message class:
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
private TypeMessage typeMessage;
private int seedMap;
public Message(TypeMessage typeMessage) {
this.typeMessage = typeMessage;
}
public TypeMessage getTypeMessage() {
return typeMessage;
}
public void setTypeMessage(TypeMessage typeMessage) {
this.typeMessage = typeMessage;
}
public int getSeedMap() {
return seedMap;
}
public void setSeedMap(int seedMap) {
this.seedMap = seedMap;
}
My send function used by the client and the server:
public final static void sendMessage(Message message, DatagramChannel socketSender, InetSocketAddress addressRecever) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos;
oos = new ObjectOutputStream(baos);
oos.writeObject(message);
oos.flush();
byte[] data = baos.toByteArray();
ByteBuffer bufferSocket = ByteBuffer.allocate(SIZE_BUFFER);
bufferSocket.put(data);
socketSender.send(bufferSocket, addressRecever);
} catch (Exception e) {
System.out.println(e);
}
}
My receive function used by the server and the client:
public final static Message receiveMessage(DatagramChannel socketRecever, SocketAddress socketSender) {
Message message = null;
try {
ByteBuffer bufferSocket = ByteBuffer.allocate(SIZE_BUFFER);
bufferSocket.clear();
socketSender = socketRecever.receive(bufferSocket);
if(socketSender != null) {
bufferSocket.flip();
byte[] bytes = new byte[bufferSocket.limit()];
bufferSocket.get(bytes);
ByteArrayInputStream bytesStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(bytesStream);
message = (Message) objectInputStream.readObject();
}
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
return message;
}
Thanks in advance for help

How to write serializable object to String without writing to file?

I want to write a class object to the string and then again create an object from it.
I searched on the net but all I found is to write an object to file however I want to write in the string, not on file.
Below is the example of writing to file similarly I want to write in String or similar Object and not in the file.
some_class implements serializable {
...
}
FileOutputStream f = new FileOutputStream(new File("myObjects.txt"));
ObjectOutputStream o = new ObjectOutputStream(f);
// Write objects to file
o.writeObject(object1);
o.close();
f.close();
FileInputStream fi = new FileInputStream(new File("myObjects.txt"));
ObjectInputStream oi = new ObjectInputStream(fi);
// Read objects
some_class object2 = (some_class) oi.readObject();
oi.close();
fi.close();
Please help with the same.
This would be one way:
try
{
// To String
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(object1);
String serializedObject1 = bos.toString();
os.close();
// To Object
ByteArrayInputStream bis = new ByteArrayInputStream(serializedObject1.getBytes());
ObjectInputStream oInputStream = new ObjectInputStream(bis);
YourObject restoredObject1 = (YourObject) oInputStream.readObject();
oInputStream.close();
} catch(Exception ex) {
ex.printStackTrace();
}
I would prefer the Base64 way though.
This would be an example of encoding:
private static String serializableToString( Serializable o ) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
return Base64.getEncoder().encodeToString(baos.toByteArray());
}
And this is an example of decoding:
private static Object objectFromString(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;
}
the best way to serialize an object to String and vice versa you should convert the object into JSON String and encode into base64. and to get object decode base64 and convert to object using GSON (opensource google provide java library)
class foo{ String name, email;
//setter getter
}
convert Object to base64 JSON
public static String convertToJson(Object o){
String result=new Gson().toJson(o);
return Base64.getEncoder().encodeToString(result);
}
//read base64
public static <T> T convertJsonToObject(String base64Object,Class<T> classOfT){
Gson gson = new Gson();
return gson.fromJson(new InputStreamReader(new ByteArrayInputStream(Base64.getDecoder().decode(base64Object))),classOfT);
}
public static void main(String[] args) {
foo obj=new foo("jhon","jhon#gamil.com");
String json=convertToJson(foo);
System.out.println(json);
foo obj_fromJson=convertJsonToObject(json,foo.class);
System.out.println(obj_fromJson.getName());
}

Java - How to do Gzip compression of java object

How to compress a Java pojo object using Gzip?
Below code compress a string -
public static String compress(String str, String inEncoding) {
if (str == null || str.length() == 0) {
return str;
}
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(out);
gzip.write(str.getBytes(inEncoding));
gzip.close();
return URLEncoder.encode(out.toString("ISO-8859-1"), "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Instead of String str as a parameter, how to use below pojo class object (Client cc) and compress?
Pojo class -
Class client {
Public string name;
Public string location;
//Getter and setter methods
}
How can i compress and decompress this client pojo class using gzip.?
You can compress your Client class which implements serializable using gzip by doing the following :
public static bytes[] compressThis(Client client){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(client);
ObjectOutputStream objectOut = new ObjectOutputStream(gzipOut);
objectOut.writeObject(client);
objectOut.close();
return baos.toByteArray();
}
Following which you can decompress it by doing the following :
public static getClientFrom(bytes[] bytes){
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
GZIPInputStream gzipIn = new GZIPInputStream(bais);
ObjectInputStream objectIn = new ObjectInputStream(gzipIn);
Client client = (Client) objectIn.readObject();
objectIn.close();
return client;
}

Java Serializable Object to Byte Array

Let's say I have a serializable class AppMessage.
I would like to transmit it as byte[] over sockets to another machine where it is rebuilt from the bytes received.
How could I achieve this?
Prepare the byte array to send:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(yourObject);
out.flush();
byte[] yourBytes = bos.toByteArray();
...
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
Create an object from a byte array:
ByteArrayInputStream bis = new ByteArrayInputStream(yourBytes);
ObjectInput in = null;
try {
in = new ObjectInputStream(bis);
Object o = in.readObject();
...
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
// ignore close exception
}
}
The best way to do it is to use SerializationUtils from Apache Commons Lang.
To serialize:
byte[] data = SerializationUtils.serialize(yourObject);
To deserialize:
YourObject yourObject = SerializationUtils.deserialize(data)
As mentioned, this requires Commons Lang library. It can be imported using Gradle:
compile 'org.apache.commons:commons-lang3:3.5'
Maven:
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
Jar file
And more ways mentioned here
Alternatively, the whole collection can be imported. Refer this link
If you use Java >= 7, you could improve the accepted solution using try with resources:
private byte[] convertToBytes(Object object) throws IOException {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos)) {
out.writeObject(object);
return bos.toByteArray();
}
}
And the other way around:
private Object convertFromBytes(byte[] bytes) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream in = new ObjectInputStream(bis)) {
return in.readObject();
}
}
Can be done by SerializationUtils, by serialize & deserialize method by ApacheUtils to convert object to byte[] and vice-versa , as stated in #uris answer.
To convert an object to byte[] by serializing:
byte[] data = SerializationUtils.serialize(object);
To convert byte[] to object by deserializing::
Object object = (Object) SerializationUtils.deserialize(byte[] data)
Click on the link to Download org-apache-commons-lang.jar
Integrate .jar file by clicking:
FileName -> Open Medule Settings -> Select your module -> Dependencies -> Add Jar file and you are done.
Hope this helps.
I also recommend to use SerializationUtils tool. I want to make a ajust on a wrong comment by #Abilash. The SerializationUtils.serialize() method is not restricted to 1024 bytes, contrary to another answer here.
public static byte[] serialize(Object object) {
if (object == null) {
return null;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.flush();
}
catch (IOException ex) {
throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex);
}
return baos.toByteArray();
}
At first sight, you may think that new ByteArrayOutputStream(1024) will only allow a fixed size. But if you take a close look at the ByteArrayOutputStream, you will figure out the the stream will grow if necessary:
This class implements an output stream in which the data is
written into a byte array. The buffer automatically grows as data
is written to it.
The data can be retrieved using toByteArray() and
toString().
Another interesting method is from com.fasterxml.jackson.databind.ObjectMapper
byte[] data = new ObjectMapper().writeValueAsBytes(JAVA_OBJECT_HERE)
Maven Dependency
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
If you are using spring, there's a util class available in spring-core. You can simply do
import org.springframework.util.SerializationUtils;
byte[] bytes = SerializationUtils.serialize(anyObject);
Object object = SerializationUtils.deserialize(bytes);
I would like to transmit it as byte[] over sockets to another machine
// When you connect
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
// When you want to send it
oos.writeObject(appMessage);
where it is rebuilt from the bytes received.
// When you connect
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
// When you want to receive it
AppMessage appMessage = (AppMessage)ois.readObject();
Spring Framework org.springframework.util.SerializationUtils
byte[] data = SerializationUtils.serialize(obj);
In case you want a nice no dependencies copy-paste solution. Grab the code below.
Example
MyObject myObject = ...
byte[] bytes = SerializeUtils.serialize(myObject);
myObject = SerializeUtils.deserialize(bytes);
Source
import java.io.*;
public class SerializeUtils {
public static byte[] serialize(Serializable value) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try(ObjectOutputStream outputStream = new ObjectOutputStream(out)) {
outputStream.writeObject(value);
}
return out.toByteArray();
}
public static <T extends Serializable> T deserialize(byte[] data) throws IOException, ClassNotFoundException {
try(ByteArrayInputStream bis = new ByteArrayInputStream(data)) {
//noinspection unchecked
return (T) new ObjectInputStream(bis).readObject();
}
}
}
This is just an optimized code form of the accepted answer in case anyone wants to use this in production :
public static void byteArrayOps() throws IOException, ClassNotFoundException{
String str="123";
byte[] yourBytes = null;
// Convert to byte[]
try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);) {
out.writeObject(str);
out.flush();
yourBytes = bos.toByteArray();
} finally {
}
// convert back to Object
try(ByteArrayInputStream bis = new ByteArrayInputStream(yourBytes);
ObjectInput in = new ObjectInputStream(bis);) {
Object o = in.readObject();
} finally {
}
}
code example with java 8+:
public class Person implements Serializable {
private String lastName;
private String firstName;
public Person() {
}
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Override
public String toString() {
return "firstName: " + firstName + ", lastName: " + lastName;
}
}
public interface PersonMarshaller {
default Person fromStream(InputStream inputStream) {
try (ObjectInputStream objectInputStream = new ObjectInputStream(inputStream)) {
Person person= (Person) objectInputStream.readObject();
return person;
} catch (IOException | ClassNotFoundException e) {
System.err.println(e.getMessage());
return null;
}
}
default OutputStream toStream(Person person) {
try (OutputStream outputStream = new ByteArrayOutputStream()) {
ObjectOutput objectOutput = new ObjectOutputStream(outputStream);
objectOutput.writeObject(person);
objectOutput.flush();
return outputStream;
} catch (IOException e) {
System.err.println(e.getMessage());
return null;
}
}
}

Categories