Skip navigation links
org.netbeans.modules.refactoring.api 1.71.0 1

Refactoring API
Under Development

The Refactoring API module provides UI and API framework for easy and uniform implementation of refactoring features.

See: Description

Refactoring API 
Package Description
org.netbeans.modules.refactoring.api  
org.netbeans.modules.refactoring.api.ui  
org.netbeans.modules.refactoring.spi  
org.netbeans.modules.refactoring.spi.ui  

The Refactoring API module provides UI and API framework for easy and uniform implementation of refactoring features. The Refactoring module provides:

What is New (see all changes)?

Use Cases

Refactoring module provides API for refactorings. The idea is that at least the most elementary set of refactorings should be available via an API, so that the refactorings could be invoked programmatically. This is particulary useful when creating more complex refactorings. These can then be composed from the primitive refactorings accessible via an API using delegation. As an example we can use a simple rename refactoring. When renaming a class in a J2SE environment, simple rename refactoring (which renames all occurrences of the class) is sufficient. However in a J2EE environment, renaming a class may require renaming of other classes to preserve the functionality of the application (e.g. synchrinized renaming a home and remote interface for an EJB). This could be achieved by creating a more complex rename refactoring composed of two simple rename refactorings (one for each class to be renamed).

When analyzing flow of various refactorings, we have found out that the steps in the flow are very common for all refactorings. The flow is as follows:
  • User selects an object (or set of objects) and chooses to invoke a particular refactoring on it.
  • Refactoring pre-conditions are checked - whether a given refactoring can be invoked on a given object (or set of objects) or not. User needs to be presented with errors (if any). The errors can be fatal or non-fatal. If an error is fatal, it means the refactoring cannot be performed, if it is not fatal, user should be notified of the problem but still be able to proceed with the refactoring.
  • User sets parameters of the refactoring - each refactoring has some input parameters (e.g. new name for an element in case of Rename refactoring). These parameters need to be set by the client.
  • Entered values of refactoring parameters are checked - errors (if any) are presented to the user.
  • Refactoring collects all changes that need to be performed and presents them to the user.
  • User can choose to not perform a particular set of proposed changes.
  • Refactoring is performed - all the changes confirmed by user are made to the source code.
To make the implementation of various refactorings consistent, the refactoring module provides an API and UI framework that allows these refactorings to be plugged in. This framework enforces the above flow. Using this framework (set of SPI and API) the refactoring implementor can focus purely on the things specific to that particular refactoring (specific pre-conditions checks, parameters checks, implementation of changes, etc.) and leave the functionality that is common for all refactorings (implementation of the flow) up to the framework.

It is quite common that some modules need to be able to affect the behavior of a refactoring. There are 4 typical use-cases when this is desirable:
  1. A module wants to implement refactoring features for their own elements. For instance Java Refactoring module wants to implement Refactoring for Java elements.
  2. A module wants to participate in existing refactoring. E.g. refactoring of java files requires refactoring of non-java files in J2EE area. When a code is refactored, these non-java files need to be refactored too. We can mention JSP files or deployment descriptors as an example.
  3. A module introduces some hidden relationships between several elements. E.g. a single logical EJB consists of several physical classes. When one of these classes are refactored, the other classes need to be refactored as well.
  4. A module generates some derived code into the guarded blocks. In such case it is desirable that the provider of the guarded block refactors the guarded code, since the refactoring module itself has no knowledge of where the guarded code comes from.
The refactoring module provides hooks for other modules - an SPI that allows other modules to participate in refactorings. The modules can participate on all refactoring phases from "preCheck" (checking preconditions), through "checkParameters" (checking validity of refactoring parameters) to "prepare" (collecting changes). Use-cases number 1), 2) and 3) are covered by the same SPI (interfaces RefactoringPluginFactory and RefactoringPlugin). The forth use-case (guarded blocks) are covered by a separate set of interfaces, since for this use-case the module does not need to participate in all refactoring phases. The refactoring framework itself automatically detects that a given change points to a code in guarded blocks and requests all registered guarded block providers to handle that situation.

The rest of this section provides simple orientational examples of API/SPI usage.

Refactoring API can be used for programmatical invocation of refactorings and for pluging ui for these refactorings in.

Refactoring API Example:

Intention: Programatically rename java filecom/company/Test.java to com/company/RenamedTest.java and update references.

        FileObject fo = ...com/company/Test.java...
        RefactoringSession renameSession = RefactoringSession.create("Rename Class");
        refactoring = new RenameRefactoring(fo);
        Problem pre = refactoring.preCheck();
        if (pre!=null && pre.isFatal()) {
          //fatal problem in precheck
          return;
        }
        refactoring.setNewName("RenamedTest");
        Problem p = refactoring.prepare(renameSession);
        
        if (p!=null && p.isFatal()) {
          //fatal problem in precheck
          return;
        }
        
        renameSession.doRefactoring(true /* saveAll */);

Refactoring SPI permit other modules to plug into existing refactorings and allow them to participate. Client of SPI must implement factory class RefactoringPluginFactory and register this class into Lookup.

