简体   繁体   中英

JAXBException: SaveButton nor any of its super class is known to this context

I have read several threads on this subject but none of them seem to answer my specific problem. Inside a package "settings" I have a SettingModel.java class that loads default settings from a default.xml file using jaxb. This works flawlessly. Then, under the same package, inside a sub-package called SettingsWidgets , I have a SaveButton.java class, that has a setOnMouseClick eventListener, triggering a method "saveSettings". The code works partially: current file is overwritten (though with void) or a new (yet empty) xml file is created in the desired package, and I get the error

javax.xml.bind.JAXBException: class settings.settingsWidgets.SaveButton nor any of its super class is known to this context.

I have tried:
creating the JAXBContext in different ways as proposed in several threads here on Stack O. (passing the package as a string and adding jaxb.index and ObjectFactory.java, passing the full classpath instead of just the class,...) To no avail and it seems to me (reading the error) that the problem is not how I pass the SettingsModel class to the context...
The @XmlSeealso workaround too is mentioned often, but I don't immediately see any use of it in my case (it's not that I'm trying to marshal a subclass or smth)
Also tried to refactor SaveButton.java out of the subpackage so it would be on the same level of SettingsModel , but that didn't change anything...
I am quite lost on how and why I should include SaveButton into the jaxbContext and when I try I get lots of errors.


My code:

// SettingsModel.java

@XmlRootElement(name = "robot")
@XmlAccessorType(XmlAccessType.FIELD)
public class SettingsModel implements Observable {

    private boolean valid = true;

    //registered views List
    //annotate as Type Object.Class because JAXB cannot handle interfaces
    @XmlElement(type = Object.class)
    private  ArrayList<InvalidationListener> listenersList;

    //list all variable robot/vehicle specs
    //filename is needed for saving to current or new file
    @XmlElement(name = "filename")
    private String fileName;

    @XmlElement(name = "vehicle-width")
    private double vehicleWidth;

    @XmlElement(name = "work-width")
    private double workWidth;

    // other getters and setters without logic are removed

    public void setValid(boolean valid) {
        if (valid != this.valid) {
            this.valid = valid;

            fireInvalidationEvent();
        }
    }

    public void setVehicleWidth(double vehicleWidth) {
        this.vehicleWidth = vehicleWidth;

        Field.getInstance().getRobot().setVehicleWidth(vehicleWidth);
        fireInvalidationEvent();
    }

    public void setWorkWidth(double workWidth) {
        this.workWidth = workWidth;

        // Field.getInstance().getRobot().setVehicleWidth(vehicleWidth);
        // fireInvalidationEvent();
    }



    //METHODS AND FUNCTIONS
    @Override
    public void addListener(InvalidationListener invalidationListener) {
        listenersList.add(invalidationListener);
    }

    @Override
    public void removeListener(InvalidationListener invalidationListener) {
        listenersList.remove(invalidationListener);
    }

    public void fireInvalidationEvent() {
        for (InvalidationListener listener : listenersList) {
            listener.invalidated(this);
        }
    }
}
// SaveButton.java

public class SaveButton extends Button implements InvalidationListener {

    private SettingsModel model;

    public SaveButton(SettingsModel model) {
        this.model = model;
        model.addListener(this);
        setText("SAVE SETTINGS");
        setOnMouseClicked((ev)->{
            try {
                saveSettings();
            } catch (JAXBException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        });
    }

    private void saveSettings() throws JAXBException, FileNotFoundException {
        String filename = model.getFileName();

        Object[] options = {"Save", "Save As"};

        //choose Save or Save As
        int choice = JOptionPane.showOptionDialog(null,"Overwrite current file or Save As New file?",
                "Save Settings",
                JOptionPane.WARNING_MESSAGE,
                JOptionPane.YES_NO_OPTION,
                null,
                options,
                options[0]
                );

        if(choice != JOptionPane.OK_OPTION){
            filename = JOptionPane.showInputDialog("Enter new file name");
            model.setFileName(filename);
        }

        System.out.println(model.getFileName());

        //Marshal
        JAXBContext jaxbContext = JAXBContext.newInstance(SettingsModel.class);

        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

        //if filename stays same, file is overwritten. Test only SAVE AS until code works to not lose default file
        File file = new File("src/resources/properties/"+ filename + ".xml");

        OutputStream os = new FileOutputStream(file);

        jaxbMarshaller.marshal(model,os);
    }

    @Override
    public void invalidated(Observable observable) {
        System.out.println("button invalidated: "+ model.isValid());

        setDisable(!model.isValid());
    }
}

Stacktrace:

javax.xml.bind.MarshalException
 - with linked exception:
[com.sun.istack.SAXException2: javax.xml.bind.JAXBException: class settings.settingsWidgets.SaveButton nor any of its super class is known to this context.
javax.xml.bind.JAXBException: class settings.settingsWidgets.SaveButton nor any of its super class is known to this context.]
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:301)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:226)
    at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:80)
    at settings.settingsWidgets.SaveButton.saveSettings(SaveButton.java:59)
    at settings.settingsWidgets.SaveButton.lambda$new$0(SaveButton.java:27)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Scene$ClickGenerator.postProcess(Scene.java:3564)
    at javafx.graphics/javafx.scene.Scene$ClickGenerator.access$8200(Scene.java:3492)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3860)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.access$1200(Scene.java:3579)
    at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1849)
    at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2588)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:397)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:434)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:390)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:433)
    at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
    at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.sun.istack.SAXException2: javax.xml.bind.JAXBException: class settings.settingsWidgets.SaveButton nor any of its super class is known to this context.
javax.xml.bind.JAXBException: class settings.settingsWidgets.SaveButton nor any of its super class is known to this context.
    at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:217)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:232)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:623)
    at com.sun.xml.bind.v2.runtime.property.ArrayElementNodeProperty.serializeItem(ArrayElementNodeProperty.java:39)
    at com.sun.xml.bind.v2.runtime.property.ArrayElementProperty.serializeListBody(ArrayElementProperty.java:142)
    at com.sun.xml.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:129)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:329)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:563)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:310)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:464)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:298)
    ... 34 more
Caused by: javax.xml.bind.JAXBException: class settings.settingsWidgets.SaveButton nor any of its super class is known to this context.
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:563)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:618)
    ... 42 more

Process finished with exit code 0

Any insights would be greatly appreciated.

Your SettingsModel has a listenerList marked as an xmlelement. You add the SaveButton to the list in this with this line: model.addListener(this);

So, when marshalling the SettingsModel, JAXB processes the listenerList and tries to marshall the SaveButton, but it doesn't know how to do it.

Adding a @XmlRootElement annotation to your SaveButton class should be enough.

Besides, I see that you create a JAXBContext every time the button is clicked. The JAXB spec says:

To avoid the overhead involved in creating a JAXBContext instance, a JAXB application is encouraged to reuse a JAXBContext instance. An implementation of abstract class JAXBContext is required to be thread-safe, thus, multiple threads in an application can share the same JAXBContext instance.

You should move JAXBContext to an static field, as the instance can be reused.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM