XML JAXB marshall not saving to xml file

Zieryn :

I have a javafx program that brings up a filechooser to allow a user to pick and image an display it to a grid view with an inserted caption that pops up after an image was pciked. I save both the filepath and the caption to different arraylists [for now] and my goal is to save both to xml file so that I can unmarshall it when the application is re opened so the images would still be there. Right now I just want to be able to save the two strings to an xml file and then figure out the rest later. I am currently able to run my code with no errors until I reach my stop method where I try to save every image and caption the user has added to the array lists.

My JAXB Annotation:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ImageCap {
    private String filePath;
    private String caption;

    public ImageCap() {
    }

    public ImageCap(String filePath, String caption) {
        this.filePath = filePath;
        this.caption = caption;
    }

    @Override
    public String toString() {
        return "ImageCap{" + "filePath=" + filePath + ", caption=" + caption + '}';
    }

    public String getFilePath() {
        return filePath;
    }

    @XmlElement
        public void setFilePath(String filePath) {
            this.filePath = filePath;
        }

      public String getCaptions() {
            return caption;
        }

      @XmlElement
        public void setCaption(String caption) {
            this.caption = caption;
        }

    }

And my main to test:

public static void main(String[] args) {launch(args);}

  public void start(Stage primaryStage) throws JAXBException{

  final JFXPanel bananarama = new JFXPanel();

  //import the library (read))

  // create the (initial) display
  display.makeBrowseButton(primaryStage);
  display.createDisplay(primaryStage);

  // show user
  primaryStage.show();



}@Override
public void stop() throws JAXBException{
  File file = new File("file.xml");
  JAXBContext jaxbContext = JAXBContext.newInstance(ImageCap.class);
  Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

//this.context = JAXBContext.newInstance(ImageCap.class);
  //Marshaller marshaller = context.createMarshaller();
  for(int i = 0; i < display.filePaths.size(); i++)
{
  ImageCap imageCap = new ImageCap();

   imageCap.setFilePath(display.filePaths.get(i));
   imageCap.setCaption(display.captions.get(i).toString());

System.out.println(display.filePaths.get(i).toString());
   try {

   // output pretty printed
   jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

   jaxbMarshaller.marshal(imageCap, file);


       } catch (JAXBException e) {
   e.printStackTrace();
       }

  }
}



Here are my errors after the stop command:

    this problem is related to the following location:
        at public void ImageCap.setCaption(java.lang.String)
        at ImageCap
    this problem is related to the following location:
        at private java.lang.String ImageCap.caption
        at ImageCap
    Class has two properties of the same name "filePath"
    this problem is related to the following location:
        at public java.lang.String ImageCap.getFilePath()
        at ImageCap
    this problem is related to the following location:
        at private java.lang.String ImageCap.filePath
        at ImageCap

but it specically cuts off at line 81 which is: JAXBContext jaxbContext = JAXBContext.newInstance(ImageCap.class);

any ideas why?

Marco R. :

If you have getter and setters for a field of the same name, then you need to use XmlAccessType.PROPERTY rather than XmlAccessType.FIELD:

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.PROPERTY)
    public static class ImageCap {
        private String filePath;
        private String caption;

...

Also, another problem that you will encounter is that you misspelled getCaptions() as plural, when it should be getCaption(). JAXB will complain about it as well.

Finally, by marshaling your file inside the loop, you are rewriting over and over the same file with the currently processed imageCap. If what you want is to marshall all imageCaps you need to put them on a List and marshall the List instead. In order to do that you'd need a new JAXB model class like:

    @XmlRootElement(name = "myImageCapList")
    class ImageCapList {
        @XmlElement
        List<ImageCap> imageCap;

        public ImageCapList() {}

        public ImageCapList(List<ImageCap> imageCaps) {
            this.imageCap = imageCaps;
        }
    }

and you'd need to create an instance of this object wrapping your list of ImageCap objects (List<ImageCap>) and use it as the target to invoke the jaxbMarshaller.marshal method as shown in the following method:

    public void imageCapsMarshal(List<ImageCap> imageCaps, File outFile) {
        try {
            jaxbMarshaller.marshal(new ImageCapList(imageCaps), outFile);
        } catch (JAXBException e) {
            // HANDLE EXCEPTIONS
        }
    }

also, you'll need to instantiate your JAXBContext appropriately:

    jaxbContext = JAXBContext.newInstance(ImageCapList.class);

The following is a complete working demo of this for you to play with:

import java.io.File;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

public class JAXBMarshall {

    private JAXBContext jaxbContext;
    private Marshaller jaxbMarshaller;

    public JAXBMarshall() throws JAXBException {
        jaxbContext = JAXBContext.newInstance(ImageCapList.class);
        jaxbMarshaller = jaxbContext.createMarshaller();
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    }

    public void imageCapsMarshal(List<ImageCap> imageCaps, File outFile) {
        try {
            jaxbMarshaller.marshal(new ImageCapList(imageCaps), outFile);
        } catch (JAXBException e) {
            // HANDLE EXCEPTIONS
        }
    }


    public static void main(String[] args) throws JAXBException {
        JAXBMarshall jaxbMarshaller = new JAXBMarshall();

        File file = new File("file.xml");
        List<ImageCap> imageCaps = IntStream.range(0, 10)
                .mapToObj(idx -> new ImageCap("my/file/path/" + idx, idx + ". The Caption!"))
                .collect(Collectors.toList());
        jaxbMarshaller.imageCapsMarshal(imageCaps, file);
    }

    @XmlRootElement(name = "myImageCapList")
    static class ImageCapList {
        @XmlElement
        List<ImageCap> imageCap;

        public ImageCapList() {}

        public ImageCapList(List<ImageCap> imageCaps) {
            this.imageCap = imageCaps;
        }
    }

    @XmlRootElement
    static class ImageCap {
        @XmlElement
        String filePath;

        @XmlElement
        String caption;

        public ImageCap() {}

        public ImageCap(String filePath, String caption) {
            this.filePath = filePath;
            this.caption = caption;
        }

        @Override
        public String toString() {
            return "ImageCap{" + "filePath=" + filePath + ", caption=" + caption + '}';
        }
    }
}

Complete code on GitHub

Hope this helps.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=100376&siteId=1