9 Replies Latest reply: Apr 12, 2013 4:39 PM by David Grieve RSS

    Reading/Writing files, is there a special case in FX?

    KonradZuse
      Okay so I am basically asking if we can read files in any specific way. Normally I know to read a file by seralizing and writing out each item, and then reading them in, in the same exact order.

      Now I'm curious is there a way I could lets say


      Write 5 boxes, then 5 circles, but read it in as 5 circles, then 5 boxes? I'm essentially asking is there a way to read it in, in any order?


      Like lets say I am reading a file, but only want to know the object heights, or another property, without having to read in the entire file?


      Any help or insight would be appreciated, I'm not sure if I will really "NEED" this, but I'm curious how it all works internally :D.

      ~KZ
        • 1. Re: Reading/Writing files, is there a special case in FX?
          David Grieve
          I think you'd have to roll you own for this one. Maybe serialize the data as a btree on disk. Have your own little RDBMS.
          • 2. Re: Reading/Writing files, is there a special case in FX?
            KonradZuse
            Yeah, I rather not have to use ORM or RDBMS.... I think I'll just use the normal seralization/deserialization(or does FX use something else)?
            • 3. Re: Reading/Writing files, is there a special case in FX?
              David Grieve
              Node is not serializable. Or are you talking about FXML? Either way, there isn't anything special in FX for reading and writing files.
              • 4. Re: Reading/Writing files, is there a special case in FX?
                KonradZuse
                Just normal FX... Also why is node not serializable? I have a class that extends a MeshView, not too sure if that would work then....

                ALso is there a way to auto-update something once deserialized. Like lets say I changed an imagepath in the file and then wanted to auto-update from it. Is there a way to say if this object != this, then reread the stream at an instance?
                • 5. Re: Reading/Writing files, is there a special case in FX?
                  James_D
                  There's also an XMLEncoder and an XMLDecoder class (in java.beans) which can persist objects that conform to the JavaBeans convention in an XML format. I've never used this (I don't think anyone has...) but the Node classes pretty much conform to JavaBeans conventions, so you might be able to use them. Some other classes like Color don't seem to work, here's a (very crude) example. (Run it, create some shapes, hit save, exit, run again, hit load...).

                  Though, really, you shouldn't be persisting your view. You really want to persist the data that is presented in the view, and then reload the data.
                  import java.beans.XMLDecoder;
                  import java.beans.XMLEncoder;
                  import java.io.BufferedInputStream;
                  import java.io.BufferedOutputStream;
                  import java.io.FileInputStream;
                  import java.io.FileNotFoundException;
                  import java.io.FileOutputStream;
                  import javafx.application.Application;
                  import javafx.beans.property.ObjectProperty;
                  import javafx.beans.property.SimpleObjectProperty;
                  import javafx.event.ActionEvent;
                  import javafx.event.EventHandler;
                  import javafx.geometry.Point2D;
                  import javafx.scene.Node;
                  import javafx.scene.Scene;
                  import javafx.scene.control.Button;
                  import javafx.scene.input.MouseEvent;
                  import javafx.scene.layout.BorderPane;
                  import javafx.scene.layout.HBox;
                  import javafx.scene.layout.Pane;
                  import javafx.scene.paint.Color;
                  import javafx.scene.shape.Circle;
                  import javafx.scene.shape.Rectangle;
                  import javafx.scene.shape.Shape;
                  import javafx.stage.Stage;
                  
                  public class XMLEncoderTest extends Application {
                  
                    public final static String FILENAME = "shapes.xml";
                  
                    @Override
                    public void start(Stage primaryStage) {
                      final BorderPane root = new BorderPane();
                      final Pane shapeHolder = new Pane();
                      final HBox controls = new HBox(5);
                      final Button rectButton = new Button("Rectangle");
                      final Button circleButton = new Button("Circle");
                      final Button loadButton = new Button("Load");
                      final Button saveButton = new Button("Save");
                      controls.getChildren().addAll(rectButton, circleButton, loadButton,
                          saveButton);
                      root.setTop(controls);
                      root.setCenter(shapeHolder);
                  
                      rectButton.setOnAction(new EventHandler<ActionEvent>() {
                        @Override
                        public void handle(ActionEvent event) {
                          final Rectangle rectangle = new Rectangle(50, 50, 200, 100);
                          rectangle.setFill(Color.AQUAMARINE);
                          addShape(shapeHolder, rectangle);
                        }
                      });
                  
                      circleButton.setOnAction(new EventHandler<ActionEvent>() {
                        @Override
                        public void handle(ActionEvent event) {
                          addShape(shapeHolder, new Circle(100, 150, 150, Color.ALICEBLUE));
                        }
                      });
                  
                      loadButton.setOnAction(new EventHandler<ActionEvent>() {
                        @Override
                        public void handle(ActionEvent event) {
                          XMLDecoder decoder;
                          try {
                            decoder = new XMLDecoder(new BufferedInputStream(new FileInputStream(
                                FILENAME)));
                            // this is horrible, but I can't figure out a nice way to know how
                            // many shapes are in the file
                            try {
                              while (true) {
                                final Node node = (Node) decoder.readObject();
                                registerHandlers(node);
                                shapeHolder.getChildren().add(node);
                              }
                            } catch (ArrayIndexOutOfBoundsException e) {
                              decoder.close();
                            }
                          } catch (FileNotFoundException e) {
                            e.printStackTrace();
                          }
                        }
                      });
                  
                      saveButton.setOnAction(new EventHandler<ActionEvent>() {
                        @Override
                        public void handle(ActionEvent event) {
                          try {
                            XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(
                                new FileOutputStream(FILENAME)));
                            for (Node node : shapeHolder.getChildren()) {
                              encoder.writeObject(node);
                            }
                            encoder.close();
                          } catch (FileNotFoundException e) {
                            e.printStackTrace();
                          }
                        }
                      });
                  
                      primaryStage.setScene(new Scene(root, 800, 800));
                      primaryStage.show();
                  
                    }
                  
                    private void addShape(Pane container, final Shape shape) {
                      registerHandlers(shape);
                      container.getChildren().add(shape);
                    }
                  
                    private void registerHandlers(final Node shape) {
                      final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>();
                      shape.setOnMousePressed(new EventHandler<MouseEvent>() {
                        @Override
                        public void handle(MouseEvent event) {
                          mouseAnchor.set(new Point2D(event.getX(), event.getY()));
                        }
                      });
                      shape.setOnMouseDragged(new EventHandler<MouseEvent>() {
                        @Override
                        public void handle(MouseEvent event) {
                          shape.setTranslateX(shape.getTranslateX() + event.getX()
                              - mouseAnchor.get().getX());
                          shape.setTranslateY(shape.getTranslateY() + event.getY()
                              - mouseAnchor.get().getY());
                        }
                      });
                    }
                  
                    public static void main(String[] args) {
                      launch(args);
                    }
                  }
                  • 6. Re: Reading/Writing files, is there a special case in FX?
                    KonradZuse
                    Last time I did this I believe I just imported/exported the data of the classes themselves, and then put the data where it needed to be, I was thinking I might just be able to serialize the entire object.


                    the only thing I really would need is a "Triangle Mesh" for the Meshview...


                    Also just to clarify(since people on the Coderanch don't like to) JavaBean "convention" is using the getting/setter methods and making a "bean" class? Grabbing data in the construction, calling it, etc etc?

                    Edited by: KonradZuse on Apr 10, 2013 4:17 PM
                    • 7. Re: Reading/Writing files, is there a special case in FX?
                      David Grieve
                      The beans convention carries over to JavaFX is that the properties follow a standard naming convention and have getters and setters. For example, Node has an 'opacity' property so there is a getOpacity and setOpacity. Plain old java beans are also required to have a default, no-arg constructor and are required to be serializable - neither of which are enforced in JavaFX.
                      • 8. Re: Reading/Writing files, is there a special case in FX?
                        KonradZuse
                        Ah, it's so great when someone actually answered a question instead of tearing apart your Q's :).

                        Thanks again David!


                        Also I was checking out this site, and #2 came as a surprise to me http://www.ibm.com/developerworks/library/j-5things1/


                        I thought that serialization cannot be decrypted/deserialized without having the SerialUID being the same? It seems that we can do a lot of hardcore encryption if we use "WriteObject" and "ReadObject" but there seems to be a few others things I've noticed such as
                         registerValidation(ObjectInputValidation obj, int prio) 
                                  Register an object to be validated before the graph is returned. 
                        http://docs.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html

                        Not too sure what the "Graph" in this case is since this is Java.io and not anything having to do with FX's Scene Graphs...


                        Also ReadObject vs ReadObjectDefault the latter says
                         defaultReadObject() 
                                  Read the non-static and non-transient fields of the current class from this stream.
                        Now would it be wiser to use the default, or should readObject just be used? I don't have any transient fields right now, nor do I have anything static at the moment.


                        Also I'm a little confused on http://docs.oracle.com/javase/6/docs/api/java/io/Externalizable.html

                        It seems as if you can replace certain things with other things using this interface/ Not too sure what the point of that is, so am I missing something?

                        Edited by: KonradZuse on Apr 12, 2013 1:11 PM
                        • 9. Re: Reading/Writing files, is there a special case in FX?
                          David Grieve
                          Sorry for picking apart your question, but I think this is a more general java question than javafx in particular. I suggest you take the conversation to one of the other Java forums (https://forums.oracle.com/forums/category.jspa?categoryID=285).

                          In short, though, you'd use write/readObject to achieve serialization if you want to use java serialization. FWIW, I wrote the code that serializes css files to a binary format using only BinaryOutStream (and BinaryInputStream for deserializing). So you don't have to use java serialization.

                          I'm still trying to figure out why you want to do this.