问题
I am trying to create a custom JavaFX element for use in FXML, but when FXMLLoader
tries to parse it, it throws an exception that states:
javafx.fxml.LoadException: Element does not define a default property.
However, after doing some research, I believe that I am defining the default property properly.
If I include the nestedCellValueFactory
tags, everything works as expected.
Java
@DefaultProperty("nestedCellValueFactory")
public class NestablePropertyValueFactory<S, T> extends PropertyValueFactory<S, T> {
private ObjectProperty<PropertyValueFactory<?, ?>> nestedCellValueFactory;
public NestablePropertyValueFactory(
@NamedArg("property") String property,
@NamedArg("nestedCellValueFactory") PropertyValueFactory<?, ?> nestedCellValueFactory) {
super(property);
this.nestedCellValueFactory = new SimpleObjectProperty<>(this, "nestedCellValueFactory", nestedCellValueFactory);
}
public final ObjectProperty<PropertyValueFactory<?, ?>> nestedCellValueFactoryProperty() {
return nestedCellValueFactory;
}
public final PropertyValueFactory<?, ?> getNestedCellValueFactory() {
return nestedCellValueFactoryProperty().get();
}
public final void setNestedCellValueFactory(PropertyValueFactory<?, ?> nestedCellValueFactory) {
nestedCellValueFactoryProperty().set(nestedCellValueFactory);
}
}
FXML
<NestablePropertyValueFactory property="outer">
<NestablePropertyValueFactory property="inner">
<PropertyValueFactory property="property"/>
</NestablePropertyValueFactory>
</NestablePropertyValueFactory>
回答1:
After some debugging, I have a possible explanation for the error, but sadly not a solution for it.
If you run without the <nestedCellValueFactory>
tags, as you already reported, you will get this exception:
Caused by: javafx.fxml.LoadException: Element does not define a default property.
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2597)
at javafx.fxml.FXMLLoader.access$100(FXMLLoader.java:103)
at javafx.fxml.FXMLLoader$Element.set(FXMLLoader.java:180)
at javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:790)
at javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2823)
So going to the FXMLLoader
sources to track the exception you will find:
Line 790:
parent.set(value);
, whereparent
is an instance ofFXMLLoader$InstanceDeclarationElement
, with type<your.package.name>. NestablePropertyValueFactory
, andvalue
is aPropertyValueFactory
object.Lines 177-183:
public void set(Object value) throws LoadException { ... Class<?> type = this.value.getClass(); DefaultProperty defaultProperty = type.getAnnotation(DefaultProperty.class); if (defaultProperty == null) { throw constructLoadException("Element does not define a default property."); } getProperties().put(defaultProperty.value(), value); }
One could expect that defaultProperty.value()
should be "nestedCellValueFactory"
, and the value will be assigned, but the exception thrown clearly shows that this is not the case, so defaultProperty
should be null.
What happens can be explained by inspecting Class<?> type
:
type: class com.sun.javafx.fxml.builder.ProxyBuilder
So type
is not your NestablePropertyValueFactory
class, but a ProxyBuilder
.
Now, if you check that class there is no @DefaultProperty
annotation, hence defaultProperty
is null and the exception is thrown.
This proxy is created in javafx.fxml.JavaFXBuilderFactory::getBuilder
, based on the real type:
if (scanForConstructorAnnotations(type)) {
builder = new ProxyBuilder(type);
}
but it returns the ProxyBuilder
instead, and in the process the DefaultProperty
annotation gets lost.
The proxy builder seems intended for classes with constructors annotated with @NamedArg
, but not for the @DefaultProperty
annotation.
While this could be the case of your class, there should be a better explanation than the short exception message.
Anyway, as the builder works fine when you add the tags and remove the default annotation, I would just consider removing @DefaultProperty
.
来源:https://stackoverflow.com/questions/43457717/element-does-not-define-a-default-property-when-defaultproperty-is-used