GUIBuilderRefactoring

Integrating GUI builder with Java refactoring

This document gathers motivation, requirements and design considerations for making the GUI builder integrated with the NetBeans refactoring infrastructure.

Contents


Motivation

Missing refactoring integration

  • Up until NB 6.0 M10, the GUI builder did not support refactoring - java refactoring features skipped the generated code in guarded blocks. Simple changes like variable rename needed to be done separately in GUI builder and in the source editor (via refactoring), some changes were even not possible without editing the form XML file manually.
  • Issue 48288 got P1 priority, became the most voted issue (42 votes), about 30 duplicates.
  • Perceived as significant problem since NB 4.0.
  • Would get even worse for NB 6.0 after introducing Swing App Framework and Beans Binding.

Requirements

The very basic requirement is to change the form file and the generated guarded code according to the Java refactoring invoked by the user. Additional changes in properties files are required e.g. for internationalization or resources used via Swing Application Framework.

In one particular case - renaming a component variable in the GUI builder - it is the GUI builder who should invoke the rename refactoring to also cover the source code where the variable might be used.

Note it is not possible to support all possible refactorings in general. Some changes makes no sense to GUI builder, i.e. can't be reflected in the form's metadata. Even in the considered list not all of the scenarios will be supported to the full extent, since it is sometimes very difficult to implement (e.g. to map a partial code change to the corresponding logical change in the form metadata). It is not only a problem of refactoring, e.g. synchronizing with other resources is very open-ended and not doable in general.

For theses reasons we don't try for a complete refactoring implementation (it is even hard to define what it should be), but rather focus on typical scenarios people run into most often.

Supported refactoring scenarios

Here's the list of scenarios supported at this moment. For each scenario there is a description of the triggering action, the changes done by standard java refactoring, and additional changes performed by the GUI builder.

1. Rename component variable

A) The user invokes rename refactoring on a field or local variable of a component.

Changes done by standard Java refactoring:

  • update all variable references in non-guarded code

Desired changes done by GUI builder:

  • update the component name in form metadata
  • update all variable references in the generated code
  • update event handler methods that used default name based on the component name
  • update resource keys that use the component name (standard automatic internationalization, app framework's resource support)
  • stored in the form metadata, in the generated code, and in the corresponding properties file

B) Renaming started from GUI builder - via in-place renaming in the Inspector tree, or using Variable Name property, or using Change Variable Name context action

In this case the rename refactoring should be invoked behind the scene so the variable name gets updated both in the form as well as in the java code (so basically the scenario A is executed.) See the design page for more information.

2. Rename the form class

Here only considering renaming within the same package, i.e. only changing the class name, not the package. Changing package is handled as moving - see paragraphs 3 and 6.

Changes done by standard Java refactoring:

  • update all class references in non-guarded code
  • rename java file (.form file is renamed automatically as well)

