2

So for a homework assignment, I have a example of how to marshal data and unmarshal.

The structure they gave us was this: Event is an interface. Wireformat is a class that "inherits" an Event. WireFormatWidget is a class with the actual code that has the marshal and unmarshal.

I have separate threads that handle the sending data in byte array using TCP.

What I have an issue is that when I create a Wireformat object. I run into issue with a thread trying to marshal the data.

Exception in thread "main" java.lang.NullPointerException
    at myhw.WriteFormatWidget.getBytes(WriteFormatWidget.java:38)

The interface structure defines the data as a message, a type of message as an integer, a timestamp (of what I am assuming is Date and getTime of that date), and a tracker. I am not sure what the tracker is.

I am told this structure is the best method to sending data which is why I am trying to implement this code style.

The WriteFormatWidget consist of this:

private int type;
private long timestamp;
private String identifier;
private int tracker;

So for my wireformat, I created it as a class that extends WireFormatWidget and implements Event because that was the only way Eclipse did not spit an error or suggest changing WireFormatWidget or Event.

Now when I hardcode my specific wireformat, I instantiate it and it seems to not be able to call getBytes() with the hardcoded values I uses for the same variables.

public class MyWireFormat extends WireFormatWidget implements Event {
    private String identifier = "here is my custom wireformat";
    ....

When I print out the identifier in the getBytes in WireFormatWidget, I get null and not the expected identifier I hardcoded. So I must not be "inheriting" appropriately. What am I doing wrong?

EDIT: WireFormatWidget (given)

public class WriteFormatWidget {
private int type;
private long timestamp;
private String identifier;
private int tracker;

    public byte[] getBytes() throws IOException {
        byte[] marshalledBytes = null;
        ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(baOutputStream));

        dout.writeInt(type);
        dout.writeLong(timestamp);

        System.out.println("getBytes using identifier: " + identifier);

        byte[] identifierBytes = identifier.getBytes();
        int elementLength = identifierBytes.length;
        dout.writeInt(elementLength);
        dout.write(identifierBytes);

        dout.writeInt(tracker);

        dout.flush();
        marshalledBytes = baOutputStream.toByteArray();

        baOutputStream.close();
        dout.close();

        return marshalledBytes;
    }
}

I'll save space by not posting the unmarshalling portion. But its the same thing just in reverse.

The issue I am having is printing the data from the Client-side as proof of what I am sending beforehand.

So I will perform a simple test like print the type or print the identifier. It fails and I have null.

Cit5
  • 346
  • 4
  • 14

2 Answers2

1

You're not initializing WireFormatWidget#identifier. It's declared but never initialized. Add a constructor to WireFormatWidget and provide a String as the identifier.

Jason
  • 4,590
  • 2
  • 9
  • 18
  • I shall name my first born male child... Jason... haha. thanks, I owe you big time. Actually I did write a constructor but I never thought of using it in my custom wireformat and overwriting the getBytes() there. That worked. Thank you so much. – Cit5 Feb 09 '20 at 05:36
  • Haha, no worries man, it's usually the small things that end up being the biggest problems. – Jason Feb 09 '20 at 05:39
0

You need to implement something that implements Serializable, or implement directly Serializable (I think is simpler).

You do not specify many things about your interface event, but probably will inherit from Serializable, at least if you are going to implement standard java serialization.

If Event implements Serializable so it is ok, otherwise if you use another serialization method you need to specify more about it.

Assuming that you implement Serializable you need to create a ByteBuffer and call to writeObject. To create the stream you can check for example Java Serializable Object to Byte Array, so joining all:

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream stream = new ObjectOutputStream(bos);   
stream.writeObject(yourinstancetoserialize);
out.flush();
byte[] yourBytes = bos.toByteArray();
...

Probably you will need to implement the writeObject directly. In that case you use the ObjectOutputStream methods to serialize the properties, check them in https://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html for example.

private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
  stream.writeInt(this.type);
  stream.writeLong(this.timestamp);
  stream.writeBytes(this.identifier); or stream.writeChars(this.identifier);
  stream.writeInt(this.tracker);
  ...
}
user1039663
  • 1,090
  • 1
  • 8
  • 15
  • Nope. No serializable allowed. 100% points deduction for using serializable. – Cit5 Feb 09 '20 at 05:14
  • Then do not use writeObject, use directly the ObjectOutputStream/ByteArrayOutputStream functions: stream.writeInt, stream.writeLong and stream.writeBytes. It's all in there, even without using serializable. – user1039663 Feb 11 '20 at 10:41