The current infrastructure for handling Java files programmatically in NetBeans is built on a bunch of standards relating to modelling and model-driven architecture (model-driven-architecture discussions tend toward being acronym salad; we get a bit of salad leakage into NetBeans APIs as a result).

Underlying it all is a generic infrastructure for handling things like refactoring in any language. So the API for Java is actually machine generated from a "metamodel" describing the Java language (i.e. specifying that there are things called packages, that they contain classes, which contain methods and fields, and so forth).

The result is that the API for interacting with Java sources usually has you dealing with objects which implement a heap of interfaces, each of which represents some characteristic of some element of a Java source. The basics of what you see look somewhat like:

Resource - a .java file containing 0 or more Java classes
  JavaClass - A java class
    Features - things such as methods, fields, etc
      Statements, StatementBlocks, VariableAccesses, MethodInvocations, etc.

Usually you get some object, and it returns a List of its child objects. Sometimes specialized getters are available for specific types of object, for example, Resource.getImports(). Be careful with these lists - they are live - if you remove an object, it disappears from the source code.

One thing to be aware of is that doing almost anything (even asking for the names of method objects) needs to be done inside the repository's transaction lock. The metadata repository (MDR) is the thing that holds a database of relationships between classes, etc. that is used for code completion and refactoring - so if you are going to modify something, you need to do this under a write lock. The typical pattern is:

 boolean writeOperation = true;
JavaModel.getJavaRepository().beginTrans(writeOperation);
// rollback is applicable only for write transactions
boolean rollback = writeOperation;
try {
  //do something
  // ....
  // everything succeeded -> set rollback to false
  rollback = false;
} finally {
  JavaModel.getJavaRepository().endTrans(rollback);
}

Acquiring the transaction lock is somewhat expensive - it is best to do as much work as possible inside a single transaction.

See also JavaModel basics.

Source: NetBeans FAQ