How to get bytes back from ChannelBuf?

I can’t sleep because of this. I tried writeBytes(bytes) then readBytes(bytes.length())
always got java.io.StreamCorruptedException: invalid stream header: 000A4275
I checked length is correct.
Did I miss something?

Can you show your full code?

	public static void name(Player player, String server) {
	RawDataChannel channel = ...
	ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
	ObjectOutput objectOutput = null;
	byte[] objecyBytes;
	
	try {
		objectOutput = new ObjectOutputStream(byteArrayOutputStream);
		objectOutput.writeObject("TEST");
	} catch (IOException e) {
		e.printStackTrace();
	} finally {
		try {
			if (objectOutput != null) {
				objectOutput.close();
			}
		} catch (Exception e2) {
			e2.printStackTrace();
		}
		try {
			byteArrayOutputStream.close();
		} catch (Exception e2) {
			e2.printStackTrace();
		}
	}
	
	objecyBytes = byteArrayOutputStream.toByteArray();
	
	channel.sendTo(player, buf -> {buf.writeUTF("Forward").writeUTF(server).writeUTF("BungeeCord").writeBytes(objecyBytes);
	byte[] msgbytes = buf.readBytes(buf.available());
	ObjectInput objectInput = null;
	try {
		objectInput = new ObjectInputStream(new ByteArrayInputStream(msgbytes));
		Object object = objectInput.readObject();
		System.out.println(object);//error
	} catch (IOException | ClassNotFoundException e) {
		e.printStackTrace();
	}
	ObjectInput objectInput2 = null;
	try {
		objectInput2 = new ObjectInputStream(new ByteArrayInputStream(objecyBytes));
		Object object2 = objectInput2.readObject();
		System.out.println(object2);//TEST
	} catch (IOException | ClassNotFoundException e) {
		e.printStackTrace();
	}
		});
	
}

I will leave a long time, so may not reply in few weeks.

Getting bytes from a ChannelBuf works fine, I just tested it with your code.
What you’re doing wrong is creating a ObjectInputStream out of the data written to the buffer. This is not a valid format for the object stream serializer.
Reading and writing the object stream works fine if you use the original content like this:

objectInput = new ObjectInputStream(new ByteArrayInputStream(objecyBytes));

I’m confused as to why you’re creating an ObjectInputStream and ObjectOutputStream, these are not normally used and are for specialised cases.

