nberlijn
nberlijn

Reputation: 323

JAXB update XML elements

I got two XML files for a JavaFX desktop application that needs to be created and updated. After some research I found JAXB an easy parser for this job.

Now reading works fine, but when I try to update XML elements it throws an exception:

Exception in thread "main" java.io.FileNotFoundException: \storage\device.xml (The system cannot find the path specified)

I tried also to work with properties files, but that feels not corresponding for the hierarchical structure I need.

Is JAXB not the way to go for updating existing elements inside XML files, or do I need to use the DOM parser in this situation?

Now I'm already struggling for hours without any solution. I use maven and XML files are stored in the storage folder inside the resources folder. See the code examples below for more information.

All feedback, suggestions or any other solution (other storage solution?) for solving this problem etc are welcome.

Maybe you know some better solution for handling the two XML files?

Thank you in advance!

DeviceDemo.java

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class DeviceDemo {

    public static void main(String[] args) throws Exception {
        // Initialize
        String file = "/storage/device.xml";
        JAXBContext jaxbContext = JAXBContext.newInstance(Device.class);

        // Read
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        InputStream inputStream = DeviceDemo.class.getResourceAsStream(file);
        Device device = (Device) unmarshaller.unmarshal(inputStream);
        inputStream.close();

        // Update
        device.setName("Updated name");
        device.setHost("Updated host");
        device.setPort(2302);

        Marshaller marshaller = jaxbContext.createMarshaller();
        OutputStream outputStream = new FileOutputStream(file);
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(device, outputStream);
        outputStream.close();
    }

}

Device

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "device")
@XmlType(propOrder = {
        "name",
        "host",
        "port"
})
public class Device {

    private String name;
    private String host;
    private Integer port;

    public String getName() {
        return name;
    }

    @XmlElement(name = "name")
    public void setName(String name) {
        this.name = name;
    }

    public String getHost() {
        return host;
    }

    @XmlElement(name = "host")
    public void setHost(String host) {
        this.host = host;
    }

    public Integer getPort() {
        return port;
    }

    @XmlElement(name = "port")
    public void setPort(Integer port) {
        this.port = port;
    }

    @Override
    public String toString() {
        return name + " " + host + " " + port;
    }

}

Device.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<device>
    <name>Device</name>
    <host>host.com</host>
    <port>80</port>
</device>

CommandsDemo.java

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

public class CommandsDemo {

    public static void main(String[] args) throws Exception {
        // Initialize
        String file = "/storage/commands.xml";
        JAXBContext jaxbContext = JAXBContext.newInstance(Commands.class);

        // Read
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        InputStream inputStream = CommandsDemo.class.getResourceAsStream(file);
        Commands commands = (Commands) unmarshaller.unmarshal(inputStream);
        inputStream.close();

        // Print all commands
        List<Command> commandsList = commands.getCommands();

        for (Command command : commandsList) {
            System.out.println(command.toString());
        }

        // Update a specific command
        for (Command command : commandsList) {
            if (command.getName().equals("Power on")) {
                command.setName("Updated name");
                command.setHost("Updated host");
                command.setUser("Updated user");
                command.setPassword("Updated password");
                command.setTimeout(3439);
                command.setPort(33223);
                command.setCommand("Updated command");

                Marshaller marshaller = jaxbContext.createMarshaller();
                OutputStream outputStream = new FileOutputStream(file);
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                marshaller.marshal(command, outputStream);
                outputStream.close();
            }
        }
    }

}

Commands.java

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;

@XmlRootElement(name = "commands")
public class Commands {

    private List<Command> commands;

    public List<Command> getCommands() {
        return commands;
    }

    @XmlElement(name = "command")
    public void setCommands(List<Command> commands) {
        this.commands = commands;
    }

    @Override
    public String toString() {
        return commands.toString();
    }

}

Command.java

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "command")
@XmlType(propOrder = {
        "name",
        "host",
        "user",
        "password",
        "port",
        "timeout",
        "command"
})
public class Command {

    private String name;
    private String host;
    private String user;
    private String password;
    private Integer port;
    private Integer timeout;
    private String command;

    public String getName() {
        return name;
    }

    @XmlElement(name = "name")
    public void setName(String name) {
        this.name = name;
    }

    public String getHost() {
        return host;
    }

    @XmlElement(name = "host")
    public void setHost(String host) {
        this.host = host;
    }

    public String getUser() {
        return user;
    }

    @XmlElement(name = "user")
    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return password;
    }

    @XmlElement(name = "password")
    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getPort() {
        return port;
    }

    @XmlElement(name = "port")
    public void setPort(Integer port) {
        this.port = port;
    }

    public Integer getTimeout() {
        return timeout;
    }

    @XmlElement(name = "timeout")
    public void setTimeout(Integer timeout) {
        this.timeout = timeout;
    }

    public String getCommand() {
        return command;
    }

    @XmlElement(name = "command")
    public void setCommand(String command) {
        this.command = command;
    }

    @Override
    public String toString() {
        return name + " " + host + " " + user + " " + password + " " + port + " " + timeout + " " + command;
    }

}

Commands.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<commands>
    <command>
        <name>Power on</name>
        <host>host.com</host>
        <user>user</user>
        <password>password</password>
        <port>22</port>
        <timeout>10000</timeout>
        <command>power on commando</command>
    </command>
    <command>
        <name>Power off</name>
        <host>host.com</host>
        <user>user</user>
        <password>password</password>
        <port>22</port>
        <timeout>10000</timeout>
        <command>power off command</command>
    </command>
</commands>

Upvotes: 0

Views: 5333

Answers (1)

Roger Gustavsson
Roger Gustavsson

Reputation: 1709

When you load your XML file, you are using getResourceAsStream. This will look for your file /storage/device.xml relative to the location of your class file, or perhaps the current directory. I can't remember exactly at the moment.

When you try to save the file, you're using FileOutputStream with the same name, /storage/device.xml. In this case it will be relative to the root of your file system. If you don't have a directory /storage there, the system can't save your file.

Example DeviceDemo

public class DeviceDemo {
    public static void main(String[] args) throws Exception {
        // Initialize
        // On unix this will result in the equivalent of $HOME/.powercontrol/storage/device.xml
        Path file = Paths.get(System.getProperty("user.home"), ".powercontrol", "storage", "device.xml");
        JAXBContext jaxbContext = JAXBContext.newInstance(Device.class);

        // Read
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        InputStream inputStream = new FileInputStream(file.toFile);
        Device device = (Device) unmarshaller.unmarshal(inputStream);
        inputStream.close();

        // Update
        device.setName("Updated name");
        device.setHost("Updated host");
        device.setPort(2302);

        // Write
        Marshaller marshaller = jaxbContext.createMarshaller();
        OutputStream outputStream = new FileOutputStream(file.toFile);
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(device, outputStream);
        outputStream.close();
    }
}

Upvotes: 1

Related Questions