Refactoring SPI Example 1:

Intention: Create a plugin for RenameRefactoring, which will participate in existing refactoring (let say in java refactoring) and renames references in XML files.

//implementation of factory class
public class J2EERefactoringFactory implements RefactoringPluginFactory {
    
    public RefactoringPlugin createInstance(AbstractRefactoring refactoring) {
    
        if (refactoring instanceof RenameRefactoring) {
            //return our custom instance for RenameRefactoring
            if (wantToParticipate(refactoring.getRefactoredObject())
                return new J2EERenameRefactoringPlugin((RenameRefactoring) refactoring);
        }
        
        if (refactoring instanceof ... {
            ...
        }

        return null;
    }
    
}
It is necessary to register J2EERefactoringFactory in the lookup:
META-INF/services/org.netbeans.modules.refactoring.spi.RefactoringPluginFactory

and implement RefactoringPlugin interface:

//implementation of RefactoringPlugin
public class J2EERenameRefactoringPlugin implements RefactoringPlugin {
    
    private RenameRefactoring refactoring;
    
    public J2EERenameRefactoringPlugin(RenameRefactoring refactoring) { 
        this.refactoring = refactoring;
    }
 
    public Problem preCheck() {
        ...
    }
    
    public Problem checkParameters() {
        ...
    }
    
    public Problem fastCheckParameters() {
        ...
    }
    
    public void cancelRequest() {
        ...
    }
    
    public Problem prepare(RefactoringElementsBag refactoringElements) {
        RenameRefactoring renameRefactor = ((RenameRefactoring)refactoring);
        Object element = renameRefactor.getRefactoredObject();
        if (...) {
           ...
           //lets add our RefactoringElements for usages found in XML files 
           refactoringElements.add(refactoring, new XMLRenameRefactoringElement());
        }
        return null;
    }

    public class XMLRenameRefactoringElement implements RefactoringElementImplementation {

        public void performChange() {
            //do change
        }
    }
Refactoring SPI Example 2: Intention: Create a module, which will add Rename... to html files First you must create your ActionsImplementationProvider:
public class MyProvider extends ActionsImplementationProvider {
    
  public boolean canRename(Lookup lookup) {
    Node[] nodes = lookup.lookupAll(Node.class);
    if (..one node selected and the node belongs to html...)
      return true;
    else 
      return fals;
 }

  public void doRename(Lookup selectedNodes) {
    Node[] nodes = lookup.lookupAll(Node.class);
    final FileObject fo = getFileFromNode(nodes[0]);
    return new Runnable() {
      public void run() {
        UI.openRefactoringUI(new RenameRefactoringUI(fo);
      }
    }    
  }
}
And of course your own RefactoringPlugin and RefactoringPluginFactory see Refactoring SPI Example 1 and Refactoring SPI Example 2
Refactoring SPI Example 3 Module wants to implement it's own refactoring preview tree: Register your own TreeElementFactoryImplementation into META-INF/services if you want to build your own RefactoringPreview tree. For instance Java Refactoring understand Java - specific objects e.g. Projects, Groups, Methods etc.
public TreeElement getTreeElement(Object o) {
.
.
if (o instanceof SourceGroup) {
  return new SourceGroupTreeElement((SourceGroup)o);
} else if (o instanceof SomethingFromJava) {
   return new SomethingFromJavaTreeElement((SomethingFromJava) o);
}
TreeElement is then displayed in refactoring preview panel.


Other usecases are docummented in javadoc.
  • Module wants to add common Refactoring Action into popup.
    See RefactoringActionsFactory
  • http://wiki.netbeans.org/wiki/view/RefactoringFAQ

Exported Interfaces

This table lists all of the module exported APIs with defined stability classifications. It is generated based on answers to questions about the architecture of the module. Read them all...
Group of java interfaces
Interface NameIn/OutStabilitySpecified in What Document?
RefactoringAPIExportedUnder Development
RefactoringSPIExportedUnder Development

Group of property interfaces
Interface NameIn/OutStabilitySpecified in What Document?

Group of lookup interfaces
Interface NameIn/OutStabilitySpecified in What Document?
org.netbeans.modules.refactoring.spi.RefactoringPluginFactoryExportedUnder Development
org.netbeans.modules.refactoring.spi.GuardedBlockHandlerFactoryExportedUnder Development
org.netbeans.modules.refactoring.spi.ReadOnlyFilesHandlerExportedUnder Development
org.netbeans.modules.refactoring.spi.ui.ActionsImplementationProviderExportedUnder Development
org.netbeans.modules.refactoring.spi.ui.TreeElementFactoryImplementationExportedUnder Development

Group of layer interfaces
Interface NameIn/OutStabilitySpecified in What Document?

Implementation Details

Where are the sources for the module?

The sources for the module are in the Apache Git repositories or in the GitHub repositories.

What do other modules need to do to declare a dependency on this one, in addition to or instead of a plain module dependency?
Nothing.

Read more about the implementation in the answers to architecture questions.

Skip navigation links
org.netbeans.modules.refactoring.api 1.71.0 1