Sorry, I don’t understand this. Can you show me how to let line 28 print “test” instead a EOFE exception? I’m already using objectInput = new ObjectInputStream(new ByteArrayInputStream(objecyBytes));

	RawDataChannel channel = Sponge.getGame().getChannelRegistrar().createRawChannel(this, "BungeeCord");
	ByteArrayOutputStream out = new ByteArrayOutputStream();
	ObjectOutput objectOutput = null;
	
	try {
		objectOutput = new ObjectOutputStream(out);
		objectOutput.writeObject("test");
	} catch (IOException e) {
		e.printStackTrace();
	}
	
	try {
		ObjectInput objectInput = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
		try {
			System.out.println(objectInput.readObject());//Output: test
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	} catch (IOException e) {
		e.printStackTrace();
	}
	
	channel.sendTo((Player) src, buf -> {
		buf.writeUTF("Forward").writeUTF("blue").writeUTF("BungeeCord").writeByteArray(out.toByteArray());
		try {
			ObjectInput objectInput = new ObjectInputStream(new ByteArrayInputStream(buf.readByteArray()));//Output: EOFE exception
			try {
				System.out.println(objectInput.readObject());//Line 28
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}//Output: test
		} catch (IOException e) {
			e.printStackTrace();
		}
	});

For the code you have there, there’s no reason to use Object I/O streams and I’m confused as to why you’re using them. Here’s an example using DataInputStream and DataOutputStream

        RawDataChannel channel = Sponge.getGame().getChannelRegistrar().getOrCreateRaw(this, "BungeeCord");
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(out);
        try {
            dos.writeUTF("test");
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        DataInputStream dis = new DataInputStream(new ByteArrayInputStream(out.toByteArray()));
        try {
            System.out.println(dis.readUTF()); // Output: test
        } catch (IOException e) {
            e.printStackTrace();
        }

        channel.sendTo((Player) src, buf -> {
            buf.writeUTF("Forward").writeUTF("blue").writeUTF("BungeeCord");
            buf.setReadIndex(buf.writerIndex()); // This puts the reader index at the current writer position
            // Write a 'bytearray' object
            buf.writeByteArray(out.toByteArray());
            // Create a new DataInputStream from the 'bytearray' object that was just written
            DataInputStream dis2 = new DataInputStream(new ByteArrayInputStream(buf.readByteArray()));
            try {
                System.out.println(dis2.readUTF()); // Output: test
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

Sorry, I totally forgot to explain this, String “test” is just for example, what I really want is send an object like List<String>. So I need writeObject. Which I finally want is send player with it’s inventory data to another server.

Sorry for missing explain.

OK I see.
what you need to do is like what I did where you set the ‘read index’ to the start of the object stream:

buf.setReadIndex(buf.writerIndex());

Do this before writing the ‘bytearray’
The problem you were having with the code above was that you called readByteArray() where the read index was 0. What this means is that it tried to convert the strings “Forward” “blue” etc into the object stream (this is not a valid format for object streams).

I suggest taking a look at the javadocs regarding the ‘reader index’ and ‘writer index’

Thanks for teaching me about index, but I encountered a new problem. When message is send to another server, it throw a exception “IndexOutOfBoundsException: readerIndex(15) + length(11) exceeds writerIndex(25): UnpooledHeapByteBuf(ridx: 15, widx: 25, cap: 25)”

I don’t understand why it’s out of bounds.

@Plugin(id = "testplugin", name = "TestPlugin", version = "1.0")
public final class Test implements CommandExecutor {
    RawDataChannel channel;
    
    @Listener
    public void onServerStart(GameStartedServerEvent event) {
        channel = Sponge.getGame().getChannelRegistrar().createRawChannel(this, "BungeeCord");
        channel.addListener(Platform.Type.SERVER, new PluginListener(channel));
        CommandSpec spec = CommandSpec.builder()
                .executor(this)
                .build();
        Sponge.getCommandManager().register(this, spec, "test");
    }
    
    @Listener
    public void onServerStop(GameStoppingServerEvent event) {
        Sponge.getChannelRegistrar().unbindChannel(channel);
    }
    
    public CommandResult execute(CommandSource src, CommandContext args) throws CommandException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutput objectOutput = null;
        try {
            objectOutput = new ObjectOutputStream(out);
            objectOutput.writeObject("test");
        } catch (IOException e) {
            e.printStackTrace();
        }
        channel.sendTo((Player) src, buf -> {
            buf.writeUTF("Forward").writeUTF("ALL").writeUTF("BungeeCord").writeShort((short) out.toByteArray().length).writeByteArray(out.toByteArray());
        });
        return CommandResult.success();
    }
}
public class PluginListener implements RawDataListener {

    private RawDataChannel channel;
    
    public PluginListener(RawDataChannel channel) {
        super();
        this.channel = channel;
    }
    
    @Override
    public void handlePayload(ChannelBuf buf, RemoteConnection connection, Platform.Type side) {
        System.out.println(buf.readUTF());
        System.out.println(buf.readShort());
        System.out.println(buf.readerIndex());//Output: 14
        try {
            ObjectInput objectInput = new ObjectInputStream(new ByteArrayInputStream(buf.readByteArray()));
            try {
                System.out.println(objectInput.readObject());//Output: IndexOutOfBoundsException
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

So in the buffer you have written the following:

|UTF|UTF|UTF|SHORT|BYTEARRAY|

However, on reading, you’re only reading one UTF string. So you need to repeat buf.readUTF() a total of 3 times.
I suspect that the output of readShort() is 3 because the writeUTF method first writes the length of the string, in this case “ALL” has a length of 3

But first buf.readUTF() will output “BungeeCord” instead “Forward”, I think it’s because BungeeCord already read first two value.

Finally succeeded! By a lucky guess, I increment writeShort() value by 1 which solved IndexOutOfBoundsException problem.

I still curious why need increment 1 to make it read correctly. As far as I remember, on spigot I don’t need to increment byte array length by 1 when put it into ChannelBuf, just put it’s original length is fine. Maybe it’s problem from BungeeCord?