Having to recreate ObjectOutputStream every time - java

I have seen a few people ask similar questions but the only answer anyone ever posts is that you shouldn't have to do it.
But I've tested it both ways - and it only works this way.
Server Side
try {
// Obtain input and output streams to the client
while(true) {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Object input = in.readObject();
if(input == RequestEnums.GETCURRENTGRID) {
out.writeObject(ContagionServerData.getImagePixels());
out.writeObject(ContagionServerData.getImageHeight());
out.writeObject(ContagionServerData.getImageWidth());
}
}
} catch( Exception e ) {
e.printStackTrace();
}
Client Side
try {
inputStream = new ObjectInputStream(serverSocket.getInputStream());
outputStream = new ObjectOutputStream(serverSocket.getOutputStream());
outputStream.writeObject(RequestEnums.GETCURRENTGRID);
int[] imagePixels = (int[]) inputStream.readObject();
int imageHeight = (Integer) inputStream.readObject();
int imageWidth = (Integer) inputStream.readObject();
copyImage(background, imagePixels, imageHeight, imageWidth);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
This works all day long.
But if I change it to this -
try {
// Obtain input and output streams to the client
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
while(true) {
Object input = in.readObject();
if(input == RequestEnums.GETCURRENTGRID) {
out.writeObject(ContagionServerData.getImagePixels());
out.writeObject(ContagionServerData.getImageHeight());
out.writeObject(ContagionServerData.getImageWidth());
out.flush();
}
}
} catch( Exception e ) {
e.printStackTrace();
}
(I have created the input and output stream farther up in the code)
try {
outputStream.writeObject(RequestEnums.GETCURRENTGRID);
outputStream.flush();
int[] imagePixels = (int[]) inputStream.readObject();
int imageHeight = (Integer) inputStream.readObject();
int imageWidth = (Integer) inputStream.readObject();
copyImage(background, imagePixels, imageHeight, imageWidth);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Then I successfully receive the correct data the first time from the server - but everytime after that - I just receive the same data and not the updated data and no errors as to why.

When you send data on an object stream, it will send each object only once. This means if you modify and object and send it multiple times, you need to either use writeUnshared(mutableObject) or reset() which clears the cache of objects already sent.
You can't create an ObjectOutput/InputStream repeatly. If you want to make sure data is sent instead of buffered use flush(). If you are sending data like int instead of Objects, try DataOutput/InputStream.

See the Javadoc for ObjectOutputStream.reset() and ObjectOutputStream.writeUnshared().

Related

Is try-catching actually this clunky in Java or am I just not aware of the elegant approach?

public void lock() {
if (this.isLocked()) return;
try {
this.dataOut.flush();
this.dataOut.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
DataInputStream inputStream =
new DataInputStream(
new BufferedInputStream(
new ByteArrayInputStream(
this.byteOut.toByteArray())));
IntStream.Builder intStreamBuilder = IntStream.builder();
try {
try {
while (true) {
intStreamBuilder.accept(inputStream.readInt());
}
} catch (EOFException e) {
// logic to be executed after stream has been fully read
int[] pool = intStreamBuilder.build().toArray();
super.lock(pool);
} finally {
inputStream.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
What I do here is take an DataOutputStream containing Integers, flush its remaining contents into a ByteArrayOutputStream named this.byteOut and then build an IntStream from it.
I'm from the C# domain and in the process of learning Java, so the code here does not have any actual purpose.
Is there any way to do what I do here more elegantly in Java?
My two main concerns are:
The way I determine that the DataInputStream has been fully read is by catching an EOFException and putting the logic to be executed after reading inside a catch block. I don't like that, since I suppose throwing and catching exceptions is somewhat expensive? Is there a better way to determine that the stream doesn't contain any more Integers?
The fact that I have to wrap a try-catch block around a try-catch block just to be able to call inputStream.close() in the inner finally block. Is there a solution that is not so clunky?
It's mostly you.
If you don't like the try with resources construct,
you can still combine all of your try statments and stack the catch blocks.
public void lock()
{
DataInputStream inputStream = null;
IntStream.Builder intStreamBuilder;
if (isLocked())
{
return;
}
try
{
inputStream = new DataInputStream(
new BufferedInputStream(
new ByteArrayInputStream(
byteOut.toByteArray())));
intStreamBuilder = IntStream.builder();
dataOut.flush();
dataOut.close();
while (true)
{
intStreamBuilder.accept(
inputStream.readInt());
}
}
catch (IOException exception)
{
throw new RuntimeException(exception);
}
catch (EOFException ignoredException)
{
// logic to be executed after stream has been fully read
int[] pool = intStreamBuilder.build().toArray();
super.lock(pool);
}
finally
{
if (inputSream != null)
{
try
{
inputStream.close();
}
catch (IOException exception)
{
throw new RuntimeException(exception);
}
}
}
}
The try inside the finally is required.
I prefer the try-with-resources construct.
If I were you I will change my code to be as the following
//try-with-resources-close
try (DataInputStream inputStream =
new DataInputStream(
new BufferedInputStream(
new ByteArrayInputStream(
this.byteOut.toByteArray())))) {
IntStream.Builder intStreamBuilder = IntStream.builder();
byte[] byts = new byte[4];
while (inputStream.read(byts) > -1) {// read 4 bytes and convert them to int
int result = ByteBuffer.wrap(byts).getInt();
intStreamBuilder.accept(result);
}
// logic to be executed after stream has been fully read
int[] pool = intStreamBuilder.build().toArray();
super.lock(pool);
} catch (IOException e) {
throw new RuntimeException(e);
}
try-with-resources this new way added in Java 7 to close any object that implements AutoCloseable automatically when try block is executed
readInt method it works as the following read 4 bteys then convert them to int
int ch1 = in.read();
int ch2 = in.read();
int ch3 = in.read();
int ch4 = in.read();
if ((ch1 | ch2 | ch3 | ch4) < 0)
throw new EOFException();
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
//So you also can do the same thing, but instead of throws EOFException
you can add return false or break the loop
for read bytes method if no bytes existed then it reture -1
Well the better solution I found thanks to #Oliver Charlesworth is the following:
try (DataInputStream inputStream =
new DataInputStream(
new BufferedInputStream(
new ByteArrayInputStream(this.byteOut.toByteArray())))) {
while (true)
intStreamBuilder.accept(inputStream.readInt());
} catch (EOFException e) {
int[] pool = intStreamBuilder.build().toArray();
super.lock(pool);
} catch (IOException e) {
throw new RuntimeException(e);
}
This still has logic inside the catch block the code look definitely cleaner.
However, I cannot come up with a better approach that determines that the InputDataStream has been fully read.
What bugs me about this is that reaching the end of the stream is expected and it would actually be exceptional if no exception was thrown, what IMO defeats the purpose of exceptions in the first place.
I asked a separate question of the possible use of Java NIO's IntBuffer class here. My above snippet could be changed to:
IntBuffer intBuffer = ByteBuffer.wrap(this.byteOut.toByteArray()).asIntBuffer();
while (intBuffer.hasRemaining()){
intStreamBuilder.accept(intBuffer.get());
}
int[] pool = intStreamBuilder.build().toArray();
super.lock(pool);

JAVA objectinputstream cant drop out from the loop

Here is the code I have:
ObjectInputStream ois = null;
UserRegistration UR = new UserRegistration();
Scanner pause = new Scanner(System.in);
Admin go = new Admin();
try {
//ItemEntry book = new ItemEntry();
ois = new ObjectInputStream(new FileInputStream("Account.txt"));
while ((UR = (UserRegistration) ois.readObject()) != null) {
//if (book.getName().equals("1"))
{
System.out.println(UR);
}
}
} catch (EOFException e) {
System.out.println("\nEnd**");
}catch (ClassNotFoundException ex) {
System.out.println(ex.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
ois.close();
System.out.println("Press \"ENTER\" to continue...");
pause.nextLine();
go.startup();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
How can I make it drop out from the loop and not to straight enter to the EOFException when it reach the last object? Help please !
This is a duplicate of this question :
Java FileInputStream ObjectInputStream reaches end of file EOF
Bottom line is that ObjectInputStream does not return null when it reaches the end of the stream. Instead, the underlying FileInputStream throws an EOFException. Although you could interpret that as the end of file, it does not allow you to distinguish a truncated file. So, practically speaking, ObjectInputStream expects you to know how many objects you will be reading in.
To get around this you could write an integer to the start of the file indicating how many UserRegistration objects are in the file. Read that value, then use a for loop to read that many objects.
Alternatively, you may be able to serialize your UserRegistration objects as an array or other container and then de-serialize the whole array/container.

EOFexception caused by empty file

I created a new file roomChecker which is empty. Now when I read it, it throws me an EOFException which is undesirable. Instead I want it to see that, if file is empty then it would run other two functions that are in if(roomFeed.size() == 0) condition. I could write this statement in EOFException catch clause; but that's not what I want to do because then every time when the file will be read and reaches end of file it will execute those functions. Instead when the file has some data it should do what is specified in else.
File fileChecker = new File("roomChecker.ser");
if(!fileChecker.exists()) {
try {
fileChecker.createNewFile();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Unable to create new File");
}
}
try(FileInputStream fis = new FileInputStream("roomChecker.ser"); ObjectInputStream ois = new ObjectInputStream(fis)) {
roomFeed = (List<roomChecker>) ois.readObject();
System.out.println("End of read");
if(roomFeed.size() == 0) {
System.out.println("your in null if statement");
defaultRoomList();
uploadAvailableRooms();
} else {
for(int i=0; i<roomNumber.size(); i++) {
for(int j=0; j<roomFeed.size(); i++) {
if((roomNumber.get(i)).equals(roomFeed.get(i).getRoomNumSearch())){
System.out.println("Reach Dead End for now");
} else {
defaultRoomList();
uploadAvailableRooms();
}
}
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
All this:
if(!fileChecker.exists()) {
try {
fileChecker.createNewFile();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Unable to create new File");
}
}
is a complete waste of time, and it is one of two possible causes for your empty file problem. Creating a file just so you can open it and then get a different problem instead of coping correctly with the original problem of the file not being there isn't a rational strategy. Instead, you should do this:
if (fileChecker.isFile() && fileChecker.length() == 0) {
// file is zero length: bail out
}
and, in the following code, this:
try(FileInputStream fis = new FileInputStream(fileChecker); ObjectInputStream ois = new ObjectInputStream(fis)) {
// ...
}
catch (FileNotFoundException exc) {
// no such file ...
}
// other catch blocks as before.
Of course you can still get EOFException if you read the file to its end, or if the file is incomplete, and you still need to handle that.

Code after readObject() does not run

I am working on a UI which reads serialized object from zookeeper, deserializes it and then converts it into JSON. For some reason I am not able to deseerialize the MQTopic object. But I am able to do the same with other objects.
This is the part which converts the byte[] into the MQTopic object.
if (tester != null && tester.contains("com.ibm.mq.jms.MQTopic")) {
System.out.println(getValue());
ByteArrayInputStream in = new ByteArrayInputStream(this.value);
ObjectInputStream is = new ObjectInputStream(in);
System.out.println("after deserializing..");
topic = (MQTopic) is.readObject();
System.out.println("after typecasting..");
System.out.println(topic.getTopicName());
System.out.println(topic.toString());
is.close();
in.close();
}
Here value is a byte array of the object after serialization.
Nothing runs after topic = (MQTopic) is.readObject(); . Not even the print statements. The program neither terminates nor an exception is thrown or caught.
EDIT : Whole Method
public String getStrValue() {
FtpConnectionInfo ftp = null;
MQTopic topic = null;
try {
String tester = new String(this.value, "UTF-8");
if (tester != null && tester.contains("FtpConnectionInfo")) {
ByteArrayInputStream in = new ByteArrayInputStream(this.value);
ObjectInputStream is = new ObjectInputStream(in);
ftp = (FtpConnectionInfo) is.readObject();
in.close();
is.close();
Gson gson = new Gson();
return gson.toJson(ftp);
} else if (tester != null
&& tester.contains("com.ibm.mq.jms.MQTopic")) {
ByteArrayInputStream in = new ByteArrayInputStream(this.value);
ObjectInputStream is = new ObjectInputStream(in);
System.out.println("after deserializing..");
topic = (MQTopic) is.readObject();
System.out.println("after typecasting..");
System.out.println(topic.getTopicName());
System.out.println(topic.toString());
is.close();
in.close();
} else {
return new String(this.value, "UTF-8");
}
} catch (UnsupportedEncodingException ex) {
System.out.println("unsupported error ");
ex.printStackTrace();
//logger.error(Arrays.toString(ex.getStackTrace()));
} catch (Exception e) {
System.out.println("Exception in new logic.");
e.printStackTrace();
}
System.out.println("im out of try");
return null;
}
The FTP if loop works fine, but the Topic loop does not work beyond typecasting.
EDIT 2: This how the other team stores the object into Zookeeper
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
return out.toByteArray();
}
The byte[] is stored in Zookeeper and that is what I am retrieving in my UI.
EDIT 3: I did a debug of the process and at the point where is is called, these are the values. Can anyone tell me if the object is right ?
You're doing this wrong. You should deserialize the object first, and then use instanceof to see what type it is. Converting binary data to String is poor practice at the best of times.
Your actual symptom is not credible. An exception must be thrown, or else you are blocking earlier than stated.
ObjectInputStream's readObject is a blocking method. First check using the available method if there is something to read without blocking.
available would most probably return 0 in this case.
This might be only half the solution you are looking for, but I think this would let you know if you have anything to read or not.

How do I solve this indexOutOfBoundsException in my server send/receive thread?

I am creating a multiplayer game in Java with a server and multiple clients. Everything runs perfectly, until I press the Kick-button in the server to kick a client.
Error at receive thread of server, after kicking the first person who joined out of three:
java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
at java.util.ArrayList.rangeCheck(ArrayList.java:604)
at java.util.ArrayList.get(ArrayList.java:382)
> at networktest.Server$3.run(Server.java:186)
at java.lang.Thread.run(Thread.java:722)
The pointed line is the ois = new ObjectInputStream where I receive datatype in the server receive thread. The server kicks the first person perfectly, but removes the second one in the list too, with an error of java.lang.ClassCastException.
server receive:
private static Thread receive = new Thread()
{
#Override
public void run()
{
ObjectInputStream ois;
while (true)
{
for (int i = 0; i < list_sockets.size(); i++)
{
try
{
ois = new ObjectInputStream(list_sockets.get(i).getInputStream());
int receive_state = (Integer) ois.readObject(); // receive state
ois = new ObjectInputStream(list_sockets.get(i).getInputStream());
byte datatype = (byte) ois.readObject(); // receive datatype
if(datatype == 2){
ois = new ObjectInputStream(list_sockets.get(i).getInputStream());
ChatLine chatLine = (ChatLine) ois.readObject(); // receive ChatLine
} else if (datatype == 0){
ois = new ObjectInputStream(list_sockets.get(i).getInputStream());
DataPackage dp = (DataPackage) ois.readObject(); // receive dp
list_data.set(i, dp);
}
if (receive_state == 1) // Client Disconnected by User
{
disconnectClient(i);
i--;
}
}
catch (Exception ex) // Client Disconnected (Client Didn't Notify Server About Disconnecting)
{
System.err.println("Error # receive:");
ex.printStackTrace();
disconnectClient(i);
i--;
}
}
try {
this.sleep(3);
} catch (InterruptedException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
user send:
Thread send = new Thread()
{
public void run()
{
ObjectOutputStream oos;
byte datatype = 0;
while (connected){
if (socket != null){
try {
DataPackage dp = new DataPackage();
dp.x = Client.player.x;
dp.y = Client.player.y;
dp.username = username;
dp.charType = charType;
dp.walking = (byte)Client.player.walking;
if (Client.outputChatLine.line != null)
datatype = 2;
else {
datatype = 0;
}
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(Integer.valueOf(Client.this.state)); // send state
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(Byte.valueOf(datatype)); // send datatype
if (datatype == 2)
{
oos.reset();
oos.writeObject(Client.outputChatLine);
Client.outputChatLine = new ChatLine();
} else {
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(dp);
}
if (Client.this.state == 1) {
connected = false;
socket = null;
JOptionPane.showMessageDialog(null, "Client Disconnected", "Info", 1);
System.exit(0);
}
}
catch (Exception ex){}
}
try {
this.sleep(2);
} catch (InterruptedException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
disconnect client method:
public static void disconnectClient(int index)
{
try
{
list_clients_model.removeElementAt(index);
list_client_states.remove(index);
list_data.remove(index);
list_sockets.remove(index);
}
catch (Exception ex) {}
}
Does anyone know how to solve this?
It looks like you're expecting some other thread to fill some data into list_sockets while you're sleep(3)ing. But you have no synchronization to ensure that this happens only while you're sleeping.
It could equally well happen that the other thread is updating list_sockets simultaneously with your own thread calling list_sockets.get(i). And the ArrayList implementation it is almost certainly not written to have two different of its methods executing simultaneously in two different threads. For example, the other thread could be in the middle of resizing the backing array when you're trying to read an element, and then any crazy thing can go wrong, including the error you're seeing.
You need to learn about inter-thread synchronization. At the very least you need synchronized blocks to protect access to shared data structures. And while you're at it; look at wait/notify or some higher-level concurrency tools to get rid of that horrible 3-millisecond polling loop -- instead have the thread that drops work into the list explicitly wake up the worker thread.

Categories

Resources