Serialization and deserialization

Hi!

I’m new to processing, so please be patient and gentle :wink: I’ve installed the latest version (3.4) and I’m running Windows 10(x64)

I’m quite advanced in programming Arduino Microcontroller and usually I use a combination of union and struct to send and receive structured binary data through the serial port.

Example structure on Arduino side:

struct Infos1 {
  int32_t P1;
  float intens;
  int32_t S1;
  float S1Max;
};

union ToInfos {
 byte ar1[sizeof(Infos1)];
 //uint32_t integer;
 Infos1 c;
};

ToInfos MainInfos;

So later on I can do a simple

Serial.write(MainInfos.ar1, sizeof(MainInfos));

to send data from arduino to the pc.

Now I’ve learned that in Processing there’s no “STRUCT” but I can use “CLASS” to manage structured data.
But something like “UNION” doesn’t even exist so I tried to get into Serial/Deserialization of objects.

So at first I’ve searched for an tutorial for Serial/Deserialization. I’ve found a nice example to save object data into a file which I modified for Processing syntax:

https://www.codementor.io/java/tutorial/serialization-and-deserialization-in-java

import java.io.Serializable;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

class DataValueObject implements Serializable{

  private static final long serialVersionUID = 1L;
  private String customer;
  private String business;
  transient private String contractID;
  transient private String passKeys;
  
  public String getCustomer() {
    return customer;
  }
  public void setCustomer(String customer) {
    this.customer = customer;
  }
  public String getBusiness() {
    return business;
  }
  public void setBusiness(String business) {
    this.business = business;
  }
  public String getContractID() {
    return contractID;
  }
  public void setContractID(String contractID) {
    this.contractID = contractID;
  }
  public String getPassKeys() {
    return passKeys;
  }
  public void setPassKeys(String passKeys) {
    this.passKeys = passKeys;
  }
  @Override
    public String toString() {
        String value = "customer : " + customer + "\nbusiness : " + business + "\ncontractID : " + contractID
                + "\npassKeys : " + passKeys;
        return value;
    }
}


class SerializationDemo {
  /**
   * This method is used to read data from file for deSerialization.
   * 
   * @param file
   * @return
   * @throws IOException
   * @throws ClassNotFoundException
   */
  public Object deSerialization(String file) throws IOException, ClassNotFoundException {
    FileInputStream fileInputStream = new FileInputStream(file);
    BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
    ObjectInputStream objectInputStream = new ObjectInputStream(bufferedInputStream);
    Object object = objectInputStream.readObject();
    objectInputStream.close();
    return object;
  }

  /**
   * This method is used to write data to file for Serialization.
   * 
   * @param file
   * @param object
   * @throws IOException
   */
  public void serialization(String file, Object object) throws IOException {
    FileOutputStream fileOutputStream = new FileOutputStream(file);
    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(bufferedOutputStream);
    objectOutputStream.writeObject(object);
    objectOutputStream.close();
  }
}

    DataValueObject dataValueObject = new DataValueObject();
    dataValueObject.setCustomer("Debbie");
    dataValueObject.setBusiness("JAVA Concepts");
    dataValueObject.setContractID("ZZZZZZ");
    dataValueObject.setPassKeys("!@wer#$");
    SerializationDemo s1 = new SerializationDemo();
    try {
      s1.serialization("x:/fileToSave.txt", dataValueObject);
      DataValueObject object = (DataValueObject) s1.deSerialization("fileToSave.txt");
      System.out.println(object.toString());
    } catch (IOException exp) {
      exp.printStackTrace();
    } catch (ClassNotFoundException exp) {
      exp.printStackTrace();
    }
  

But when I try to run the sketch the following exception appears:

java.io.NotSerializableException: sketch_181226d
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at sketch_181226d$1SerializationDemo.serialization(sketch_181226d.java:105)
	at sketch_181226d.setup(sketch_181226d.java:117)
	at processing.core.PApplet.handleDraw(PApplet.java:2404)
	at processing.awt.PSurfaceAWT$12.callDraw(PSurfaceAWT.java:1557)
	at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:313)

What am I doing wrong? Is serial/deserialization the right/only way to send/receive binary structured data?

Thank you very much!

Kind regards,

Chris

Your example seems correct and works as expected in my working environment.

I suggest you to double check which object you are trying to serialize. Do you use right class that implements java.io.Serializable interface? Do you have properties in your class that don’t implement Serializable interface?

Probably it would be helpful if you can provide full sketch you are trying to run.

P.S. If you need to serialize your POJOs (data objects) and to transfer them to non-java application (e.g. Arduino) - I suggest you to use Externalizable interface instead (example). It gives you better control on serialization/deserialization process. Another option is to use existing library like kryo.

Hi dector,
thank you for your answer! I don’t have any other full sketch. I’m trying to learn how to use the serial/deserialize function. In my example I was trying to serialize “dataValueObject”. But the code dumps the message I’ve postet (“java.io.NotSerializableException…”). So my example doesn’t work in my environment.
The code just creates an empty file (0 bytes).
Also thanks for your suggested alternatives! I’ll have a look at these!

I’m sorry for this noob question… How do I install libraries like kryo in Processing 3.4?
I only know how to install additional libraries by using the built in Contribution Manager.

There are two ways to import java libraries into Processing environment. They are described here.

Many libraries you can find on github have this “Installation” section. This one on kryo’s page, for example.

For this particular case you can do it like this:

  • Download latest release: [at the time of this post] choose between kryo-4.0.2 and kryo-5.0.0-RC1. You need only one. Beware, they are not compatible. I think that for education purposes you should use version 4.0.2 as I expect that it’s easier to find tutorials for it. Unzip it. You need kryo-<version>.jar file.
  • Download dependencies for kryo here. You need all jar files from this page.
  • Open Processing, create new sketch and drag-n-drop all downloaded jar files to Processing IDE.
  • Now you can use installed library in this sketch.

Okay, I’ve found solution but don’t know the reason (need to dig deeper for it). But I thinks it’s about the way Processing compiles java classes.

Anyway, in this case you need to extract your class into separate file (DataValueObject.java). Create new file by clicking on that triangle on the right and then choose New Tab option. Enter file name: DataValueObject.java.

Ok, I tried and I failed xD … I can manage to add libraries to Arduino IDE and Atom Plattform.io. But adding java libraries seems too difficult for me. I don’t know where to put a file which I don’t know where to download. When I try to download a kryo-5.0.0.RC1 ZIP file Chrome tells me there’s a virus in it.
I’m really sorry for beeing that noob :frowning:

Thank you very much! The save function works for me too now with this workaround. But deSerialization still fails with this exception:

java.io.EOFException
	at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2681)
	at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3156)
	at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:862)
	at java.io.ObjectInputStream.<init>(ObjectInputStream.java:358)
	at SerializationDemo.deSerialization(DataValueObject.java:63)
	at sketch_181226a.setup(sketch_181226a.java:25)
	at processing.core.PApplet.handleDraw(PApplet.java:2404)
	at processing.awt.PSurfaceAWT$12.callDraw(PSurfaceAWT.java:1557)
	at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:313)

Now, when I open fileToSave.txt it doesn’t look like I can send this binary data through serial into a STRUCT in an Arduino.
I was expecting a simple flat structure of the data which is defined in the class. Is there really no easy way to do this?

My current sketch:

    DataValueObject dataValueObject = new DataValueObject();
    dataValueObject.setCustomer("Debbie");
    dataValueObject.setBusiness("JAVA Concepts");
    dataValueObject.setContractID("ZZZZZZ");
    dataValueObject.setPassKeys("!@wer#$");
    SerializationDemo s1 = new SerializationDemo();
    try {
      s1.serialization("x:/fileToSave.txt", dataValueObject);
      DataValueObject object = (DataValueObject) s1.deSerialization("fileToSave.txt");
      System.out.println(object.toString());
    } catch (IOException exp) {
      exp.printStackTrace();
    } catch (ClassNotFoundException exp) {
      exp.printStackTrace();
    }

