FXMLLoader在使用Spring应用程序上下文

时间:2018-03-08 19:10:17

标签: java spring nullpointerexception applicationcontext fxmlloader

我使用Spring来管理我的控制器实例,使用setControllerFactory(见下文),使控制器能够通过自动装配EntityManagerFactory和处理数据库事务来关心实体的持久性。这种方法适用于我迄今为止开发的其他几种控制器。但是,最近我想扩展功能并复制现有的工作控制器脚手架,将其采用到具有相应FXML UI的不同实体。无论出于何种原因,我无法使其发挥作用。发生的事情是控制器被实例化并调用控制器初始化方法,而没有任何声明的FMXL成员被预先注入 - 我调试它,它们都是空的。因此初始化会抛出NullPointerException。如果我评论setControllerFactory行和所有持久的相关命令,它工作正常,但我没有毅力。我花了一个小时来比较工作示例和新工作示例,但找不到根本原因。

请查看以下代码段

实体类

@Entity
@Inheritance
@Access(AccessType.FIELD)
public abstract class Term implements Serializable {

    @Transient
    private transient final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final long serialVersionUID = -5585030750290575696L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;    

    private String identifier;  
    private String goal = "tbd.";       // what shall be achieved in the given time frame
    @OneToOne
    private Term predecessor;
    @OneToOne
    private Term successor;
    private int myNumber; // order within release

    private int version;
    private LocalDateTime publishingDate;
    private String owner;

    /*
     * Note: Use Period.between(begin, end).getUnits() to determine the years, months, days, hours between begin and end
     */
    private LocalDate begin;
    private LocalDate end;
    @Transient
    private transient DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(Locale.GERMAN);

    /*
     * Terms are structured in hierarchical levels as defined by the following finals
     */
    public final static String RELEASE = "Release"; // top level
    public final static String PHASE = "Phase"; // 
    public final static String BASELINE = "Baseline";
    public final static String ITERATION = "Iteration";
    public final static String TASK = "Task";   // bottom level
    @Transient
    public final static transient ArrayList<String> levels = 
    new ArrayList<String>(Arrays.asList(RELEASE, PHASE, BASELINE, ITERATION, TASK));

    @Transient
    public transient static ObservableList<String> chronoUnits =  FXCollections.observableArrayList(
            EffortEstimate.YEARS, EffortEstimate.MONTHS, EffortEstimate.WEEKS, EffortEstimate.DAYS, EffortEstimate.HOURS);

    public abstract String getLevel(); // return one of the above values indicating the hierarchical level
    protected String defaultTimeUnit;


    /*
     * A Term may be broken down into sub-Terms, called children. A child can not be a Term from a higher hierarchical level.
     * Between parent and child is a bi-directional relationship
     */
    @ManyToOne
    private Term parent;

    @Transient
    private List<Term> children;
    @Transient
    private transient ObservableList<Term> observableChildren = FXCollections.observableArrayList();    // an observable mirror of field children

    /*
     * If a requirement should be implemented during a certain time, but it is unclear by which team, then the
     * requirement may be temporarily assigned to a term. 
     */
    @Transient
    private List<UserRequirement> userRequirements;
    @Transient
    private transient final ListProperty<UserRequirement> observableRequirements = new SimpleListProperty<>(FXCollections.observableArrayList());



    public enum Type {
        Development, Hardening
    }
    @Enumerated(EnumType.STRING)
    protected Type myType;  // see enum Type

    public enum Status {
        Setup, Upcoming, Running, Complete
    }
    @Enumerated(EnumType.STRING)
    protected Status myState;   // see enum Status



    protected Term() {
        children = FXCollections.observableArrayList();
        userRequirements = FXCollections.observableArrayList();
        publishingDate = LocalDateTime.now();
        myState = Status.Setup;
        myType = Type.Development;
    }

    public Term(Term parent, String identifier) {
        this();
        setIdentifier(identifier);
        setParent(parent);
    }

