1

I am going crazy because I am trying to pass by value an observable list of Part objects but I am somehow passing by reference, because every time I add a new Product, and try to pass a NEW list of parts specific for that instance of the Product that will in turn be added to an observable list. Somehow, I can not get it to have a new instance of observable list of parts but instead it is creating references, that, whenever I try to modify one list, it modifies the list for all of them. and if I create a new product, the new Product instances observable list of parts associated with it will then override all the previous product instances parts lists. I have tried everything I could find online for this issue but none of it seems to work. Can you please look over my code to see what I am doing wrong?

To save on putting in to much code, I will just put in addProduct, modifyProduct and Product classes, since I believe that is where the issue or issues are located. If anyone thinks I need more classes, I will edit to add.

addProduct Class


public class addProduct
{
    private static Label error = new Label("");
    private static TextField idT = new TextField();
    private static TextField nameT = new TextField();
    private static TextField invT = new TextField();
    private static TextField priceT = new TextField();
    private static TextField maxT = new TextField();
    private static TextField minT = new TextField();
    private static boolean pass = false;
    private static ObservableList list;
    //private static ObservableList adder = FXCollections.observableArrayList();
    
    public static void displayAddProduct(Stage primaryStage, ObservableList list, ObservableList listParts)
    {
        addProduct.list = list;
        Stage PrimaryStage = primaryStage;
        
        Label addP = new Label("Add Product");
        addP.setStyle("-fx-font-weight: bold;");
        Label id = new Label("ID");
        Label name = new Label("Name");
        Label inv = new Label("Inv");
        Label price = new Label("Price");
        Label max = new Label("Max");
        Label min = new Label("Min");
        
        ///////////////////////////////////
        
        idT.setPrefWidth(140);
        idT.setPromptText(String.valueOf("Auto Gen - Disabled"));
        idT.setFocusTraversable(false);
        nameT.setPrefWidth(140);
        nameT.setText("");
        nameT.requestFocus();
        invT.setPrefWidth(60);
        invT.setText(String.valueOf(""));
        priceT.setPrefWidth(60);
        priceT.setText(String.valueOf(""));
        maxT.setPrefWidth(60);
        maxT.setText(String.valueOf(""));
        minT.setPrefWidth(60);
        minT.setText(String.valueOf(""));
        idT.setEditable(false);
        //l2 = FXCollections.observableArrayList();
        
        ///////////////////////////////////
        
        HBox hId = new HBox(id, idT);
        hId.setSpacing(30);
        HBox hName = new HBox(name, nameT);
        hName.setSpacing(10);
        HBox hInv = new HBox(inv, invT);
        hInv.setSpacing(26);
        HBox hPrice = new HBox(price, priceT);
        hPrice.setSpacing(16);
        HBox hMaxMin = new HBox(max, maxT, min, minT);
        hMaxMin.setSpacing(20);
        
        VBox labels = new VBox(hId, hName, hInv, hPrice, hMaxMin);
        labels.setSpacing(10);
        labels.setStyle("-fx-padding: 20;");
        
        VBox left = new VBox(addP, labels, error);
        labels.setAlignment(Pos.CENTER_LEFT);
        left.setSpacing(10);
        
        ///////////////////////////////////
        
        TableView<Part> tb1 = new TableView<>();
        TableView<Part> tb2 = new TableView<>();
        
        TableColumn pId = new TableColumn("Part ID");
        TableColumn pName = new TableColumn("Part Name");
        TableColumn iLvl = new TableColumn("Inventory Level");
        TableColumn pCost = new TableColumn("Price/ Cost per Unit");
        
        TableColumn pId2 = new TableColumn("Part ID");
        TableColumn pName2 = new TableColumn("Part Name");
        TableColumn iLvl2 = new TableColumn("Inventory Level");
        TableColumn pCost2 = new TableColumn("Price/ Cost per Unit");
        
        tb1.getColumns().addAll(pId, pName, iLvl, pCost);
        tb2.getColumns().addAll(pId2, pName2, iLvl2, pCost2);

        ObservableList l1 = listParts;
        ObservableList l2 = FXCollections.observableArrayList();
        

        tb1.setItems(l1); // This is the list of parts that I can pick and choose to add to tb2
                          // tb2 is the list of chosen products that will then be passed as its
        tb2.setItems(l2); // own list of parts that are unique to each instance of Product.
      
        ///////////////////////////////////


        pId.setCellValueFactory(new PropertyValueFactory<Product, Integer>("id"));
        pName.setCellValueFactory(new PropertyValueFactory<Product, String>("name"));
        pId2.setCellValueFactory(new PropertyValueFactory<Product, Integer>("id"));
        pName2.setCellValueFactory(new PropertyValueFactory<Product, String>("name"));
        iLvl.setCellValueFactory(new PropertyValueFactory<Product, Integer>("stock"));
        pCost.setCellValueFactory(new PropertyValueFactory<Product, Double>("price"));
        iLvl2.setCellValueFactory(new PropertyValueFactory<Product, Integer>("stock"));
        pCost2.setCellValueFactory(new PropertyValueFactory<Product, Double>("price"));
        
        ///////////////////////////////////
        
        TextField search = new TextField();
        search.setPromptText("Search by Part ID or Name");
        search.setPrefWidth(160);
        
        Button add = new Button("Add");
        add.setOnAction(e -> l2.add(tb1.getSelectionModel().getSelectedItem()));
        Button remove = new Button("Remove Associated Part");
        remove.setOnAction(e -> {Part selected = tb2.getSelectionModel().getSelectedItem();
                                 alert(tb2, selected);
        });
        
        Button save = new Button("Save");
        save.setOnAction(e -> {pass = addInfo(l2);
                                if(pass == true){
                                        FXMain.displayMain(PrimaryStage);
                                    }
                                });
        save.setPrefWidth(50);
                
        Button cancel = new Button("Cancel");
        cancel.setOnAction(d -> FXMain.displayMain(PrimaryStage));
        
        ///////////////////////////////////
        
        HBox hSearch = new HBox(search);
        HBox hAdd = new HBox(add);
        HBox hRemove = new HBox(remove);
        HBox saveCancel = new HBox(save, cancel);
        
        hSearch.setAlignment(Pos.BASELINE_RIGHT);
        saveCancel.setSpacing(41);
        
        VBox right = new VBox(hSearch, tb1,hAdd, tb2, hRemove, saveCancel);
        
        hRemove.setAlignment(Pos.TOP_RIGHT);
        hAdd.setAlignment(Pos.BASELINE_RIGHT);
        hAdd.setStyle("-fx-padding: 0 40 0 0;");
        saveCancel.setAlignment(Pos.CENTER_RIGHT);
        right.setSpacing(10);
        
        ///////////////////////////////////
        
        HBox fBox = new HBox(left, right);
        
        fBox.setSpacing(70);
        fBox.setStyle("-fx-border-style: solid inside;" + 
                        "-fx-border-radius: 5;" + 
                        "-fx-padding: 40;");
        
        HBox sBox = new HBox(fBox);
        sBox.setStyle("-fx-padding: 30 40 10 20;");
       
        Scene scene = new Scene(sBox, 800, 520);
        PrimaryStage.setScene(scene);
        
        PrimaryStage.show();
    }
    