And DataValueObject.java tab:

import java.io.Serializable;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

class DataValueObject implements Serializable{

  private static final long serialVersionUID = 1L;
  private String customer;
  private String business;
  transient private String contractID;
  transient private String passKeys;
  
  public String getCustomer() {
    return customer;
  }
  public void setCustomer(String customer) {
    this.customer = customer;
  }
  public String getBusiness() {
    return business;
  }
  public void setBusiness(String business) {
    this.business = business;
  }
  public String getContractID() {
    return contractID;
  }
  public void setContractID(String contractID) {
    this.contractID = contractID;
  }
  public String getPassKeys() {
    return passKeys;
  }
  public void setPassKeys(String passKeys) {
    this.passKeys = passKeys;
  }
  @Override
    public String toString() {
        String value = "customer : " + customer + "\nbusiness : " + business + "\ncontractID : " + contractID
                + "\npassKeys : " + passKeys;
        return value;
    }
}


class SerializationDemo {
  /**
   * This method is used to read data from file for deSerialization.
   * 
   * @param file
   * @return
   * @throws IOException
   * @throws ClassNotFoundException
   */
  public Object deSerialization(String file) throws IOException, ClassNotFoundException {
    FileInputStream fileInputStream = new FileInputStream(file);
    BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
    ObjectInputStream objectInputStream = new ObjectInputStream(bufferedInputStream);
    Object object = objectInputStream.readObject();
    objectInputStream.close();
    return object;
  }

  /**
   * This method is used to write data to file for Serialization.
   * 
   * @param file
   * @param object
   * @throws IOException
   */
  public void serialization(String file, Object object) throws IOException {
    FileOutputStream fileOutputStream = new FileOutputStream(file);
    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(bufferedOutputStream);
    objectOutputStream.writeObject(object);
    objectOutputStream.close();
  }
}

Chrome tells me there’s a virus in it.

I think something like Windows Defender is responsible for this notification. And it’s false-positive.
As always, you can check files you are downloading on virustotal.

But deSerialization still fails with this exception:

Because you use different files in serialization and deSerialization methods and it’s trying to read empty file.

s1.serialization("x:/fileToSave.txt", dataValueObject);
DataValueObject object = (DataValueObject) s1.deSerialization("fileToSave.txt")

I was expecting a simple flat structure of the data which is defined in the class. Is there really no easy way to do this?

You need to use libraries (e.g. kryo) or convert your data to bytes manually. Take a look at this example.

OMG I’m so sorry I feel so dumb! Thank you, I was searching for this error the whole time !

Also thank you for your example. But this is exactly not the thing I wanted to do. In your example you’re reading and writing each element of the class hardcoded in the class Import.readFrom / Export.writeTo.

I’m searching for a generic way to store and restore all values in a structured datatype.
Currently I’m trying to do these thing with ByteBuffer but I’m always ending also in hardcoding each element by element and it’s byte size. Which is quite anyoing and stupid work compared to C.

Today I was trying to learn more about java especially how it handles datatypes and their sizes.
In C you have a simple sizeof() function which tells you about the size of nearly everything in bytes. But even this is quite difficult in java so I wrote a function which gives me the size of basic datatypes (string, integer,byte, boolean …).

Could there be a way to access all elements of an object in a object-array style? So I could iterate through all elements and read and write all values from the ByteBuffer by recognizing their classname and bytesize.

I suppose that something close is FieldSerializer in kryo.

class DataClass {
    // ...
}
FieldSerializer.FieldSerializerConfig config = new FieldSerializer.FieldSerializerConfig();
FieldSerializer serializer = new FieldSerializer(kryo, Obj.class, config);

Kryo kryo = new Kryo();
kryo.register(DataClass.class, serializer);

FileOutputStream fout = new FileOutputStream("out.dat");
Output output = new Output(fout);

kryo.writeObject(output, data);

output.close();
fout.close();

Or you can use Java reflection to write your own unified serialization mechanism.

DataClass data = new DataClass();

Field[] fields = data.class.getDeclaredFields();
for (Field field : fields) {
    System.out.println(field.getType() + " " + field.get(data));
}