    private Long getId() {
        return id;
    }

    private void setId(Long id) {
        this.id = id;
    }


    public Term getParent() {
        return parent;
    }

    public void setParent(Term parent) {
        this.parent = parent;
    }

    public ObservableList<Term> getObservableChildren() {
        return observableChildren;
    }

    @Access(AccessType.PROPERTY)
    @OneToMany(mappedBy="parent", orphanRemoval = true, cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
    private List<Term> getChildren() {
        return children;
    }

    @SuppressWarnings("unused")     // Used by JPA
    private void setChildren(List<Term> children) {
        this.children = children;
        observableChildren.setAll(FXCollections.observableArrayList(children));
    }

    public void addChild(Term child) {
        children.add(child);
        observableChildren.add(child);
        Term currentParent = child.getParent();
        if(currentParent != null) {
            currentParent.delChild(child);
        }
        child.setParent(this);
    }

    public boolean delChild(Term child) {
        child.setParent(null);
        observableChildren.remove(child);

        return children.remove(child);  
    }


    public String getIdentifier() {
        return identifier;
    }

    public void setIdentifier(String identifier) {
        this.identifier = identifier;
    }

    public String getGoal() {
        return goal;
    }

    public void setGoal(String goal) {
        this.goal = goal;
    }

    public Term getPredecessor() {
        return predecessor;
    }

    public void setPredecessor(Term predecessor) {
        this.predecessor = predecessor;
    }

    public Term getSuccessor() {
        return successor;
    }

    public void setSuccessor(Term successor) {
        this.successor = successor;
    }

    public LocalDate getBegin() {
        return begin;
    }

    public void setBegin(LocalDate begin) {
        this.begin = begin;
    }

    public LocalDate getEnd() {
        return end;
    }

    public void setEnd(LocalDate end) {
        this.end = end;
    }

    public String getDefaultTimeUnit() {
        return defaultTimeUnit;
    }

    public void setDefaultTimeUnit(String defaultTimeUnit) {
        this.defaultTimeUnit = defaultTimeUnit;
    }


    public ObservableList<UserRequirement> getObservableRequirements() {    
        return observableRequirements;
    }


    /*
    public ListProperty<UserRequirement> observableRequirementsProperty() {
        return observableRequirements;
    }
    */

    @Access(AccessType.PROPERTY)
    @OneToMany(mappedBy="term", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    private List<UserRequirement> getRequirements() {
        return userRequirements;
    }

    @SuppressWarnings("unused")     // Used by JPA
    private void setRequirements(List<UserRequirement> userRequirements) {

        //logger.debug(userRequirements.size() + " reqs to " + this.debug());

        this.userRequirements = userRequirements;
        if(userRequirements != null) {
            observableRequirements.clear();
            for(UserRequirement req: userRequirements) {
                observableRequirements.add(req);
            }
        }
        observableRequirements.setAll(FXCollections.observableList(userRequirements)); 
    }

    public void addRequirement(UserRequirement userRequirement) {

        logger.debug(userRequirement.debug() + " to " + this.debug());

        userRequirements.add(userRequirement);
        observableRequirements.add(userRequirement);
        userRequirement.setTerm(this);
    }

    public void delRequirement(UserRequirement userRequirement) {

        logger.debug(userRequirement.debug() + " from " + this.debug());

        if(userRequirements.contains(userRequirement)) {
            if(!userRequirements.remove(userRequirement)) {
                logger.error("Removal of requirement from list failed! Term: " + this.toString());
            }
            if(!observableRequirements.remove(userRequirement)) {
                logger.error("Removal of requirement from observable list failed! Term: " + this.toString());
            }

            userRequirement.setTerm(null);
        }
    }


    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }


    public LocalDateTime getPublishingDate() {
        return publishingDate;
    }

    public void setPublishingDate(LocalDateTime publishingDate) {
        this.publishingDate = publishingDate;
    }

    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        this.owner = owner;
    }



    public List<String> getAllowedChildClasses() {
        List<String> list = new ArrayList<String>(levels.subList(levels.indexOf(getLevel())+1, levels.size()));
        //list.set(0, "Sub-" + list.get(0));

        return list;
    }

    public int getMyNumber() {
        return myNumber;
    }

    public void setMyNumber(int myNumber) {
        this.myNumber = myNumber;
    }

    public Type getMyType() {
        return myType;
    }

    public void setMyType(Type myType) {
        this.myType = myType;
    }

    public Status getMyState() {
        return myState;
    }

    public void setMyState(Status myState) {
        this.myState = myState;
    }

    @Override
    public String toString() {
        String beginString = begin == null? "tbd." : begin.format(formatter);
        String endString = end == null? "tbd." : end.format(formatter);

        return String.format("%s-%s: %s > %s", beginString, endString, identifier, goal);
    }

    public String debug() {
        String tmp = getRequirements() == null ? "0" : Integer.toString(getRequirements().size());
        String txt = getId() + "@" + getLevel() + ": " + toString() + "; " + tmp + " userRequirements; " + getChildren().size() + " children";
        if(getParent() == null) {
            txt += " as root element";
        } else {
            txt += " owned by " + getParent().getId();
        }
        return txt;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        //result = prime * result + version;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Term other = (Term) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        /*
        if (version != other.version)
            return false;
         */
        return true;
    }


}

FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.DatePicker?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>