    private static boolean addInfo(ObservableList l2)
    {
        ObservableList pass;
        pass = FXCollections.observableArrayList(l2);
        int lastIndex = 0;
        if(!list.isEmpty()){
            Product last = (Product) list.get(list.size() - 1);
            lastIndex = last.getId();
        }
        int intMax = 0, intMin = 0, intInv = 0, intMachine = 0, check1 = 0, check2 = 0;
        double doubPrice = 0;
        boolean nameCheck = false, priceCheck = false, restCheck = false; 
        String checkName = nameT.getText(), checkInv = invT.getText(), checkPrice = priceT.getText(), checkMax = maxT.getText(), checkMin = minT.getText();
        error.setText("");
        String forError = "";
        //Inhouse last = (Inhouse) addList.get(addList.size() - 1);

        if(!checkName.isEmpty())
        {
            nameCheck = true;
        } else {
                forError = forError + "Exception: No data in name field\n";
        }
        try{
            intInv = Integer.parseInt(checkInv);
        } catch (NumberFormatException e){
            forError = forError + "Exception: Inventory is not an Integer\n";
        }
        try{
            doubPrice = Double.parseDouble(checkPrice);
            priceCheck = true;
        } catch (NumberFormatException e) {
            forError = forError + "Exception: Price is not a Double\n";
        }        
        try {
            intMax = Integer.parseInt(checkMax);
            check1 = 1;
        } catch (NumberFormatException e) {
            forError = forError + "Exception: Max is not an Integer\n";
        }
        try{
            intMin = Integer.parseInt(checkMin);
            check2 = 1;
        } catch (NumberFormatException e){
            forError = forError + "Exception: Min is not an Integer\n";
        }
        if(check1 == 1 && check2 == 1)
        {
            if(intInv > intMax || intInv < intMin)
            {
                forError = forError + "Inv must be between Min and Max\n";
            } else {
                restCheck = true;
            }
                if(intMin > intMax)
                {
                    forError = forError + "Exception: Min must be less than Max\n";
                }
            }
        error.setText(forError);  
        if(nameCheck == true && priceCheck == true && restCheck == true)
        {
            list.add(new Product((lastIndex + 1), checkName, doubPrice, intInv, intMin, intMax, pass));
            return true;
        } else{
            return false;
        }
    }
    public static void alert(TableView table, Part selected){
        Alert alert = new Alert(AlertType.CONFIRMATION);
        alert.setTitle("Associated Parts");
        alert.setHeaderText("Do you want to remove this part?");
        alert.setContentText("Remove");
        Optional<ButtonType> result = alert.showAndWait();
        if(result.get() == ButtonType.OK)
        {
            table.getItems().remove(selected);
        }
    }
}