reflection looks pretty interesting!!
But it seems I’ve got no class “Field”. What do I have to import to get this class?

Your code snippet does not work in my environment … this is what works for me but I got stuck:
( field.getType() and field.get(data) does not work )

class DataClass {
    int x;
    int y;
    String title="hello world!";
}

DataClass data = new DataClass();

Object[] fields = data.getClass().getDeclaredFields();
for (Object field : fields) {
    System.out.println(field.toString());
}

But it seems I’ve got no class “Field”. What do I have to import to get this class?

Yup. In API you can always find package for class.

Your code snippet does not work in my environment

Sorry, my bad. If you are getting class from instance - you should use data.getClass(). If you are using class - then use static field in it DataClass.class.

Another one thing. If you declare classes in you sketch file (*.pde) - they will have reference to your sketch instance. I suppose you don’t need it. Just create new tab as .java file.

Here it is:

sketch.pde:

import java.lang.reflect.Field;

DataClass data = new DataClass();
data.x = 100;
data.y = 500;

Field[] fields = data.getClass().getDeclaredFields();
// or DataClass.class.getDeclaredFields();

try {
  for (Field field : fields) {
      System.out.println(field.getType() + " " + field.getName() + " = " + field.get(data));
  }
} catch (IllegalAccessException e) {
  e.printStackTrace();
}

DataClass.java:

public class DataClass {
    int x;
    int y;
    String title="hello world!";
}

Checkout documentation for Reflection if you decided to go this way. It’s good as exercise but to get things done I suggest you to implement Externalizable. :slight_smile:

1 Like

Damn, that works like a charm :wink: Thank you very much!
I’ll post my work as soon as it’s usable !

Good luck. :slight_smile:

Ok I’ve got some very basic stuff ready.

The first thing I’ve noticed is the high latency time. I haven’t measured it exactly but it seems like nearly 1 second latency from receiving in processing and receiving the data again on the device. This does not happen in other programming languages…

@dector could you please have a look if there is an easy way to get rid of this latency?

sketch:

import processing.serial.*;

test1 data = new test1();  //new testing object

void setup() {  //take the first serial device you'll find
  String portName = Serial.list()[0];
  data.SerialPort = new Serial(this, portName, 921600); //highest speed I've tested is 921600 - usually I work with 115200
}
void draw() {

  if( data.ReceiveData() ) {  //have a look if new data is available
    println("X_ORIG=" + data.x);   //Show the new data which came up from the device
    println("Y_ORIG=" + data.y);
    data.x = data.x / 2;           //make some new calculations on the new data and send it back to the device
    data.y = data.x / 3;
    println("X_CALC=" + data.x);   //show the calculated values
    println("Y_CALC=" + data.y);
    data.SendData();               //send it back
  }

}

SerialTransmission.java:

import java.lang.reflect.Field;
import processing.serial.*;
import java.nio.*;

public class SerialTransmission {
  private int objectsize = -1;    //Object size will be calculated at first send/receive
  private Field[] fields;         //All fields of the current class will be listet here
  private byte values[];          //Values of all fields for send/receive
  private ByteBuffer bb;          //byteBuffer object to collect and reconstruct data
  public Serial SerialPort;       //the current serial port
  
  public void SendData() {        //Sends the current object fields
    if ( objectsize == -1 ) {     //If object size isn't calculated
      GetObjectSize();
    }
    
    values = new byte[objectsize];      //Prepair some space for the serial data array
    bb = ByteBuffer.wrap(values);       //Prepair the byteBuffer with the serial data array
    bb.order(ByteOrder.LITTLE_ENDIAN);  //For Arduino it's neccessary to set order of bits to little endian
    try {
      for (Field field : fields) {      //loop through all fields and put together all values with their corresponding primitive data classes
        if (field.getType() == int.class) { bb.putInt((int) field.get(this)); }
        if (field.getType() == boolean.class) {  bb.put((byte) field.get(this)); }
        if (field.getType() == byte.class) { bb.put((byte)field.get(this)); }
        if (field.getType() == char.class) { bb.putChar((char)field.get(this)); }
        if (field.getType() == short.class) { bb.putShort((short)field.get(this)); }
        if (field.getType() == long.class) { bb.putLong((long)field.get(this)); }
        if (field.getType() == float.class) { bb.putFloat((float)field.get(this)); }
        if (field.getType() == double.class) { bb.putDouble((double)field.get(this)); }
        //System.out.println(field.getType() + " " + field.getName() + " = " + field.get(this)); //debug purpose
      }
      SerialPort.write(values);  //Send the serial data array 
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    }      
  }

