This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 251982 - NullPointerException at utils.Model.FilterListModel.getSize
Summary: NullPointerException at utils.Model.FilterListModel.getSize
Status: REOPENED
Alias: None
Product: guibuilder
Classification: Unclassified
Component: Code (show other bugs)
Version: 8.1
Hardware: All All
: P3 normal (vote)
Assignee: issues@guibuilder
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-04-22 10:50 UTC by Chiana
Modified: 2015-04-25 13:11 UTC (History)
0 users

See Also:
Issue Type: DEFECT
Exception Reporter: 216904


Attachments
stacktrace (4.71 KB, text/plain)
2015-04-22 10:50 UTC, Chiana
Details
Screendump showing error in IDE (240.70 KB, image/jpeg)
2015-04-25 12:08 UTC, Chiana
Details
Log (419.84 KB, application/octet-stream)
2015-04-25 12:11 UTC, Chiana
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Chiana 2015-04-22 10:50:21 UTC
Build: NetBeans IDE Dev (Build 201504130001)
VM: Java HotSpot(TM) 64-Bit Server VM, 24.45-b08, Java(TM) SE Runtime Environment, 1.7.0_45-b18
OS: Windows 7

User Comments:
Chiana: Tried to add a selfmade panel using add bean in a design.




Stacktrace: 
java.lang.NullPointerException
   at utils.Model.FilterListModel.getSize(FilterListModel.java:118)
   at javax.swing.JList.getPreferredScrollableViewportSize(JList.java:2448)
   at javax.swing.ViewportLayout.preferredLayoutSize(ViewportLayout.java:92)
   at java.awt.Container.preferredSize(Container.java:1788)
   at java.awt.Container.getPreferredSize(Container.java:1773)
   at javax.swing.JComponent.getPreferredSize(JComponent.java:1662)
Comment 1 Chiana 2015-04-22 10:50:25 UTC
Created attachment 153295 [details]
stacktrace
Comment 2 Tomas Pavek 2015-04-22 12:02:41 UTC
This is an exception from a custom component (FilterListModel) when asked for preferred size, I'm afraid we can hardly do anything about it.
Comment 3 Chiana 2015-04-22 13:06:32 UTC
I know that, but the question is; why did it happen in the first Place?
Comment 4 Tomas Pavek 2015-04-24 12:55:29 UTC
I don't have the components around FilterListModel, nor their sources, don't know the steps to reproduce -- so I really can't tell.
Comment 5 Chiana 2015-04-25 05:59:09 UTC
Well I Think I can shed some light to that, FilterListModel is a controler for a listmodel that selects data from an SQL-server, it works in conjunction with a JList that does the actual displaying.
I had some problem adding this with drag-drop ao I tried using "add bean" and typing in the name of the class instead.

It is apparent that the IDE instansiated the class and then called getSize() on it and as you can se in the source of FilterListModel.java below that is not a really good idea.

But the question is still; why should the IDE request the size of a listmodel when you are editing?


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package utils.Model;

import ent.manager.AbstractRegManager;
import java.awt.EventQueue;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.AbstractListModel;
import javax.swing.SwingWorker;
import utils.swing.FilterModelAccess;
import utils.SimpleList;

/**
 * A ListModel that has some rudimentary filtering capacity
 *
 * @author Kent
 */