ModifyProductClass

public class ModifyProduct
{
    private static Label error = new Label("");
    private static TextField idT = new TextField();
    private static TextField nameT = new TextField();
    private static TextField invT = new TextField();
    private static TextField priceT = new TextField();
    private static TextField maxT = new TextField();
    private static TextField minT = new TextField();
    private static boolean pass = false;
    private static ObservableList list;
    private static Product modify;
    private static ObservableList l1;
    private static ObservableList l2;
    
    public static void displayModifyProduct(Stage primaryStage, ObservableList list, ObservableList listParts, Product modify)
    {
        ModifyProduct.modify = modify;
        Stage PrimaryStage = primaryStage;
        
        Label addP = new Label("Add Product");
        addP.setStyle("-fx-font-weight: bold;");
        Label id = new Label("ID");
        Label name = new Label("Name");
        Label inv = new Label("Inv");
        Label price = new Label("Price");
        Label max = new Label("Max");
        Label min = new Label("Min");
        
        ///////////////////////////////////
        
        idT.setPrefWidth(140);
        idT.setPromptText(String.valueOf(modify.getId()));
        idT.setFocusTraversable(false);
        nameT.setPrefWidth(140);
        nameT.setText(modify.getName());
        invT.setPrefWidth(60);
        invT.setText(String.valueOf(modify.getStock()));
        priceT.setPrefWidth(60);
        priceT.setText(String.valueOf(modify.getPrice()));
        maxT.setPrefWidth(60);
        maxT.setText(String.valueOf(modify.getMax()));
        minT.setPrefWidth(60);
        minT.setText(String.valueOf(modify.getMin()));
        idT.setEditable(false);
        
        ///////////////////////////////////
        
        HBox hId = new HBox(id, idT);
        hId.setSpacing(30);
        HBox hName = new HBox(name, nameT);
        hName.setSpacing(10);
        HBox hInv = new HBox(inv, invT);
        hInv.setSpacing(26);
        HBox hPrice = new HBox(price, priceT);
        hPrice.setSpacing(16);
        HBox hMaxMin = new HBox(max, maxT, min, minT);
        hMaxMin.setSpacing(20);
        
        VBox labels = new VBox(hId, hName, hInv, hPrice, hMaxMin);
        labels.setSpacing(10);
        labels.setStyle("-fx-padding: 20;");
        
        VBox left = new VBox(addP, labels, error);
        labels.setAlignment(Pos.CENTER_LEFT);
        left.setSpacing(10);
        
        ///////////////////////////////////
        
        TableView<Part> tb1 = new TableView<>();
        TableView<Part> tb2 = new TableView<>();
        
        TableColumn pId = new TableColumn("Part ID");
        TableColumn pName = new TableColumn("Part Name");
        TableColumn iLvl = new TableColumn("Inventory Level");
        TableColumn pCost = new TableColumn("Price/ Cost per Unit");
        
        TableColumn pId2 = new TableColumn("Part ID");
        TableColumn pName2 = new TableColumn("Part Name");
        TableColumn iLvl2 = new TableColumn("Inventory Level");
        TableColumn pCost2 = new TableColumn("Price/ Cost per Unit");
        
        tb1.getColumns().addAll(pId, pName, iLvl, pCost);
        tb2.getColumns().addAll(pId2, pName2, iLvl2, pCost2);

        l1 = listParts;
        l2 = FXCollections.observableArrayList(modify.getList());
        
        tb1.setItems(l1);
        tb2.setItems(l2);
        
        ///////////////////////////////////

        pId.setCellValueFactory(new PropertyValueFactory<Product, Integer>("id"));
        pName.setCellValueFactory(new PropertyValueFactory<Product, String>("name"));
        pId2.setCellValueFactory(new PropertyValueFactory<Product, Integer>("id"));
        pName2.setCellValueFactory(new PropertyValueFactory<Product, String>("name"));
        iLvl.setCellValueFactory(new PropertyValueFactory<Product, Integer>("stock"));
        pCost.setCellValueFactory(new PropertyValueFactory<Product, Double>("price"));
        iLvl2.setCellValueFactory(new PropertyValueFactory<Product, Integer>("stock"));
        pCost2.setCellValueFactory(new PropertyValueFactory<Product, Double>("price"));
        
        ///////////////////////////////////
        
        TextField search = new TextField();
        search.setPromptText("Search by Part ID or Name");
        search.setPrefWidth(160);
        
        Button add = new Button("Add");
        add.setOnAction(e -> l2.add(tb1.getSelectionModel().getSelectedItem()));
        Button remove = new Button("Remove Associated Part");
        remove.setOnAction(e -> {Part selected = tb2.getSelectionModel().getSelectedItem();
                                 alert(tb2, selected);
        });
        
        Button save = new Button("Save");
        save.setOnAction(e -> {pass = addInfo();
                               if(pass == true){ 
                                   FXMain.displayMain(PrimaryStage);
                                    }
                               });
        save.setPrefWidth(50);
                
        Button cancel = new Button("Cancel");
        cancel.setOnAction(d -> FXMain.displayMain(PrimaryStage));
        
        ///////////////////////////////////
        
        HBox hSearch = new HBox(search);
        HBox hAdd = new HBox(add);
        HBox hRemove = new HBox(remove);
        HBox saveCancel = new HBox(save, cancel);
        
        hSearch.setAlignment(Pos.BASELINE_RIGHT);
        saveCancel.setSpacing(41);
        
        VBox right = new VBox(hSearch, tb1,hAdd, tb2, hRemove, saveCancel);
        
        hRemove.setAlignment(Pos.TOP_RIGHT);
        hAdd.setAlignment(Pos.BASELINE_RIGHT);
        hAdd.setStyle("-fx-padding: 0 40 0 0;");
        saveCancel.setAlignment(Pos.CENTER_RIGHT);
        right.setSpacing(10);
        
        ///////////////////////////////////
        
        HBox fBox = new HBox(left, right);
        
        fBox.setSpacing(70);
        fBox.setStyle("-fx-border-style: solid inside;" + 
                        "-fx-border-radius: 5;" + 
                        "-fx-padding: 40;");
        
        HBox sBox = new HBox(fBox);
        sBox.setStyle("-fx-padding: 30 40 10 20;");
       
        Scene scene = new Scene(sBox, 800, 520);
        PrimaryStage.setScene(scene);
        
        PrimaryStage.show();
    }
    
