"Element does not define a default property" 使用@DefaultProperty 时

"Element does not define a default property" when @DefaultProperty is used

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

javafx.fxml.LoadException: Element does not define a default property.

但是,经过一些研究,我相信我正确定义了默认值 属性。

如果我包含 nestedCellValueFactory 标签,一切都会按预期进行。

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>

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

如果您 运行 没有 <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.access0(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>. NestablePropertyValueFactoryvalue 是一个 PropertyValueFactory 对象。

  • 第 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应该是空。

可以通过检查 Class<?> type 来解释发生了什么:

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

所以type不是你的NestablePropertyValueFactoryclass,而是ProxyBuilder.

现在,如果您检查 class 没有 @DefaultProperty 注释,因此 defaultProperty 为空并抛出异常。

此代理创建于javafx.fxml.JavaFXBuilderFactory::getBuilder,基于真实类型:

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

但它 returns 代替了 ProxyBuilder,并且在此过程中 DefaultProperty 注释丢失了。

代理生成器似乎适用于 classes,其构造函数用 @NamedArg 注释,但 不适用于 @DefaultProperty 注释。

虽然这可能是您的 class 的情况,但应该有比简短的异常消息更好的解释。

无论如何,由于构建器在您添加标签并删除默认注释时工作正常,我只考虑删除 @DefaultProperty.