  public boolean ReceiveData() {  //Receive serial data - if true new data has been arrived
    if ( objectsize == -1 ) {     //If object size isn't calculated
      GetObjectSize();
    }
    if ( SerialPort.available() >= objectsize) {  //if the amount of neccessary bytes is reached / otherwise return false no data update
      values = SerialPort.readBytes(objectsize);  //read the serial data array with the amount of objectsize bytes
      bb = ByteBuffer.wrap(values);               //Prepair the byteBuffer with the serial data array
      bb.order(ByteOrder.LITTLE_ENDIAN);          //For Arduino it's neccessary to set order of bits to little endian
      
      try {
        for (Field field : fields) {              //loop through all fields and get all values from the serial data array into the corresponding data classes
          if (field.getType() == int.class) { field.setInt(this, bb.getInt()); }
          if (field.getType() == boolean.class) {   field.setByte(this, bb.get()); }
          if (field.getType() == byte.class) {  field.setByte(this, bb.get()); }
          if (field.getType() == char.class) {  field.setChar(this, bb.getChar()); }
          if (field.getType() == short.class) {  field.setShort(this, bb.getShort()); }
          if (field.getType() == long.class) {  field.setLong(this, bb.getLong()); }
          if (field.getType() == float.class) {  field.setFloat(this, bb.getFloat()); }
          if (field.getType() == double.class) {  field.setDouble(this, bb.getDouble()); }
        //System.out.println(field.getType() + " " + field.getName() + " = " + field.get(this)); //debug purpose
        }
        return true;
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }      
    };
    return false;  //no new data available - no update
  }

  private void GetObjectSize() {    //Calculate the object size and get the fields of the current object with
    fields = this.getClass().getDeclaredFields();
    objectsize = 0;
    for (Field field : fields) {
      if (field.getType() == int.class) { objectsize += 4; }      //source https://cs.fit.edu/~ryan/java/language/java-data.html
      if (field.getType() == boolean.class) { objectsize += 1; }  //an easier way would be fine!
      if (field.getType() == byte.class) { objectsize += 1; }
      if (field.getType() == char.class) { objectsize += 2; }
      if (field.getType() == short.class) { objectsize += 2; }
      if (field.getType() == long.class) { objectsize += 8; }
      if (field.getType() == float.class) { objectsize += 4; }
      if (field.getType() == double.class) { objectsize += 8; }
    }
  }
}

test1.java:

public class test1 extends SerialTransmission {    //An test of the serial transmission
  public int x;
  public int y;
}

Try to measure time (with millis() for example) for all crucial parts of process.

Also you are receiving data in draw() method. I would rather move I/O (Input/Output) functionality into Thread that is started in setup().

Another room for improvement is to get rid of reflection and serialize objects manually (e.g. via Externalizable interface). Reflection may be quite slow (you can measure it as well :slight_smile: ).

But I see some possible improvements for your code as well. Let’s look:

a)

bb = ByteBuffer.wrap(values);

If you are receiving same data structure - create buffer once and reuse it.

b)

if (field.getType() == int.class) { bb.putInt((int) field.get(this)); }
if (field.getType() == double.class) { bb.putDouble((double)field.get(this)); }

Here you can use if - else if instead of many if branches. Because only one of them will be true.

Call getType() once (no need to get field type value in every branch):

for (Field field : fields) {
    Class type = field.getType();
    Object value = field.get(this); 
    
    if (type == int.class) { bb.putInt((int) value); }
    else if (type == boolean.class) {  bb.put((byte) value); }
    // ...
}

c) I suggest you to split data object and I/O implementation but with your current implementation you can just count object size once (on first GetObjectSize() call), stored this value and then return it. There is no need to perform such heavy operation every time.

d) As an exercise. Try to serialize object without reflection and compare time for both solutions. :slight_smile:

Hi @dector
first of all thank you very much for your guidance and support and I wish you a happy new year :wink:

I found several reasons for this high latency also some of them you’ve mentioned.

  1. the serial buffer grows endless - so I put an SerialPort.clear() command into the receive routine. (~700ms -> ~100ms)
  2. draw() is called 60 times per second by default - this is also an influence to the latency can be avoided by creating a thread or rising the framerate. (Creating a thread reduced latency from ~100ms -> ~85ms)
  3. the new initialization of the byteBuffer object can’t be avoided completely but can be reduced. (see my new code bewow (~85ms -> ~80ms))
  4. My arduino wasn’t answering quickly enough because I used a graphical display (SSD1306) to show the transfered values. If I switch off the display in the arduino code the latency finally dropped from ~80ms -> ~0-~1ms.

to your improvement advices:

I don’t know how to use" Externalizable interface" … could you give me an simple example?

to b) how does else if improve performance? how would you write the code with else if ? I was trying to use switch but it doesn’t work… it says
“Cannot switch on value of type Class<capture#1-of ?>, Only convertible int values, strings or enum variables are permitted”

to c) I don’t call GetObjectSize() every time. GetObjectSize() is just called once if objectsize is -1.

do d) that was very helpfull! I wrote a simple sketch which sends all received data directly back to the device. So I could figure out the latency caused by the OLED display.

All in all I’m already very happy with this code. But the only thing which still annoys me are the missed bytes which are removed my SerialPort.clear(). (some times 56-64 bytes are available) May you have some ideas about it?

sketch:

import processing.serial.*;

test1 data = new test1();  //new testing object

void setup() {  //take the first serial device you'll find
  String portName = Serial.list()[0];
  data.SerialPort = new Serial(this, portName, 115200); //highest speed I've tested is 921600 - usually I work with 115200
  thread("serialthread"); 
}

void serialthread() {

  float t1 = 0;
  float t2 = 0;
  while ( true ) {
    if( data.ReceiveData() ) {  //have a look if new data is available
      data.x = data.x;           //make some new calculations on the new data and send it back to the device
      data.y = data.x;
      data.SendData();               //send it back
      t2 = millis() - t1;
      println("data.x    = " + data.x );
      println("data.y    = " + data.y );
      println("latency   = " + t2 + " ms");
      t1 = millis();
    }
    if ( data.SerialPort.available() > 0) {
      println("available = " + data.SerialPort.available() + " bytes");
    }
  }
  
}

SerialTransmission.java

import java.lang.reflect.Field;
import processing.serial.*;
import java.nio.*;


public class SerialTransmission {
  private int objectsize = -1;    //Object size will be calculated at first send/receive
  private Field[] fields;         //All fields of the current class will be listet here
  private byte values[];          //Values of all fields for send/receive
  private ByteBuffer bb;          //byteBuffer object to collect and reconstruct data
  public Serial SerialPort;       //the current serial port
  
  public void SendData() {        //Sends the current object fields
    if ( objectsize == -1 ) {     //If object size isn't calculated
      GetObjectSize();
    }
    try {
      for (Field field : fields) {      //loop through all fields and put together all values with their corresponding primitive data classes
        Object GetField = field.get(this);
        if (field.getType() == int.class) { bb.putInt((int) GetField); }
        if (field.getType() == boolean.class) {  bb.put((byte) GetField); }
        if (field.getType() == byte.class) { bb.put((byte) GetField); }
        if (field.getType() == char.class) { bb.putChar((char) GetField); }
        if (field.getType() == short.class) { bb.putShort((short) GetField); }
        if (field.getType() == long.class) { bb.putLong((long) GetField); }
        if (field.getType() == float.class) { bb.putFloat((float) GetField); }
        if (field.getType() == double.class) { bb.putDouble((double) GetField); }
        //System.out.println(field.getType() + " " + field.getName() + " = " + field.get(this)); //debug purpose
      }
      bb.flip();
      SerialPort.write(values);  //Send the serial data array 
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    }      
  }