    private static boolean addInfo()
    {
        /**
        Product last;
        int lastIndex;
        try{
            last = (Product) list.get(list.size() - 1);
            lastIndex = last.getId();
        } catch(NumberFormatException e){
            
        }
        **/ 
        int intMax = 0, intMin = 0, intInv = 0, intMachine = 0, check1 = 0, check2 = 0;
        double doubPrice = 0;
        boolean nameCheck = false, priceCheck = false, restCheck = false; 
        String checkName = nameT.getText(), checkInv = invT.getText(), checkPrice = priceT.getText(), checkMax = maxT.getText(), checkMin = minT.getText();
        error.setText("");
        String forError = "";
        //Inhouse last = (Inhouse) addList.get(addList.size() - 1);

        if(!checkName.isEmpty())
        {
            nameCheck = true;
        } else {
                forError = forError + "Exception: No data in name field\n";
        }
        try{
            intInv = Integer.parseInt(checkInv);
        } catch (NumberFormatException e){
            forError = forError + "Exception: Inventory is not an Integer\n";
        }
        try{
            doubPrice = Double.parseDouble(checkPrice);
            priceCheck = true;
        } catch (NumberFormatException e) {
            forError = forError + "Exception: Price is not a Double\n";
        }        
        try {
            intMax = Integer.parseInt(checkMax);
            check1 = 1;
        } catch (NumberFormatException e) {
            forError = forError + "Exception: Max is not an Integer\n";
        }
        try{
            intMin = Integer.parseInt(checkMin);
            check2 = 1;
        } catch (NumberFormatException e){
            forError = forError + "Exception: Min is not an Integer\n";
        }
        if(check1 == 1 && check2 == 1)
        {
            if(intInv > intMax || intInv < intMin)
            {
                forError = forError + "Inv must be between Min and Max\n";
            } else {
                restCheck = true;
            }
                if(intMin > intMax)
                {
                    forError = forError + "Exception: Min must be less than Max\n";
                }
            }
            error.setText(forError);
        if(nameCheck == true && priceCheck == true && restCheck == true)
        {
            modify.setName(checkName);
            modify.setPrice(doubPrice);
            modify.setStock(intInv);
            modify.setMax(intMax);
            modify.setMin(intMin);
            modify.setToList(l2);
            l1 = FXCollections.observableArrayList();
            l2 = FXCollections.observableArrayList();
            idT.setText("");
            nameT.setText("");
            priceT.setText("");
            minT.setText("");
            maxT.setText("");
            
            return true;
        } else{
            return false;
        }
    }
    public static void alert(TableView table, Part selected){
        Alert alert = new Alert(AlertType.CONFIRMATION);
        alert.setTitle("Associated Parts");
        alert.setHeaderText("Do you want to remove this part?");
        alert.setContentText("Remove");
        Optional<ButtonType> result = alert.showAndWait();
        if(result.get() == ButtonType.OK)
        {
            modify.removePart(table, selected);
        }
    }
}

