2

I'm making networking program with Java. As the title, the object which server is trying to send is changed in client which receives it. I'm trying to change the object which exists in client before I receive the new one from server. Here's my codes. First one is Server.sendIdea and second is Client.rcvIdea.

void sendIdea(Idea _idea) throws IOException {
    objectOS.flush();
    Idea idea = _idea;
//when I look into 'idea' it's fine
    objectOS.writeObject(idea);
}

..

Idea rcvIdea(int _ideaCode) throws ClassNotFoundException, IOException {
    objectOS.writeObject("sendIdea");
    objectOS.writeObject(_ideaCode);
    Idea returnValue = (Idea) objectIS.readObject();
//when I look into 'returnValue', it is not the one 'sendIdea' has sent.
    return returnValue;
}

As you can see, sendIdea(Idea _idea) is sending an object from the class Idea by using writeObject method. And rcvIdea() is receiving the object by using readObject() method. (I'm sure you don't have to know about class Idea in detail). The client actually received some Ideas at start of this program by this method and there was no problem. But when I try to receive the same but slightly changed object Idea by this method, in Client class the object does not change, not like in Server class where the object which is going to be sent by sendIdea method is changed correctly. I tried about 5 hours to solve this problem. I checked all the codes line by line and found nothing. I'm pretty sure that writeObject or readObject method have problem. I tried objectOS.flush() to make clear of the stream and many other trials. I hope that I can find the problem. Below is some codes in my program

Client.class package ideaOcean;

import java.awt.HeadlessException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

import javax.swing.JOptionPane;

import data.Idea;
import data.Opinion;
import data.Profile;

public class Client {
Socket socket;
OutputStream os;
ObjectOutputStream objectOS;
InputStream is;
ObjectInputStream objectIS;
MainWindow mainWindow;

int idCode;
String email, password;
Profile myProfile;
ArrayList<Idea> myIdeas;
ArrayList<Opinion> myOpinions;
ArrayList<Integer> newIdeasCodes, hotIdeasCodes;
ArrayList<Idea> newIdeas, hotIdeas;

String command;

static final String SERVER_IP = "127.0.0.1";// 
static final int SERVER_PORT_NUM = 5000;

public static void main(String[] args) {
    Client client = new Client();
    client.mainWindow = new MainWindow();

    client.mainWindow.setVisible(true);

    client.mainWindow.showLoginPg();
    try {
        while (!client.loginCheck()) {// login
            continue;
        }
    } catch (HeadlessException | NumberFormatException | ClassNotFoundException | IOException e) {
        e.printStackTrace();
    }
    System.out.println("[login complete]");

    try {
        client.myProfile = client.rcvProfile(client.idCode);// get myProfile
        int i;
        for (i = 0; i < client.myProfile.myIdeaCode.size(); i++) {
            client.myIdeas.add(client.rcvIdea(client.myProfile.myIdeaCode.get(i)));
        }
        for (i = 0; i < client.myProfile.myOpinionCode.size(); i++) {
            client.myOpinions.add(client.rcvOpinion(client.myProfile.myOpinionCode.get(i)));
        }
        // ***************************
    } catch (ClassNotFoundException | IOException e1) {
        e1.printStackTrace();
    }

    try {
        client.rcvNewIdeas(12);
        client.mainWindow.newOcean.floatingIdeas = client.newIdeas;
        client.mainWindow.newOcean.arrangeFloatingPanels();

        client.rcvHotIdeas(12);
        client.mainWindow.hotOcean.floatingIdeas = client.hotIdeas;
        client.mainWindow.hotOcean.arrangeFloatingPanels();
    } catch (ClassNotFoundException | IOException e) {
        e.printStackTrace();
    }

    client.mainWindow.setMyPg(client.myProfile, client.myIdeas, client.myOpinions);
    client.mainWindow.showMainPg();

    client.start();
}

public Client() {
    try {
        socket = new Socket(SERVER_IP, SERVER_PORT_NUM);

        System.out.println("Connected to Server!");

        os = socket.getOutputStream();
        objectOS = new ObjectOutputStream(os);
        is = socket.getInputStream();
        objectIS = new ObjectInputStream(is);

        myIdeas = new ArrayList<>();
        myOpinions = new ArrayList<>();
        newIdeasCodes = new ArrayList<>();
        hotIdeasCodes = new ArrayList<>();
        newIdeas = new ArrayList<>();
        hotIdeas = new ArrayList<>();

    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

void start() {
    while (true) {
        try {
            if (mainWindow.newBtnClicked) {
                rcvNewIdeas(12);
                mainWindow.newOcean.floatingIdeas = newIdeas;
                mainWindow.newOcean.arrangeFloatingPanels();
                mainWindow.newBtnClicked = false;
            } else if (mainWindow.hotBtnClicked) {
                rcvHotIdeas(12);
                mainWindow.hotOcean.floatingIdeas = hotIdeas;
                mainWindow.hotOcean.arrangeFloatingPanels();
                mainWindow.hotBtnClicked = false;
            } else if (mainWindow.newOcean.detailBtnClicked) {

                updateIdeaDetailFrame(mainWindow.newOcean.clickedIdea);
                mainWindow.newOcean.detailBtnClicked = false;

            } else if (mainWindow.hotOcean.detailBtnClicked) {

                updateIdeaDetailFrame(mainWindow.hotOcean.clickedIdea);
                mainWindow.hotOcean.detailBtnClicked = false;

            } else if (mainWindow.ideaDetailFrame.saveOpinionBtnClicked) {

                sendOpinion(mainWindow.ideaDetailFrame.newOpinion);
                updateIdeaDetailMainPanel(rcvIdea(mainWindow.ideaDetailFrame.idea.ideaCode));
                mainWindow.ideaDetailFrame.saveOpinionBtnClicked = false;

            } else if (mainWindow.writeIdeaPg.postIdeaBtnClicked) {

                sendIdea(mainWindow.writeIdeaPg.thisIdea);
                mainWindow.writeIdeaPg.postIdeaBtnClicked = false;

            } else if (mainWindow.newOcean.plusBtnClicked) {

                objectOS.writeObject("plusBtnClicked");
                objectOS.writeObject(mainWindow.newOcean.plusMinusClickedIdeaCode);
                mainWindow.newOcean.plusBtnClicked = false;

            } else if (mainWindow.newOcean.minusBtnClicked) {

                objectOS.writeObject("minusBtnClicked");
                objectOS.writeObject(mainWindow.newOcean.plusMinusClickedIdeaCode);
                mainWindow.newOcean.minusBtnClicked = false;

            } else if (mainWindow.hotOcean.plusBtnClicked) {

                objectOS.writeObject("plusBtnClicked");
                objectOS.writeObject(mainWindow.hotOcean.plusMinusClickedIdeaCode);
                mainWindow.hotOcean.plusBtnClicked = false;

            } else if (mainWindow.hotOcean.minusBtnClicked) {

                objectOS.writeObject("minusBtnClicked");
                objectOS.writeObject(mainWindow.hotOcean.plusMinusClickedIdeaCode);
                mainWindow.hotOcean.minusBtnClicked = false;

            } else if (mainWindow.myBtnClicked) {

                mainWindow.setMyPg(myProfile, myIdeas, myOpinions);
                mainWindow.myBtnClicked = false;
            }
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();
        }
    }
}

int i = 0;

Idea rcvIdea(int _ideaCode) throws ClassNotFoundException, IOException {
    objectOS.writeObject("sendIdea");
    objectOS.writeObject(_ideaCode);
    Idea returnValue = (Idea) objectIS.readObject();
    return returnValue;
}

Opinion rcvOpinion(int _opinionCode) throws ClassNotFoundException, IOException {
    objectOS.writeObject("sendOpinion");
    objectOS.writeObject(_opinionCode);
    return (Opinion) objectIS.readObject();
}

Profile rcvProfile(int _idCode) throws IOException, ClassNotFoundException {
    objectOS.writeObject("sendProfile");
    objectOS.writeObject(_idCode);
    return (Profile) objectIS.readObject();
}

void rcvNewIdeasCodes() throws ClassNotFoundException, IOException {
    objectOS.writeObject("sendNewIdeasCodes");
    newIdeasCodes = (ArrayList<Integer>) objectIS.readObject();
}

void rcvHotIdeasCodes() throws IOException, ClassNotFoundException {
    objectOS.writeObject("sendHotIdeasCodes");
    hotIdeasCodes = (ArrayList<Integer>) objectIS.readObject();
}

void rcvNewIdeas(int num) throws ClassNotFoundException, IOException {
    int i;
    rcvNewIdeasCodes();
    newIdeas = new ArrayList<>();
    if (num <= newIdeasCodes.size()) {
        for (i = 0; i < num; i++) {
            newIdeas.add(rcvIdea(newIdeasCodes.get(i)));
        }
    } else {
        for (i = 0; i < newIdeasCodes.size(); i++) {
            newIdeas.add(rcvIdea(newIdeasCodes.get(i)));
        }
    }
}

void rcvHotIdeas(int num) throws ClassNotFoundException, IOException {
    int i;
    rcvHotIdeasCodes();
    hotIdeas = new ArrayList<>();
    if (num <= hotIdeasCodes.size()) {
        for (i = 0; i < num; i++) {
            hotIdeas.add(rcvIdea(hotIdeasCodes.get(i)));
        }
    } else {
        for (i = 0; i < hotIdeasCodes.size(); i++) {
            hotIdeas.add(rcvIdea(hotIdeasCodes.get(i)));
        }
    }
}

void sendIdea(Idea _idea) throws IOException {
    objectOS.writeObject("rcvIdea");
    objectOS.writeObject(_idea);
}

void sendOpinion(Opinion _opinion) throws IOException {
    objectOS.writeObject("rcvOpinion");
    objectOS.writeObject(_opinion);
}

void sendProfile(Profile _profile) throws IOException {
    objectOS.writeObject(_profile);
}

boolean loginCheck() throws HeadlessException, NumberFormatException, IOException, ClassNotFoundException {
    objectOS.writeObject("loginCheck");// send command

    while (!mainWindow.loginBtnClicked) {
        continue;
    }
    mainWindow.loginBtnClicked = false;

    email = mainWindow.emailField.getText().trim();
    password = mainWindow.passwordField.getText().trim();
    objectOS.writeObject(email);
    objectOS.writeObject(password);

    boolean valid;
    valid = (boolean) objectIS.readObject();
    if (valid == false) {
        JOptionPane.showMessageDialog(mainWindow, "ID or Password is not correct");
        mainWindow.emailField.setText("");
        mainWindow.passwordField.setText("");
        return false;
    } else if (valid == true) {
        idCode = (int) objectIS.readObject();
        return true;
    } else {
        return false;
    }
}

void updateIdeaDetailMainPanel(Idea clickedIdea) throws ClassNotFoundException, IOException {
    ArrayList<Opinion> opinions = new ArrayList<>();
    for (int j = 0; j < clickedIdea.opinionCode.size(); j++) {
        opinions.add(rcvOpinion(clickedIdea.opinionCode.get(j)));
    }
    mainWindow.ideaDetailFrame.updateMainPanel(opinions);
}

void updateIdeaDetailFrame(Idea clickedIdea) throws ClassNotFoundException, IOException {
    ArrayList<Opinion> opinions = new ArrayList<>();
    for (int j = 0; j < clickedIdea.opinionCode.size(); j++) {
        opinions.add(rcvOpinion(clickedIdea.opinionCode.get(j)));
    }
    mainWindow.ideaDetailFrame = new IdeaDetailFrame(clickedIdea, opinions);
    mainWindow.ideaDetailFrame.setVisible(true);
}
}

Idea.class package data;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;

public class Idea implements Serializable {

private static final long serialVersionUID = 123123L;
public int idCode;
public int ideaCode;

public int plus = 0, minus = 0;

public String ideaName;
public String oneLineExp;
public String explanation;
public ArrayList<Integer> opinionCode;
public Date date;
public MyCanvas image;

int hotDegree;

public Idea(int _idCode,int _ideaCode, String _ideaName, String _oneLineExp, String _explanation, MyCanvas _image) {
    this(_idCode,_ideaName,_oneLineExp,_explanation,_image);
    ideaCode = _ideaCode;

}

public Idea(int _idCode, String _ideaName, String _oneLineExp, String _explanation, MyCanvas _image) {
    this(_idCode,_ideaName,_oneLineExp,_explanation);
    image = _image;
}

public Idea(int _idCode, String _ideaName, String _oneLineExp, String _explanation){
    idCode = _idCode;
    oneLineExp = new String(_oneLineExp);
    ideaName = new String(_ideaName);
    explanation = new String(_explanation);
    date = new Date();
    opinionCode = new ArrayList<>();
}

public void saveIdea() {
    FileOutputStream fos = null;
    ObjectOutputStream oos = null;

    try {
        fos = new FileOutputStream("Idea.dat");
        oos = new ObjectOutputStream(fos);

        oos.writeObject(this);
    } catch (IOException e1) {
        System.out.println("e1");
    }
}

void addOpinionCode(int _opinion) {
    opinionCode.add(opinionCode.size(), _opinion);
}

public void incPlus() {
    plus++;
}

public void incMinus() {
    minus++;
}

public int setHotDegree() {
    hotDegree = plus - minus + opinionCode.size() * 2;
    return hotDegree;
}

}

Opinion.class

package data;

import java.io.Serializable;
import java.util.Date;

public class Opinion implements Serializable{
int idCode;
public int opinionCode;//the intrinsic code of this opinion

public int commentedIdeaCode;
public String opinion;
public Date date;
int plus, minus;

public Opinion(int _idCode,int _commentedIdeaCode, String _opinion){
    idCode = _idCode;
    commentedIdeaCode = _commentedIdeaCode;
    opinion = new String(_opinion);
    date = new Date();
    plus = 0;
    minus = 0;
}// Opinion(int _idCode,int _commentedIdeaCode, String _opinion)

public Opinion(int _idCode,int _opinionCode,int _commentedIdeaCode, String _opinion){
    this(_idCode, _commentedIdeaCode, _opinion);
    opinionCode = _opinionCode;
}//Opinion(int _idCode,int _opinionCode,int _commentedIdeaCode, String _opinion)

void incPlus(){
    plus++;
}

void incMinus(){
    minus++;
}
}
JHKwag
  • 31
  • 4
  • 1
    (I'm sure you don't have to know about class Idea in detail) -> actually yes, we do – JonK Dec 09 '16 at 10:45
  • I take it `objectOS` and `objectIS` are standard ObjectInput/OutputStreams? If so, it's highly unlikely that their read/write method works incorrectly. It is used by a huge codebase in all sorts of production-quality code. It is more likely that implementation details of the Idea class make the object instantiation of ObjectInputStream.readObject() non-intuitive (for instance, because static variables are used in a constructor, or something else which detaches state from the serialized object). – Markus Fischer Dec 09 '16 at 10:50
  • 1
    what do you mean by `the object does not change`? Attributes are not changed? `equals` still return true? You wrote `the same but slightly changed object Idea`, can you povide a MVCE to show how you change and send the object? – jhamon Dec 09 '16 at 10:50
  • Does your *Idea* class have a default constructor? In the code example it is missing. – Alexander Dec 09 '16 at 11:00
  • @jhamon As you can see in main method in `Client` class, the client object receives many Idea objects from server by using `rcvIdea` method. Then the client has many Idea objects. But when the client receives the Idea object which was in the client and is now slightly changed in server, this object remains same as the object at the beginning. – JHKwag Dec 09 '16 at 11:06
  • @Alexander I have made a default constructor and run this again but it is not solved – JHKwag Dec 09 '16 at 11:11
  • Please answer the first question I asked in my previous comment. And i ask another one: what is unchanged? The java object or the content displayed in the `ideaDetailFrame`? Try to be more specific. – jhamon Dec 09 '16 at 11:12
  • @MarkusFischer I agree with you. read/write method must not be wrong but I tried lots of debuggings found nothing. I wrote Idea class. Is there any problem? – JHKwag Dec 09 '16 at 11:15
  • @jhamon In the beginning, the `opinionCode` in Idea objects have size 3. Then during the program in process, the Client send new `opinion` to the server and server adds the integer value `opinionCode` of this opinion object to the ArrayList `opinionCode` in the idea object and send the idea object to the client again. This idea object has all same properties except the ArrayList `opinionCode` which was change by the server. So I mentioned it 'same but slightly changed'. – JHKwag Dec 09 '16 at 11:26
  • @jhamon Then the client call `updateIdeaDetailMainPanel` and the parameter is the new idea object. But `clickedIdea.opinionCode.size()` in the method `updateIdeaDetailMainPanel` is still same as the beginning(which was 3). I'll edit my question to add more codes. Please have a look – JHKwag Dec 09 '16 at 11:27

1 Answers1

4

ObjectOutputStream creates a graph of all objects already serialized, and uses references to previously serialized objects. Therefore, when you serialize an Idea instance multiple times, each time after the first, a reference to the first serialization is written instead of the full object.

You can use ObjectOutputStream.reset() after each serialization. This discards the object graph and forces ObjectOutputStream to create new object serializations, even for objects it had seen before.

Your sendIdea method should therefore look like this:

void sendIdea(Idea _idea) throws IOException {
    objectOS.flush();
    objectOS.reset();

    Idea idea = _idea;
    objectOS.writeObject(idea);
}

Very importantly, please note that after reset(), all object references are serialized anew. So if you have a complex object graph, you may end up with object duplicates after deserialization.

If you want to share transitive references for an object that is to be serialized multiple times, look into ObjectOutputStream.writeUnshared() instead.

Markus Fischer
  • 1,326
  • 8
  • 13