【问题标题】:Mysteriously vanishing object reference神秘消失的对象引用
【发布时间】:2014-08-16 05:21:46
【问题描述】:

在具有多个模块的 netbeans 平台项目中,有一个 TopComponent 对象。此 TopComponent 的私有属性之一引用另一个对象。此 TopComponent 的组件之一是 TopComponent 中带有事件处理代码的按钮。

在按下按钮之前,该属性指的是正确的对象,但一旦按下按钮(在事件处理代码的开头),该属性的值为 null!

我的对象引用发生了什么?

据我所知,我还没有编写任何将其设置为 null 的代码。根据调试器,我所有的代码似乎都运行良好。我不知道如何让调试器在变量被清除的地方停止。我在 TopComponent 对象上使用了一个固定的手表来确认在按下按钮之前对象引用就在那里,并在按钮的事件处理代码开始处设置一个断点来查看它已经在那里。但在这之间会发生什么?我不知道,但不管它是什么,它都会弄乱我的代码。

该属性在声明为 null 时被初始化,当来自另一个模块的查找触发设置它的方法时,它被赋予一个值。这种方法效果很好。

我很确定它是 TopComponent 的同一个实例,因为调试器为对象提供了相同的 id,并且我使用了固定的手表。

我错过了什么?

这里是相关的类

package org.sil.jflavourviewer;

// <snip> import statements

/**
 * Top component which displays something.
 */
@ConvertAsProperties(dtd = "-//org.sil.jflavourviewer//JFlavourViewer//EN",
autostore = false)
@TopComponent.Description(preferredID = "JFlavourViewerTopComponent",
//iconBase="SET/PATH/TO/ICON/HERE", 
persistenceType = TopComponent.PERSISTENCE_ALWAYS)
@TopComponent.Registration(mode = "explorer", openAtStartup = true)
@ActionID(category = "Window", id = "org.sil.jflavourviewer.JFlavourViewerTopComponent")
@ActionReference(path = "Menu/Window" /*, position = 333 */)
@TopComponent.OpenActionRegistration(displayName = "#CTL_JFlavourViewerAction",
preferredID = "JFlavourViewerTopComponent")
public final class JFlavourViewerTopComponent extends TopComponent implements LookupListener
{

    public JFlavourViewerTopComponent()
    {
        initComponents();
        setName(NbBundle.getMessage(JFlavourViewerTopComponent.class, "CTL_JFlavourViewerTopComponent"));
        setDisplayName("Project Viewer");
        setToolTipText("Here are the items in the active project");
        categoriesListModel = new DefaultListModel<String>();
        categoryList.setModel(categoriesListModel);
        lookupContent = new InstanceContent();
        lookup = new AbstractLookup(lookupContent);
        associateLookup(lookup);
    }

    /** The content of this method is
     * always regenerated by the Form Editor.
     */                       
    private void initComponents() {

        // <snip> Some swing components initialised

        btnAddItem = new javax.swing.JButton();

        // <snip> component settings and layout

        org.openide.awt.Mnemonics.setLocalizedText(btnAddItem, org.openide.util.NbBundle.getMessage(JFlavourViewerTopComponent.class, "JFlavourViewerTopComponent.btnAddItem.text")); // NOI18N
        btnAddItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnAddItemActionPerformed(evt);
            }
        });

       // <snip> more component settings and layout

    }                        


    // here is the event handling code for the "add" button
    private void btnAddItemActionPerformed(java.awt.event.ActionEvent evt)
    {                                           
        // At this point this.activeProject is already null
        JFlavourItemBean newItem = new JFlavourItemBean();
        this.activeProject.addItem(newItem);
        // <snip> the rest of the method is not executed because the NullPointerException is thrown
    }                                          

    // <snip> swing variable declerations
    private javax.swing.JButton btnAddItem;  

    private Lookup.Result<JFlavourProjectBean> result = null;
    private DefaultListModel<String> categoriesListModel;
    private JFlavourProjectBean activeProject = null;
    private InstanceContent lookupContent;
    private AbstractLookup lookup;

    @Override
    public void componentOpened()
    {
        result = Utilities.actionsGlobalContext().lookupResult(JFlavourProjectBean.class);
        result.addLookupListener (this);
    }

    @Override
    public void componentClosed()
    {
        result.removeLookupListener(this);
    }

    void writeProperties(java.util.Properties p)
    {
        //<snip>
    }

    void readProperties(java.util.Properties p)
    {
        //<snip>
    }

    // this is the code that sets this.activeProject via listening to the global Lookup
    // after this method runs this.activeProject is successfully set
    @Override
    public void resultChanged(LookupEvent le)
    {
        Collection<? extends JFlavourProjectBean> allProjects = result.allInstances();
        if (!allProjects.isEmpty()) {
            JFlavourProjectBean project = allProjects.iterator().next();
            this.activeProject = project;
            SortedSet<String> categories = project.getCategories();
            categoriesListModel.clear();
            for (Iterator<String> it = categories.iterator(); it.hasNext();) {
                categoriesListModel.addElement(it.next());
            }
            tmpLabel.setText(project.getName());
        } else {
            activeProject = null;
            // TODO what to display when no project is loaded
        }
    }

}