public abstract class FilterListModel
        extends AbstractListModel
        implements Filters,
                   FilterModelAccess {

  /**
   * Descriptions of the type of filter to be used
   */
  public static final String filterTypes[] = new String[]{"innehåller",
                                                          "börjar med",
                                                          "slutar med"};
  private int filterNo = 0;
  // filtertype 0=contains 1=starts 2=ends
  private int filterType = 0;  // Contains
  private String searchFilter = null;
  /**
   * Ultimate filter, always apply to model
   */
  private String mainFilter = null;
  List keys = null;

  public void setMainFilter(String filter) {
    keys = null;
    if (filter != null && filter.trim().isEmpty()) {
      filter = null;
    }
    mainFilter = filter;
  }

  public String getMainFilter() {
    return mainFilter;
  }

  /**
   * Get the registry manager that is used to control the data itself This should be based on a EntityManager
   *
   * @return Registry manager
   */
  public abstract AbstractRegManager getRegManager();

  private String formatFilter(int filterNo,
                              int filterType,
                              String searchFilter) {
    String f, startsWith = "", endsWith = "";
    f = getFilterFields()[filterNo] + " like ";
    if (filterType == 0) {
      startsWith = "%";
      endsWith = "%";
    }
    if (filterType == 1) {
      startsWith = "%";
    }
    if (filterType == 2) {
      endsWith = "%";
    }
    f += "'" + endsWith + searchFilter + startsWith + "'";
    return f;
  }

  private String[] filterArray() {
    String[] filt;
    int index = 0;
    if (mainFilter != null) {
      filt = new String[2];
      filt[0] = mainFilter;
      index = 1;
    } else {
      filt = new String[1];
    }
    if (searchFilter == null || searchFilter.isEmpty()) {
      return new String[]{mainFilter};
    }
    filt[index] = formatFilter(filterNo, filterType, searchFilter);
    return filt;
  }
  /**
   * When set true will not check against database for updates on the keys
   */
  private boolean noDBcheck = false;

  private int listSize() {
    if (keys == null) {
      return 0;
    }
    return keys.size() - 1;
  }

  @Override
  public int getSize() {
    /*  int size = noDBcheck ? keys.size() : getRegManager().count(searchFilterString());
     if (keys == null || size != keys.size()) {
     loadKeys();
     }
     return size;*/
    if (keys == null) {
      loadKeys();
    }
    return keys.size();
  }

  /**
   * Call with flag set to true to indicate a repaint of the model is about to start, also makes sure the keys have been
   * loaded into the model
   *
   * @param flag
   */
  @Override
  public void dbBlock(boolean flag) {
    noDBcheck = flag;
    if (flag && keys == null) {
      loadKeys();
    }
  }

  /**
   * This should be called when the list is initiated the first time only, it makes the model return no entries and not
   * to load anything from the database
   *
   * @param flag
   */
  @Override
  public void initialPaintBlock(boolean flag) {
    if (flag) {
      noDBcheck = true;
      keys = new SimpleList<Object>();
    } else {
      noDBcheck = false;
      keys = null;
    }
  }

  private void loadKeys() {
    if (EventQueue.isDispatchThread()) {
      SwingWorker< List, Object> worker = new SwingWorker< List, Object>() {

        @Override
        protected List doInBackground()
                throws Exception {
          return getRegManager().allKeys(filterArray());
        }
      };
      worker.run();
      // Wait here for completion
      int count = 0;
      while (!worker.isDone()) {
        count++;
      }

      try {
        keys = worker.get();
      } catch (InterruptedException ex) {
      } catch (ExecutionException ex) {
      }
    } else {
      keys = getRegManager().allKeys(filterArray());
    }
    /*   boolean noReset = noDBcheck;
     noDBcheck = true;
     this.fireContentsChanged(this, 0, keys.size() - 1);
     if (!noReset) {
     noDBcheck = false;
     }*/
  }

  public void updateModel() {
    boolean noReset = noDBcheck;
    noDBcheck = true;
    fireContentsChanged(this, 0, listSize());
    if (!noReset) {
      noDBcheck = false;
    }
  }

  @Override
  public Object getElementAt(int index) {
    if (index == -2) {
      // Special case, used for signalling update of model
      boolean noReset = noDBcheck;
      noDBcheck = true;
      this.fireContentsChanged(this, 0, listSize());
      if (!noReset) {
        noDBcheck = false;
      }
      return null;
    }
    if (index > listSize()) {
      return new String("Invalid index");
    }
    return keys.get(index);
  }

  /**
   * Sets the filters
   *
   * @param filter Database field to be used for filtering
   * @param filterNo Filter number
   * @param filterType Type of filter @seealso filterTypes
   */
  @Override
  public void setFilter(String filter,
                        int filterNo,
                        int filterType) {
    this.filterNo = filterNo;
    this.filterType = filterType;
    searchFilter = filter;
    noDBcheck = false;
    keys = null;
    int size = getSize();
    noDBcheck = true;
    fireContentsChanged(this, 0, listSize());
    noDBcheck = false;
  }

  /**
   *
   * @param filter
   * @param filterNo
   * @param filterType
   */
  @Override
  public void setFilter(String filter,
                        String filterNo,
                        String filterType) {
    setFilter(filter, getFilterIndex(filterNo), getFilterTypeIndex(filterType));
  }

  /**
   *
   * @return
   */
  @Override
  public String getFilter() {
    return searchFilter;
  }

  /**
   *
   */
  @Override
  public void clearFilter() {
    setFilter(null, filterNo, filterType);
  }

  /**
   * Get the offset for the filter, note: This is a special speeded version that only works with the builtin filters. If
   * you use other filters this should be overridden
   *
   * @param type
   * @return
   */
  @Override
  public int getFilterTypeIndex(String type) {
    if (type.charAt(0) == 'i') {
      return 0;
    }
    if (type.charAt(0) == 'b') {
      return 1;
    }
    if (type.charAt(0) == 's') {
      return 2;
    }
    throw new RuntimeException("Filter type not found");
  }

  /**
   *
   * @return
   */
  @Override
  public final String[] getFilterTypes() {
    return filterTypes;
  }

  /**
   *
   * @param filter
   * @return
   */
  @Override
  public int getFilterIndex(String filter) {
    for (int i = 0; i < getFilterNames().length; i++) {
      if (getFilterNames()[i].equals(filter)) {
        return i;
      }
    }
    throw new RuntimeException("Filter name not found");
  }
}
Comment 6 Chiana 2015-04-25 11:53:13 UTC
Now I know how to reproduce this.