Desired changes done by GUI builder:

  • update the class references in the generated code
  • update resource keys that use the form class name (automatic internationalization storing strings into a properties file common to whole package)
  • both in the generated code as well as in the corresponding properties file
  • rename properties file dedicated to the form class (app framework's resource support)

Seems that renaming the superclass need not be treated specially in the form that extends the superclass (beyond what standard java refactoring does).

3. Move the form class

Similar to renaming (2), but also moving to another package or even another project.

Changes done by standard Java refactoring:

  • update all class references in non-guarded code
  • move the java file (.form file is moved automatically as well)

Desired changes done by GUI builder:

  • if the form uses app framework resources:
  • move the properties file dedicated to the form class (no need to change anything inside the file)
  • if using automatic internationalization:
  • move the auto-created strings from the original properties file to the corresponding file in the new package, creating a new file as needed
  • update the path to the properties file in the generated code
  • do not moved manually created i18n values since we can't be sure they are not shared (but we should probably copy them - if the properties file is in the same package as the form)

Since the class name itself is not changed:

  • don't need to update the class references in guarded code (the form class itself is used as simple name)
  • don't need to update the resource keys that contain the form class name (automatic internationalization)

4. Copy the form class

Similar to moving, just the original files are kept intact. Some resources are copied instead of moved. The copied form can stay in the same package or go into another one, it can be renamed during the operation.

Changes done by standard Java refactoring:

  • copy the java file (.form file is copied automatically as well) - the file is renamed if needed (or if the user specifies a different name)
  • update all class references in non-guarded code (in the class itself if its name changes and is used in it)

Desired changes done by GUI builder:

  • if the form uses app framework resources:
  • copy the properties file dedicated to the form class, rename if needed (no need to change the content of the file)
  • if using automatic internationalization:
  • copy the auto-created strings from the original properties file to the new copy of the properties file (create it if needed)
  • if the form name has been changed, update the keys to use the new name (auto-generated keys)
  • update the path to the properties file in the generated code (if copied to another package)
  • manually created i18n values are not copied - keep referencing the original properties file

5. Rename/move a component class

This means a component used in the form has changed to another class.

Changes done by standard Java refactoring:

  • move/rename and update the component source file itself
  • update all class references in non-guarded code of classes where the component is used

Desired changes done by GUI builder:

  • update component class name in the form metadata
  • update the class references in the generated code
  • rename variables used for the component if default name derived from class name was used?

6. Rename a package

The package may contain form classes, component classes, resources (e.g. image files) and properties files. These all can be referred to via a classpath name.

  • The form classes are handled similarly to renaming/moving (2, 3). No source/form files are moved. Neither the properties files need to be moved, renamed or split (all classes and resources stay together).
  • The component classes are handled the same way as when moved/renamed (5), just no files are moved.
  • All references in forms to properties files or other resource files that are defined by absolute (full) resource path should be updated. Scope of this update is potentially the whole project and all projects depending on it, however we'll only consider forms within the renamed package. (Typical case is internationalization - the properties file accessed via ResourceBundle is referred to via package name and is used only by the classes from the same package.)

Changes done by standard Java refactoring:

  • update package name in all sources
  • if having separate root for resource in the project, should the same package in there be renamed as well?

Desired changes done by GUI builder:

  • update component class name in metadata of affected forms
  • update the class references in the generated code
  • update paths to properties files (for internationalization), images, or other resources from the changed package
  • in form metadata and corresponding generated code
  • not in user code in general
  • update resource values in properties that use absolute (full) resource path (icon resources may do)
  • don't need to change resource/internationalization keys (the simple class names not changed)
  • don't need to update the form class references in guarded code (simple class name used as well)

7. Updating embedded custom code

The custom code entered by the user in the GUI (e.g. custom creation code, or various pre-/post-init code fragments) should be changed as any other code written by the user. This code appears in the guarded section of the generated code and is primarily stored in the .form file, so it must be changed properly in the .form file as well.

The principial problem is in that there is no mapping between the generated code in the document to the corresponding logical piece of custom code stored in the form metadata. Thus these changes can't be 100% reliable in general. But since the usage of the custom code is quite limited, it seems sufficient to support just several basic cases in a simple way, i.e.:

  • renaming a component variable (typically the user writes some additional code when an existing component variable is used, so this variable should be changed in the custom code when the component is renamed),
  • renaming a class (typically when the user provides custom creation code for a component, refers to some constant through the class name, etc),
  • renaming a package (typically when the custom code uses a fully quilified name of a class and package of that class is renamed).

More general refactoring of custom code blocks is out of scope for now. See also Custom Code Issues.

8. Undo refactoring

All refactoring changes must be undo-able. Undo in refactoring is not invoking a reversible change - each executed operation is asked to undo to revert affected files to the original state.


Not yet supported refactoring scenarios / features

There are still many refactoring scenarios that are not supported by the GUI builder at this moment, either for technical difficulties in the implementation, unclear specification of desired behavior, or simply due to lack of time. We'll continue implementing some of these scenarios gradually in the future.

Rename event handler method in the form class

The user invokes rename refactoring on the method or some of its calls.

Changes done by standard Java refactoring:

  • rename the method and all calls to the method in non-guarded code

Desired changes done by GUI builder:

  • change the event handler name in form metadata
  • update calls in the generated code
  • update the event handler method itself

Rename event handler parameter

The user invokes rename refactoring on the event's variable name.

Rename @action method

The user invokes rename refactoring on an @action method (used by Swing Application Framework) or some of its calls.

Changes done by standard Java refactoring:

  • rename the method and direct calls to the method in non-guarded code

Desired additional changes:

  • rename the keys of action resources in corresponding properties file
  • update the action name in form metadata
  • update the string parameter in java code used to obtain the action via name
  • in guarded code (simply regenerate the code)
  • in non-guarded code (tricky)

Rename bean property

The user invokes rename refactoring on the getter and setter methods (representing a property of the component class).

Changes done by standard Java refactoring:

  • rename all calls to the property getter/setter method in non-guarded code

Desired changes done by GUI builder:

  • update the property name in form metadata
  • update the getter/setter methods in generated code
  • update binding - paths that contains the property

Can be in: form superclass, or component class used in the form.

General problem: How to handle bean pattern changes?

This includes renaming property getter/setter methods, listener class and its methods, event object class, the listener adding method, etc. Besides the mentioned fact that the new class does not exist yet, so the new configuration can't be used directly (also not found via BeanInfo), there is also a problem in that the changes aren't done at once. Unfortunately there is no refactoring for logical changes in bean structure, e.g. renaming a property which would rename both getter and setter methods at once. Doing it by renaming the methods separately leads to an inconsistent state when just one method is renamed at one moment. With events this can be even more complicated.

As for property renaming, the GUI builder can handle the cases separately:

  • changes in setter methods are relevant for setting the properties or binding to them (binding targets),
  • changes in getter methods for cases where the property is used as form connection or binding source.

Suggest not to support changes in component events via refactoring. It's too complicated to get over the intermediate states. We should make sure there is a way to fix the form after the event change is done. Should also be covered in help or FAQ.

Propery type changes

The main problem with changing the type of a property is that there is the value of the old type stored/serialized in the .form file. Such a property should be reset (no value stored, no code generated).

Moving/copying resource files

When a properties file with app framework resources is moved or copied to another package, the resource files that the properties refer to (typically images) should be moved/copied as well. Since relative resource name is typically used, it needs the resource file (image) in the target resources package as well. See also issue 105850.

If full resource name is used instead of a short (relative) one, another problem appears - not updating when renaming packages - see issue 125999.

Resources refactoring (finding usages)

In general, when a resource file is moved or a key in a properties file changed, corresponding updates should be done on all places that use the affected resources. Mostly this relates to moving the properties file used for internationalization, or e.g. moving an image file - generally any resources referenced by a string resource path. OTOH code that identifies the resource using a class (e.g. via NbBundle.getBundle(MyClass.class) or Swing App Framework resources) gets updated automatically by the standard java refactoring.

Ideally there should be a similar machinery to java file rename and variable rename, searching for all resources usages, etc. The scope of updates can potentially span the whole project and all projects depending on it. We don't plan to do that for now, i.e. updating java code based on changes in resource files. We'll try to make sure the other way works, i.e. updating resources based on changes in java source. Plus we'll try to update all usages when a package is renamed. But only within this package and only usages managed by the GUI builder (internationalization, app framework resources, generated code only).

Update palette items

If a component class is renamed/moved and it is present in the palette, the corresponding palette item should be updated to the new class. (Not sure if this doable for all type of palette items and not only when installed from projects.)

Other - undesirable changes

  • Renaming initComponents() method
  • Renaming auxiliary local variables - e.g. gridBagConstraints, or variables used for setting nested properties
  • Renaming FormListener innerclass
  • Incompatible changes in bean pattern or other specialized methods (edge cases)

User view (UI)

The user invokes Java refactoring as usual. If they choose Preview, all the individual changes in source code are shown, except the changes in guarded code - these changes are combined into one item in the preview, displayed e.g. as "Update generated code". If updates in properties files are needed, they'll have its own item, e.g. "Update properties files with resources". (The display name might be a bit more specific for some types of operation, e.g. for moving resources out of a package.)

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo