我正在尝试创建用于FXML的自定义JavaFX元素,但是当FXMLLoader试图解析它时,它会抛出一个异常,指出:


  javafx.fxml.LoadException:元素未定义默认属性。


但是,在进行了一些研究之后,我相信我正在正确定义默认属性。

如果我包含nestedCellValueFactory标记,则一切正常。

爪哇

@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);
    }

}


XML文件

<NestablePropertyValueFactory property="outer">
    <NestablePropertyValueFactory property="inner">
        <PropertyValueFactory property="property"/>
    </NestablePropertyValueFactory>
</NestablePropertyValueFactory>

最佳答案

经过一些调试后,我有一个可能的错误解释,但遗憾的是没有解决方案。

如果您没有报告<nestedCellValueFactory>标记而运行,则将收到此异常:

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)


因此,转到FXMLLoader源以跟踪异常,您将发现:


790行:parent.set(value);,其中parentFXMLLoader$InstanceDeclarationElement的实例,类型为<your.package.name>. NestablePropertyValueFactory,而valuePropertyValueFactory对象。
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);
}



可以期望defaultProperty.value()应该是"nestedCellValueFactory",并且将分配值,但是抛出的异常清楚地表明不是这种情况,因此defaultProperty应该为null。

可以通过检查Class<?> type来解释发生的情况:

 type: class com.sun.javafx.fxml.builder.ProxyBuilder


因此,type不是您的NestablePropertyValueFactory类,而是一个ProxyBuilder

现在,如果您检查该类,则没有@DefaultProperty批注,因此defaultProperty为null并引发异常。

该代理基于真实类型在javafx.fxml.JavaFXBuilderFactory::getBuilder中创建:

    if (scanForConstructorAnnotations(type)) {
        builder = new ProxyBuilder(type);
    }


但它会返回ProxyBuilder,并且在此过程中DefaultProperty注释会丢失。

代理构建器似乎旨在用于带有以@NamedArg注释的构造函数的类,而不是用于@DefaultProperty注释的类。

尽管您的课堂可能是这种情况,但比简短的异常消息更好的解释。

无论如何,由于当您添加标签并删除默认注释时,构建器运行良好,所以我只考虑删除@DefaultProperty

09-28 14:05