8 Replies Latest reply: May 3, 2012 10:37 AM by 921640 RSS

    Drag&Drop Custom Data?

    921640
      Hello, my fellow JavaFXsians :)

      I'm trying to implement a Drag&Drop of an Object. But, as you could guess, I'm not really successful. I'm being hit with the +"java.lang.IllegalArgumentException: Only serializable objects or ByteBuffer can be used as data with data format [model.jfxwrappers.VezaDjetetaWrapper]"+ exception. Why is this wrong:
      DataFormat dataFormatVDW = new DataFormat("model.jfxwrappers.VezaDjetetaWrapper");  //A Class
      
      ......
      
      myListView.setOnDragDetected(new EventHandler<MouseEvent>() {
      
          @Override
          public void handle(MouseEvent dragEvent) {
              Dragboard db= myListView.startDragAndDrop(TransferMode.COPY);
              ClipboardContent content= new ClipboardContent();
              content.put(dataFormatVDW, db);
              db.setContent(content);
              dragEvent.consume();
          }
      });
      ?

      I've read that the model.jfxwrappers.VezaDjetetaWrapper has to be Serializable, so it is. What am I missing, please?
        • 1. Re: Drag&Drop Custom Data?
          zonski
          You are setting 'db' (i.e. the DragBoard) as the content for your Drag and Drop action? This is not serializable, which I think is why you are getting your error.
          content.put(dataFormatVDW, db);
          I suspect that you don't actually want to do this and you probably want to put some other Object (like the data item of the list cell being dragged) to be the content of the drag.
          • 2. Re: Drag&Drop Custom Data?
            921640
            Oh, I'm embarrassed. :) Yes, that was the error, but now I'm having some other difficulties.

            When I tried D&D after making the appropriate change suggested above, I've got some more exceptions. First it was:
            java.lang.IllegalArgumentException: Could not serialize the data
                 at com.sun.javafx.tk.quantum.QuantumClipboard.putContent(Unknown Source)
                 at javafx.scene.input.Clipboard.setContent(Unknown Source)
                                ...........
                 at java.lang.Thread.run(Thread.java:722)
            Caused by: java.io.NotSerializableException: javafx.beans.property.SimpleObjectProperty
                 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
                 at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
                 at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
                 at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
                 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
                 at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
                 ... 40 more
            but then I've commented out the SimpleObjectProperty (although I've made it's value Serializable as well) and got this exception:
            java.lang.IllegalArgumentException: Could not serialize the data
                 at com.sun.javafx.tk.quantum.QuantumClipboard.putContent(Unknown Source)
                 at javafx.scene.input.Clipboard.setContent(Unknown Source)
                                ...........
                 at java.lang.Thread.run(Thread.java:722)
            Caused by: java.io.NotSerializableException: javafx.beans.property.SimpleStringProperty
                 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
                 at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
                 at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
                 at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
                 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
                 at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
                 ... 40 more
            I'm using JavaFX 2.2b06 and presuming that these properties are indeed Serializable (although I couldn't find a confirmation in the API) don't know what could it be.
            The only change I've made in my code listed above is this:
            content.put(dataFormatVDW, vezeDjetetaList.getSelectionModel().getSelectedItem());
            • 3. Re: Drag&Drop Custom Data?
              csh
              Well, as the exception says: StringProperty is not serializable.

              Try to mark it as transient!

              private transient StringProperty....
              • 4. Re: Drag&Drop Custom Data?
                921640
                Is it possible that Properties are not Serializable? Why?

                I don't see a point in making them transient, because all of my object's properties are JavaFX Beans' Properties. So, I'll be Dragging nothing?
                • 5. Re: Drag&Drop Custom Data?
                  csh
                  It is probably hard to serialize the complete state of a property. There are events, which are added to a property. There are bindings to other properties and so on.
                  If you serialize it and deserialize again you don't really have the same object, unless you can manage to serialize a lot more stuff.

                  Ponder to make normal getters and setters for your properties and mark the JavaFX property as transient. Maybe this helps.
                  • 6. Re: Drag&Drop Custom Data?
                    921640
                    csh wrote:
                    Ponder to make normal getters and setters for your properties and mark the JavaFX property as transient. Maybe this helps.
                    What do you mean exactly by this? Following the JavaFX 2 Beans convention, I do have 3 methods for each Property (ex. StringProperty myStringProperty(), final String getMyString and final void setMyString(String myString) for arbitrary StringProperty myString), and I've tried making JavaFX properties transient, but when I wanted to use the dropped value, the NullPointerException was thrown.
                    • 7. Re: Drag&Drop Custom Data?
                      zonski
                      Making properties transient won't really help. Sure your bean is serializable but you lose all your property values. Not overly useful.

                      Also following the bean convention of using Properties internally and then having get/sets on your bean won't help for true Serialization. It'll help for the psuedo-serialization that is often used for converting beans to XML, etc - this uses Bean introspection to find the getters and setters and calls those to access the properties. In true Java Serialization however, the internal member variables are streamed directly to serialization output and input streams, the getters and setters are ignored. So this approach won't help you here either.

                      One obvious option is to not use properties. Just use a traditional bean with normal attributes. I do this a lot because I am sending data back and forth between client and server so my beans are more or less Data Transfer Objects (DTOs), which is what you are using them for here. If data changes or is edited instead of updating individual properties on a bean, I just load a new bean into the list (i.e. replace the old bean in the 'items' list with the new bean). Properties are great and all, but they don't need to be used in every case and can overly complicate things at time. Like any tool, use appropriately.

                      If you really do want Properties on your Bean then your next best option is probably to define your own serialization.
                      class Person implements Serializable 
                      {
                          private StringProperty firstName;
                          private StringProperty lastName;
                      
                          // getters and setters
                      
                          private void writeObject(ObjectOutputStream out) throws IOException
                          {
                              out.writeObject(firstName.get());
                              out.writeObject(lastName.get());
                          }
                          
                          private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException 
                          {
                              firstName = new SimpleStringProperty((String) in.readObject());
                              lastName = new SimpleStringProperty((String) in.readObject());
                          }
                      }
                      And another option would be to define your own serializable Property classes, which serializes just the 'value' of the property and marks the listener lists as transient.

                      I'm a bit surprised that this is not the default behaviour in JFX anyway so you could consider raising a JIRA for this if it's not in there already.
                      • 8. Re: Drag&Drop Custom Data?
                        921640
                        Hi Zonski,

                        You're right, it's best to just use POJOs. Since I already have them (these Classes with JFX Properties are just wrappers, to make my life easier when working with UI), that was easy.

                        As for the native serialization, @csh might have some good points here, but I too am surprised that it's not implemented. It is hard, yes, but not impossible. Anyway, since there is a way to overcome this inconvenience, and dev team has more pressing issues on mind right now, i will not be filing any JIRA issue concerning this.