<GridPane fx:id="gridPane" hgap="10.0" maxHeight="1.7976931348623157E308"
    maxWidth="1.7976931348623157E308" stylesheets="@../stylesheets/controller.css"
    vgap="10.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="com.agiletunes.controllers.terms.TermEditorCtrl">

    <columnConstraints>
        <ColumnConstraints maxWidth="1.7976931348623157E308" />
        <ColumnConstraints maxWidth="1.7976931348623157E308"
            minWidth="10.0" />
        <ColumnConstraints minWidth="10.0" />
        <ColumnConstraints maxWidth="1.7976931348623157E308"
            minWidth="10.0" />
    </columnConstraints>
    <rowConstraints>
        <RowConstraints minHeight="10.0" />
        <RowConstraints minHeight="10.0" />
        <RowConstraints minHeight="10.0" />
        <RowConstraints minHeight="10.0" />
        <RowConstraints />
        <RowConstraints minHeight="10.0" />
        <RowConstraints minHeight="10.0" />
        <RowConstraints minHeight="10.0" />
        <RowConstraints minHeight="10.0" />
        <RowConstraints minHeight="10.0" />
    </rowConstraints>
    <children>
        <DatePicker fx:id="beginDatePicker" onAction="#beginChanged"
            GridPane.columnIndex="1" GridPane.rowIndex="4">
            <GridPane.margin>
                <Insets />
            </GridPane.margin>
        </DatePicker>
        <DatePicker fx:id="endDatePicker" onAction="#endChanged"
            GridPane.columnIndex="3" GridPane.rowIndex="4">
            <GridPane.margin>
                <Insets right="24.0" />
            </GridPane.margin>
        </DatePicker>
        <Label text="Begin" GridPane.halignment="LEFT"
            GridPane.rowIndex="4">
            <GridPane.margin>
                <Insets left="24.0" />
            </GridPane.margin>
        </Label>
        <Label text="End" GridPane.columnIndex="2" GridPane.halignment="LEFT"
            GridPane.rowIndex="4">
            <GridPane.margin>
                <Insets left="12.0" right="8.0" />
            </GridPane.margin>
        </Label>
        <Label maxWidth="1.7976931348623157E308" text="Identifier"
            GridPane.hgrow="ALWAYS" GridPane.rowIndex="2">
            <GridPane.margin>
                <Insets left="24.0" right="12.0" top="24.0" />
            </GridPane.margin>
        </Label>
        <TextField fx:id="identifierTextField" onAction="#identifierChanged"
            onMouseExited="#identifierChanged" GridPane.columnIndex="1"
            GridPane.columnSpan="2147483647" GridPane.rowIndex="2">
            <GridPane.margin>
                <Insets right="24.0" top="24.0" />
            </GridPane.margin>
        </TextField>
        <Label layoutX="34.0" layoutY="80.0" maxWidth="1.7976931348623157E308"
            text="Level" GridPane.rowIndex="5">
            <GridPane.margin>
                <Insets left="24.0" />
            </GridPane.margin>
        </Label>
        <ComboBox fx:id="timeUnitComboBox" maxWidth="1.7976931348623157E308"
            onAction="#timeUnitChanged" GridPane.columnIndex="3" GridPane.hgrow="ALWAYS"
            GridPane.rowIndex="5">
            <GridPane.margin>
                <Insets right="24.0" />
            </GridPane.margin>
        </ComboBox>
        <Separator prefWidth="200.0" GridPane.columnSpan="2147483647"
            GridPane.rowIndex="7" />
        <Label layoutX="34.0" layoutY="39.0" text="Goal"
            GridPane.rowIndex="3">
            <GridPane.margin>
                <Insets left="24.0" />
            </GridPane.margin>
        </Label>
        <TextField fx:id="goalTextField" layoutX="116.0" layoutY="34.0"
            onAction="#goalChanged" onKeyReleased="#goalChanged" onMouseExited="#goalChanged"
            GridPane.columnIndex="1" GridPane.columnSpan="2147483647"
            GridPane.rowIndex="3">
            <GridPane.margin>
                <Insets right="24.0" />
            </GridPane.margin>
        </TextField>
        <Label layoutX="34.0" layoutY="162.0" text="Time unit"
            GridPane.columnIndex="2" GridPane.halignment="RIGHT"
            GridPane.rowIndex="5">
            <GridPane.margin>
                <Insets left="12.0" right="8.0" />
            </GridPane.margin>
        </Label>
        <Label layoutX="34.0" layoutY="162.0" maxWidth="1.7976931348623157E308"
            text="Type" GridPane.rowIndex="6">
            <GridPane.margin>
                <Insets left="24.0" />
            </GridPane.margin>
        </Label>
        <ComboBox fx:id="typeComboBox" layoutX="116.0" layoutY="157.0"
            maxWidth="1.7976931348623157E308" onAction="#typeChanged"
            GridPane.columnIndex="1" GridPane.rowIndex="6" />
        <Label layoutX="391.0" layoutY="162.0" text="State"
            GridPane.columnIndex="2" GridPane.halignment="LEFT"
            GridPane.rowIndex="6">
            <GridPane.margin>
                <Insets left="12.0" right="8.0" />
            </GridPane.margin>
        </Label>
        <ComboBox fx:id="stateComboBox" layoutX="464.0" layoutY="157.0"
            maxWidth="1.7976931348623157E308" onAction="#stateChanged"
            GridPane.columnIndex="3" GridPane.rowIndex="6">
            <GridPane.margin>
                <Insets right="24.0" />
            </GridPane.margin>
        </ComboBox>
        <Separator prefWidth="200.0" GridPane.columnSpan="2147483647"
            GridPane.rowIndex="1" />
        <Label layoutX="34.0" layoutY="99.0" maxWidth="1.7976931348623157E308"
            text="Parent">
            <GridPane.margin>
                <Insets left="24.0" top="24.0" />
            </GridPane.margin>
        </Label>
        <Hyperlink fx:id="parentHyperlink" onMouseClicked="#parentSelected"
            text="Hyperlink" GridPane.columnIndex="1" GridPane.columnSpan="2147483647">
            <GridPane.margin>
                <Insets right="24.0" top="24.0" />
            </GridPane.margin>
        </Hyperlink>
        <ListView fx:id="subTermListView" onMouseClicked="#childSelected"
            prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1"
            GridPane.columnSpan="2147483647" GridPane.rowIndex="8">
            <GridPane.margin>
                <Insets bottom="24.0" right="24.0" />
            </GridPane.margin>
        </ListView>
        <Label layoutX="34.0" layoutY="38.0" maxWidth="1.7976931348623157E308"
            text="Sub-terms" GridPane.hgrow="ALWAYS" GridPane.rowIndex="8"
            GridPane.valignment="TOP">
            <GridPane.margin>
                <Insets left="24.0" />
            </GridPane.margin>
        </Label>
        <Label fx:id="levelLabel" text="Label" GridPane.columnIndex="1"
            GridPane.rowIndex="5" />
    </children>
</GridPane>

Controller类:

    ..

    @Controller
    public class TermEditorCtrl implements Initializable {

    @FXML    private DatePicker beginDatePicker;
    @FXML    private DatePicker endDatePicker;
    @FXML    private TextField identifierTextField;
    @FXML    private ComboBox<String> timeUnitComboBox;
    @FXML    private TextField goalTextField;
    @FXML    private ComboBox<Term.Type> typeComboBox;
    @FXML    private ComboBox<Term.Status> stateComboBox;
    @FXML   private ListView<Term> subTermListView;
    @FXML   private Label levelLabel;
    @FXML   private Hyperlink parentHyperlink;

    @Autowired private TermService termService;
    @Autowired private EntityManagerFactory emf;
    protected EntityManager entityManager;
    protected EntityTransaction transaction;


    protected boolean isDirty;

    protected Term myTerm;


    public TermEditorCtrl() {

    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        typeComboBox.setItems(FXCollections.observableArrayList(Term.Type.values()));
        stateComboBox.setItems(FXCollections.observableArrayList(Term.Status.values()));
        timeUnitComboBox.setItems(FXCollections.observableArrayList(Term.chronoUnits));
    }

    @Transactional(propagation=Propagation.REQUIRED)
    protected void saveIfNeeded() {
        if(transaction != null) {
            if(isDirty) {
                Alert alert = new Alert(AlertType.CONFIRMATION, "Otherwise all changes will be lost\n\n", ButtonType.YES, ButtonType.NO);
                alert.setTitle("Requirement changed");
                alert.setHeaderText("Save changes?");

                Optional<ButtonType> result = alert.showAndWait();
                if (result.get() == ButtonType.YES){
                    termService.save(myTerm);
                    transaction.commit();
                } 
            } else {
                transaction.rollback();
                transaction = null;
            }   
        }
    }

    @Transactional(propagation=Propagation.REQUIRED)
    public void setTerm(Term aTerm) {
        saveIfNeeded();
        myTerm = aTerm;

        entityManager = emf.createEntityManager();
        transaction = entityManager.getTransaction();
        transaction.begin();

        identifierTextField.setText(aTerm.getIdentifier());
        beginDatePicker.setValue(aTerm.getBegin());
        endDatePicker.setValue(aTerm.getEnd());
        goalTextField.setText(aTerm.getGoal());
        stateComboBox.getSelectionModel().select(aTerm.getMyState());
        typeComboBox.getSelectionModel().select(aTerm.getMyType());
        levelLabel.setText(aTerm.getLevel());
        subTermListView.setItems(aTerm.getObservableChildren());
        timeUnitComboBox.getSelectionModel().select(aTerm.getDefaultTimeUnit());
        Term parent = aTerm.getParent();
        if (parent != null) {
            parentHyperlink.setText(parent.getIdentifier());
        } else {
            parentHyperlink.setText("");
        }

        isDirty = false;

    }

    @FXML
    void beginChanged(ActionEvent event) {
        myTerm.setBegin(beginDatePicker.getValue());
        isDirty = true;
    }

    @FXML
    void endChanged(ActionEvent event) {
        myTerm.setEnd(endDatePicker.getValue());
        isDirty = true;
    }

    @FXML
    void goalChanged(KeyEvent event) {
        myTerm.setGoal(goalTextField.getText());
        isDirty = true;
    }

    @FXML
    void identifierChanged(ActionEvent event) {
        myTerm.setIdentifier(identifierTextField.getText());
        isDirty = true;
    }


    @FXML
    void stateChanged(ActionEvent event) {
        myTerm.setMyState(stateComboBox.getSelectionModel().getSelectedItem());
        isDirty = true;
    }

    @FXML
    void childSelected(MouseEvent event) {
        setTerm(subTermListView.getSelectionModel().getSelectedItem());
    }

    @FXML
    void parentSelected(MouseEvent event) {
        setTerm(myTerm.getParent());
    }


    @FXML
    void timeUnitChanged(ActionEvent event) {
        myTerm.setDefaultTimeUnit(timeUnitComboBox.getSelectionModel().getSelectedItem());
        isDirty = true;
    }

    @FXML
    void typeChanged(ActionEvent event) {
        myTerm.setMyType(typeComboBox.getSelectionModel().getSelectedItem());
        isDirty = true;
    }

    public void setStage(Stage aStage) {
        aStage.setOnCloseRequest(event -> {
            saveIfNeeded();
        });
    }
}