First create a new JDialog form.
Then create a new JPanel form.
Third you create a ListModel for use;

import javax.swing.AbstractListModel;

/**
 *
 * @author Kent
 */
public class Model
        extends AbstractListModel {

  @Override
  public int getSize() {
    throw new NullPointerException("Gotcha");
  }

  @Override
  public Object getElementAt(int index) {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
  }

}

Save everything and then go back to the JPanel form and insert a JList using the GUI. After that edit the Model property into "Customized" and make it "new Model()"
Switch to the JDialog and enter design mode, right-click your project and build it (Might need to use clean and build) compile on save wont do. Now, when you try to drag (from the project window) the JPanel onto the JDialog a "Gotcha" is thrown...
I simply don't see the point in requesting the size of a listmodel during editing/design as it cannot possibly be know.
Comment 7 Chiana 2015-04-25 12:08:50 UTC
Created attachment 153391 [details]
Screendump showing error in IDE

Seems it is not possible to upload reports for the moment, reports server unavailable, uploads a screendump and a log manually.
Comment 8 Chiana 2015-04-25 12:11:03 UTC
Created attachment 153392 [details]
Log
Comment 9 Chiana 2015-04-25 13:11:15 UTC
It is apparent that this is actually caused by a design flaw of the GUI itself, I think it needs to be adressed somehow, but short of redesigning the entire GUI I'm not shure of how it should be done, perhaps some alternate mechanism using proxys and stuff when the IDE instansiates a component would be appropriate such as the GUI actually creates a Constructor for it's own use that does not try to do dangerous things like instansiating listmodels and stuff (or atleast activley tries to avoid it...).

I also recognize that this is similar to the debugger Calling .toString() reported elsewhere several times.

But for now I think this should be adressed so that this is properly caught and not reported as an exception by the GUI but more in a "Unable to instansiate Component, please try again later when your Component meets the requirement of the Graphical Editor..." way.