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.