在ListView

中选择Term对象时加载FXML UI和控制器的代码
private ContextMenu getContextMenu(Term term) {
            ContextMenu cm = new ContextMenu();

            MenuItem editItem = new MenuItem("Edit");
            cm.getItems().add(editItem);
            editItem.setOnAction(event -> {
                try{
                    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/TermEditor.fxml"));
                    fxmlLoader.setControllerFactory(c -> App.springContext.getBean(c));  //  lookup the controller from the spring application context
                    Parent parent = fxmlLoader.load();
                    TermEditorCtrl termCtrl = fxmlLoader.getController();

                    Stage stage = new Stage();
                    Scene scene = new Scene(parent);
                    stage.setScene(scene);
                    stage.show();

                    termCtrl.setStage(stage);
                    termCtrl.setTerm(term);
                }
                catch(IOException e){
                    logger.debug(e.getLocalizedMessage());
                    e.printStackTrace();
                }
            });

错误消息

javafx.fxml.LoadException: 
/C:/Users/Alexander/Documents/agiletunes-codespace/agileTunes-implementation/target/classes/fxml/TermEditor.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
    at com.agiletunes.controllers.requirement.PlanningPaneCtrl$TermTreeCell.lambda$0(PlanningPaneCtrl.java:674)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.control.MenuItem.fire(MenuItem.java:462)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1405)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$343(ContextMenuContent.java:1358)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:417)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
    at com.agiletunes.controllers.terms.TermEditorCtrl.initialize(TermEditorCtrl.java:68)
    at com.agiletunes.controllers.terms.TermEditorCtrl$$FastClassBySpringCGLIB$$1861d384.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:669)
    at com.agiletunes.controllers.terms.TermEditorCtrl$$EnhancerBySpringCGLIB$$bd8c26eb.initialize(<generated>)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
    ... 45 more

如果您需要其他信息,代码或类似信息,请告知我们

非常感谢您提前寻求帮助。

1 个答案:

答案 0 :(得分:0)

我进一步考虑了这一点。最终我在AopUtils中的canApply(Pointcut pc,Class targetClass,boolean hasIntroductions)中找到了根本原因。问题是控制器的模型已设置,调用setTerm方法。 setTerm的参数是Term对象,Term是抽象类。 Spring在处理抽象参数时显然存在问题。我用5种不同的setter方法替换了setTerm方法,每个具体的Term扩展名为1。现在它有效。

我想知道这是一个错误还是一个功能,因为CglibAopProxy中的拦截方法也会获得一个设置了所有FXML变量的代理对象?!