SQLAlchemy фильтр in_ оператор

Аннотация @NamedArg позволяет FXMLLoader создавать экземпляр класса, у которого нет конструктора с нулевым аргументом.

Техническая информация:

Создает объекты FXMLLoader используя отражение. Как правило, если вы используете тег, соответствующий классу с конструктором без аргументов, объект создается из этого класса, вызывая Class.newInstance(), который вызывает конструктор без аргументов.

Если класс определяется только конструкторами, которые принимают параметры, то это проблематично. Основная проблема заключается в том, что Java Language Specification не требует, чтобы имена параметров (для методов или конструкторов) сохранялись во время выполнения. Это означает, что для FXMLLoader для определения того, какой параметр имеет заданное имя, нет прямого и гарантированного способа.

Чтобы сделать это конкретным, предположим, что мы определяем класс Person следующим образом:

package application;

import javafx.beans.NamedArg;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Person {
    private final StringProperty firstName ;
    private final StringProperty lastName ;

    public Person(String firstName, String lastName) {
        this.firstName = new SimpleStringProperty(this, "firstName", firstName);
        this.lastName = new SimpleStringProperty(this, "lastName", lastName);
    }

    // methods....

}

В FXML мы можем попытаться создать Person следующим образом:


Это не сработает, потому что загрузчик FXML не гарантирует, что представление времени выполнения Person сохраняет информацию о том, какой параметр конструктора firstName и который lastName.

Историческая справка

Java 2.2 определяет классы «Builder», соответствующие каждому элементу управления. Эти классы-строители следуют стандартным шаблонам-строителям. Когда FXMLLoader встречает тег, ссылающийся на класс без конструктора с нулевым аргументом, он будет использовать соответствующий конструктор для создания экземпляра.

К сожалению, реализация классов построителя была ошибочной, а они устарели в JavaFX 8 и будут удалены в более поздней версии (возможно, JavaFX 9). Это оставило проблему для FXMLLoader, у которой больше не было бы классов-конструкторов, для которых можно было бы использовать экземпляры классов без конструктора с нулевым аргументом. Реальный пример - это класс Color , у которого нет конструктора с нулевым аргументом и будет удалена его класс строителя.

@NamedArgs

Исправить это - ввести аннотацию, которая используется для сохранения имени аргумента метода (или конструктора) во время выполнения. Посредством отражения мы можем запросить список параметров конструктора / метода и получить тип (но не имя) каждого параметра. Также возможно запросить каждый параметр для любых аннотаций и получить значение этих аннотаций. Таким образом, аннотация @NamedArg была введена специально для того, чтобы сохранить имя параметра во время выполнения.

Пример

В качестве примера используйте класс Person, который мы ввели выше :

package application;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Person {
    private final StringProperty firstName ;
    private final StringProperty lastName ;

    public Person(String firstName, String lastName) {
        this.firstName = new SimpleStringProperty(this, "firstName", firstName);
        this.lastName = new SimpleStringProperty(this, "lastName", lastName);
    }

    public final StringProperty firstNameProperty() { return firstName; }
    public final String getFirstName() { return firstNameProperty().get(); }
    public final void setFirstName(final String firstName) { firstNameProperty().set(firstName); }
    public final StringProperty lastNameProperty() { return lastName; }
    public final String getLastName() { return lastNameProperty().get(); }
    public final void setLastName(final String lastName) { lastNameProperty().set(lastName); }
}

Если вы попытаетесь загрузить это с помощью FXML:

Person.fxml:




Main.java:

package application;

import java.io.IOException;
import javafx.fxml.FXMLLoader;

public class Main  {

    public static void main(String[] args) throws IOException {     
        Person person = FXMLLoader.load(Main.class.getResource("Person.fxml"));
        System.out.println(person.getFirstName()+" "+person.getLastName());
    }
}

, тогда вы увидите ошибку во время выполнения:

Caused by: java.lang.NoSuchMethodException: application.Person.()

, указывающее, что FXMLLoader ищет конструктор, не принимающий аргументов (Person.()).

В JavaFX 8, вы можете исправить проблему, указав имя параметров с помощью аннотации @NamedArg:

package application;

import javafx.beans.NamedArg;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Person {
    private final StringProperty firstName ;
    private final StringProperty lastName ;

    public Person(@NamedArg("firstName") String firstName, @NamedArg("lastName") String lastName) {
        this.firstName = new SimpleStringProperty(this, "firstName", firstName);
        this.lastName = new SimpleStringProperty(this, "lastName", lastName);
    }

    public final StringProperty firstNameProperty() { return firstName; }
    public final String getFirstName() { return firstNameProperty().get(); }
    public final void setFirstName(final String firstName) { firstNameProperty().set(firstName); }
    public final StringProperty lastNameProperty() { return lastName; }
    public final String getLastName() { return lastNameProperty().get(); }
    public final void setLastName(final String lastName) { lastNameProperty().set(lastName); }
}

Это позволит FXMLLoader загружать класс по мере необходимости.

Обратите внимание, что вы также можете исправить эту проблему, указав класс строителя, и это также работает в JavaFX 2.0 и более поздних версиях. Команда JavaFX решила (возможно, правильно), что использование этого подхода таким образом, чтобы не страдать от ошибок, существовавших в первоначальной реализации сборщиков, добавило бы слишком много раздувания в кодовую базу.

package application;

public class PersonBuilder {

    private String firstName ;
    private String lastName ;

    private PersonBuilder() {   }

    public static PersonBuilder create() {
        return new PersonBuilder();
    }

    public PersonBuilder firstName(String firstName) {
        this.firstName = firstName ;
        return this ;
    }

    public PersonBuilder lastName(String lastName) {
        this.lastName = lastName ;
        return this ;
    }

    public Person build() {
        return new Person(firstName, lastName);
    }
}

Очевидно, что если вы используете JavaFX 8, подход аннотации конструктора гораздо меньше работает.

Ссылки:

17
задан M.javid 26 May 2015 в 08:38
поделиться