Product

public class Product extends Part{
    private static ObservableList data; // = FXCollections.observableArrayList();
    
    public Product(int id, String name, double price, int stock, int min, int max) 
    {
        super(id, name, price, stock, min, max);
    }
    public Product(int id, String name, double price, int stock, int min, int max, ObservableList firstData) 
    {
        super(id, name, price, stock, min, max);
        this.data = FXCollections.observableArrayList(firstData);
    }
    
    public void setToList(ObservableList addTo)
    {
        this.data = FXCollections.observableArrayList(addTo);
    }
    
    public ObservableList getList()
    {
        return this.data;
    }
    
    public void removePart(TableView table, Part part)
    {
        table.getItems().remove(part);
    }
    
    public boolean check()
    {
        if(data.isEmpty() == true)
        {
            return true;
        } else {
            return false;
        }
    }
}

  • 1
    don't use static scope – kleopatra Aug 25 '21 at 09:01
  • 2
    .. also provide a [mcve] (vs. a dump of excerpted code) demonstrating what's not working as expected. And stick to java naming conventions when showing jva code publicly – kleopatra Aug 25 '21 at 09:34
  • 1
    Why is everything `static`? – James_D Aug 25 '21 at 11:07
  • [Is Java “pass-by-reference” or “pass-by-value”?](https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value). Java **is** _pass-by-value_. But the value passed is the reference to the object. That is to say, the reference is copied (but the old and new references point to the same instance). – Slaw Aug 25 '21 at 23:19

0 Answers0