  public boolean ReceiveData() {  //Receive serial data - if true new data has been arrived
    if ( objectsize == -1 ) {     //If object size isn't calculated
      GetObjectSize();
    }
    if ( SerialPort.available() >= objectsize) {  //if the amount of neccessary bytes is reached / otherwise return false no data update
      values = SerialPort.readBytes(objectsize);  //read the serial data array with the amount of objectsize bytes
      bb = ByteBuffer.wrap(values);
      bb.order(ByteOrder.LITTLE_ENDIAN);
      try {
        for (Field field : fields) {              //loop through all fields and get all values from the serial data array into the corresponding data classes
          if (field.getType() == int.class) { field.setInt(this, bb.getInt()); }
          if (field.getType() == boolean.class) {   field.setByte(this, bb.get()); }
          if (field.getType() == byte.class) {  field.setByte(this, bb.get()); }
          if (field.getType() == char.class) {  field.setChar(this, bb.getChar()); }
          if (field.getType() == short.class) {  field.setShort(this, bb.getShort()); }
          if (field.getType() == long.class) {  field.setLong(this, bb.getLong()); }
          if (field.getType() == float.class) {  field.setFloat(this, bb.getFloat()); }
          if (field.getType() == double.class) {  field.setDouble(this, bb.getDouble()); }
        //System.out.println(field.getType() + " " + field.getName() + " = " + field.get(this)); //debug purpose
        }
        bb.flip();           //set byteBuffer read position back to start
        SerialPort.clear();  //clear serial buffer
        return true;
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }      
    };
    return false;  //no new data available - no update
  }

  private void GetObjectSize() {    //Calculate the object size and get the fields of the current object with
    fields = this.getClass().getDeclaredFields();
    objectsize = 0;
    for (Field field : fields) {
      if (field.getType() == int.class) { objectsize += 4; }      //source https://cs.fit.edu/~ryan/java/language/java-data.html
      if (field.getType() == boolean.class) { objectsize += 1; }  //an easier way would be fine!
      if (field.getType() == byte.class) { objectsize += 1; }
      if (field.getType() == char.class) { objectsize += 2; }
      if (field.getType() == short.class) { objectsize += 2; }
      if (field.getType() == long.class) { objectsize += 8; }
      if (field.getType() == float.class) { objectsize += 4; }
      if (field.getType() == double.class) { objectsize += 8; }
    }
    values = new byte[objectsize];              //Prepair some space for the serial data array
    bb = ByteBuffer.wrap(values);               //Prepair the byteBuffer with the serial data array
    bb.order(ByteOrder.LITTLE_ENDIAN);          //For Arduino it's neccessary to set order of bits to little endian
  }
}

test1.java

public class test1 extends SerialTransmission {    //An test of the serial transmission
  public int x;
  public int y;
}

Nice result. :slight_smile:

I was trying to use switch but it doesn’t work…

Yep, no switch for classes in Java.

I don’t call GetObjectSize() every time. GetObjectSize() is just called once if objectsize is -1.

Nice, missed it.

But the only thing which still annoys me are the missed bytes which are removed my SerialPort.clear() . (some times 56-64 bytes are available) May you have some ideas about it?

Sorry, I didn’t get the problem. Probably you don’t need to clear inner serial buffer, just read chunks of data from it directly with readBytes() etc.

I can’t. In this example I want to read 8 bytes which contain 2 integers. Why should I read the whole chunk of serialbuffer into an array by readBytes() ?
I found an workaround on Arduino side - I just added a waiting loop:

while (Serial.available() < sizeof(objectsize)) { delay(1); }

On processing side I send the first chunk then Arduino answers. So it’s a kind of ping pong and not just sending and reading without any syncronization.

How would you write the else if statement for the classes?