如果你愿意,你可以在这里看到整个文件而不用剪断JFlavourViewerTopComponent.java 将 JFlavourProjectBean 对象添加到其查找中的是JFlavourProjectManagerTopComponent.java

如果您愿意,可以浏览整个 JFlavour 项目的代码,因为它是目前为止。如果我有 10 个声望,我会给你这个链接,但你可能可以从上面的 2 个链接中计算出来。

我打算发布调试器的图像,但由于我没有足够的代表,所以我只需要描述它。

我在 resultChanged 方法接近尾声时停止执行,并将“this”设置为固定手表。 this.activeProject 上的手表显示它已正确填充。我继续执行,直到它等待输入。固定手表仍显示正确设置的 activeProject 属性。然后我按下“添加...”按钮并在事件处理程序的第一行停止执行。现在 this.activeProject 上的手表显示“null”,固定手表也显示 activeProject 为 null。

我已经确定使用 Object 的 hashCode() 方法,该方法自始至终都在处理 TopComponent 的同一实例。

【问题讨论】:

  • 我建议发布您的代码,以便我们检查逻辑。
  • 一行代码值1000字。
  • 您可能正在隐藏您的引用(将变量声明为类级实例,但将实例分配给局部变量) - 代码会告诉...
  • 好的,我发布了一些代码并链接到更多。根据 SO 规则,我需要发布重现错误所需的最短代码。如果我找不到导致错误的代码怎么办?我已经发布了我认为与我的代码最相关的内容,但我很确定错误不在其中,因为它一切正常 AFAIK。这就是为什么我之前没有发布它。错误出现在用户单击组件和该单击的事件处理代码之间的某个位置。我不知道在哪里可以找到当时执行的任何代码。
  • 我还添加了我在调试器中看到的内容的描述。

标签: java netbeans-platform


【解决方案1】:

我研究了如何向修改时触发的变量添加断点 (Ctrl+Shift+F8 -> Breakpoint Type: Field)

这表明当单击按钮时执行重新进入 resultChanged 方法(为什么?我不知道),这次查找中没有 JFlavourProjectBean 所以它进入 else 子句并设置activeProject 为 null。

现在我把那个方法改成了这样:

@Override
public void resultChanged(LookupEvent le)
{
    Collection<? extends JFlavourProjectBean> allProjects = result.allInstances();
    if (!allProjects.isEmpty()) {
        JFlavourProjectBean project = allProjects.iterator().next();
        this.activeProject = project;
        SortedSet<String> categories = project.getCategories();
        categoriesListModel.clear();
        for (Iterator<String> it = categories.iterator(); it.hasNext();) {
            categoriesListModel.addElement(it.next());
        }
        tmpLabel.setText(project.getName());
    } else {
        // do nothing if no projects are in the lookup
    }
}

【讨论】:

    猜你喜欢
    • 2011-08-23
    • 1970-01-01
    • 2018-08-18
    • 2012-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-19
    • 2010-10-03
    相关资源
    最近更新 更多