CompileOnSave

FaqCompileOnSave is probably newer.

Contents


Motivation

Compile on Save (also known as Incremental Compilation) is highly requested feature, especially from users moving (or want to move) from Eclipse. This feature significantly speeds up edit/compile/deploy/test cycle.

Application is always compiled and ready to run. Even application under development with errors can be run, debugged and deployed. Test run is almost instant, since build is not required. This feature brings new dynamic programming environment normally associated with interpreted languages, where repetitive compile/debug/test cycles are smooth and fast. For instance user can debug application which contains errors. When erroneous code is reached, application stops in debugger, user can fix compile errors and save it. But save action might be connected to fix and continue feature in debugger. Application is lively fixed and user can continue testing his application.

In Java EE area there is a big overhead for the developer. In order to see the results of the change he has to redeploy (restart, reload) the application. The feature can be implemented in two levels, depending on the support provided by the server:

  • automatic reload of the application on save (save-refresh instead of save-deploy(run)-refresh)
  • automatic reload of class (resource) in runnign application (even faster)


Description

There will be a new option to turn on/off automatic building of project. Modified source will be compiled immediately after modifications are saved. It will not be required to invoke build to be able to test the project.

Warning: the following is a draft and is a subject of change.

Source files will be compiled into .class files stored in ${netbeans.user}/var/cache/.../ during initial scan and will be compiled each time the source files are changed. The ${netbeans.user}/var/cache/.../ will therefore contain .class file corresponding to the sources at all times. The .class files will be copied into the project specific build/classes directory as necessary.

Java SE

The J2SE-like projects will allow to "test"-run the project. This "test"-run will bypass the normal project execution (e.g. ant script) and execute classes from build/classes directly.

The following cases may occur:

  • the user requests "test"-run, build/classes is either empty, or does not contain .class files produced by NetBeans. Content of ${netbeans.user}/var/cache/.../ should be copied to build/classes before execution.
  • the user requests "test"-run, build/classes contains classes produced by NetBeans. The project can be directly executed.
  • user saves a java source file, build/classes is either empty, or does not contain .class files produced by NetBeans. The resulting .class file is written only to ${netbeans.user}/var/cache/.../.
  • user saves a java source file, build/classes contains .class files produced by NetBeans. The resulting .class file is written to both ${netbeans.user}/var/cache/.../ and build/classes.
  • user invokes different action than "test"-run on the project, build/classes is either empty, or does not contain .class files produced by NetBeans. The action is executed without changes.
  • user invokes different action than "test"-run on the project, build/classes contains .class files produced by NetBeans. The project is cleaned (so the .class file produces by NetBeans are discarded) and the action is executed.

Supported "test"-run actions should be "run", "debug", "test" and their "-single" variants.

Java EE

The build mechanism described for Java SE will be used in order to handle the build directory update (however in case of EE app classes are not directly located in build/classes). Java EE projects will execute standard run action in order to build and deploy project to server. Javac task will use either copying of files from cache or real javac.

Once the project is running the responsible serverplugin will be notified on each class change. The responsibility of the plugin is to do whatever is needed to reaload the class (if supported at all). For some plugins it means reload of an application (tomcat) for others this means nothing (GFv3 with class realoading).

  • Class Reloading Support
  • Class reloading feature will be (optionally) supported only by serverplugins implementing directory based deployment.
  • Partially compilable classes will be reloaded as well. Different behaviour (reload only valid classes) could be very confusing. Example: User see uncompilable class in the editor, however when he reload the page in the browser everything goes fine - he starts thinking what's wrong, whether reload works correctly and what version of class is actually deployed.
  • Debugging Mode
  • Automatic deploy won't work while debugging (there is "apply changes" button, perhaps this action could be done automatically).
  • Non Java Resources
  • Should be addressed either by listener in java infrastructure (clean solution) or by listener on project dir (dirty one).
  • Frameworks
  • Just ordinary reload of non-Java resources. No special support for 6.5.
  • EE Project Depending on Java SE Library Project
  • No support - limitation placed by EE specification - library is always JAR placed in WEB-INF/lib even in case of directory deployment.

Open Problems

Location of classes to execute

Note on resources: currently, when the J2SE-like project is executed, we translate dist.jar into build/classes:src, so the user's code sees the resources through ClassLoader.getResource(). Will not see the resources through Class.getProtectionDomain().getCodeSource().getLocation(). Also, this approach does not allow preprocessing of resources (templates in src/ which are processed into real resources in build/claases). Likely not a very important usecase. We might end up with copying the resources from src/ into executable location to support web projects.

  • standard project's output location (build/classes):
  • pro: the user's code expects to be run from here
  • pro: resources could be easily copied there, so the users code can access () Could also support processing of resources while copying.
  • pro: user's code cannot affect IDE behavior any more than it can in NB6.5
  • con: slower first run - the .class files need to be copied there and the .class files need to be stored on two places: into java.source's caches and build/classes while compiling
  • con: needs help from the projects (all action except "test"-run need to clear build/classes when there are classes generated by the IDE).
  • java.source's private caches (var/cache/index/0.X/sX/classes):
  • pro: faster first run, no need to copy the .class files on compile
  • pro: no help needed from the project types
  • con: the structure of this directory becomes API (cannot be changed)
  • con: the user's code can affect the IDE behavior (if incidentally or accidentally removes or rewrites a .class file or a group of .class files from the cache, the IDE will have troubles)
  • con: difficult or impossible to copy resources there (may also affect IDE behavior inadvertedly)
  • con: the user's code does not expect to be run from there.
  • con: EE - need to build whole EE app structure "around" the classes
  • a designated cache directory in var/cache used only for execution:
  • pro: user's code cannot affect IDE behavior any more than it can in NB6.5
  • pro: no help needed from the project types
  • pro: resources could be copied there
  • pro: EE - limited file locking on windows
  • con: slower first run - the .class files need to be copied there and the .class files need to be stored on two places: into java.source's caches and the designated directory while compiling
  • con: EE - slower first run - whole EE app have to be copied to cache
  • con: the user's code does not expect to be run from there.
  • a location selected by the project (any of the above except java.source's private caches):
  • pros: project type may choose from the above pros the ones it requires, except "faster first run, no need to copy the .class files on compile"
  • con: slower first run - the .class files need to be copied there and the .class files need to be stored on two places: into java.source's caches and the given directory while compiling
  • con: if the project type wishes to use build/classes, it needs to clean it before non-"test"-run action.
  • con: could be much more error prone as this in fact combines all different layouts "together"

UI

UI Specification is available.

No new actions are introduced to the UI. The ordinary Run/Debug actions will perform either "test"-run (i.e. will use compile-on-save), or the 6.1-like run action (i.e. using the project's ant script) depending on the project's settings. The user will be able to switch between these two semantics of the Run/Debug action in the Project Properties. The pre-existing projects will use 6.1-like run action by default, newly created projects will use the "test"-run action by default.

There will be additional support when a J2SE-like project is run in the debugger:

  • the debugger will automatically stop on the corrected compilation errors
  • save of a Java class during "test"-debug will automatically trigger "Apply Code Changes". If it won't be possible to apply the changes, a warning

dialog will be shown to the user (with a "Do not show again" checkbox). Success or failure of the automatic "Apply Code Changes" will be noted in the status bar

The Build and Clean actions will be disabled when the "test"-run is enabled for the project. The Clean and Build action state will not depend on the "test"-run setting.

J2SE Projects

In particular, the following changes are proposed to the J2SE project properties:

  • remove "Track Java Dependencies" checkbox from the Build/Compiling tab
  • add "Enable Quick Run" checkbox to the Run tab

Effort estimation

2 engineers/1 month (J2SE Part)

Dependencies

Need cooperation with javac team.

Impacts

Architecture

Various actions (run file, debug project, ...) need to work with IDE-compiled classes, not those created by e.g. an Ant script. Need to have APIs to perform these actions, as they would be needed by many different project types (not all Ant-based).



Impl should provide a FileBuiltQueryImplementation for *.java.

Class org.netbeans.modules.j2ee.deployment.plugins.spi.IncrementalDeployment will be enhanced in following way (subject to change):

public abstract class IncrementalDeployment {

    ...

    /**
     * Returns <code>true</code> if deploy on save is supported, <code>false</code>
     * otherwise. If this method returns <code>true</code>
     * {@link #deployOnSave(javax.enterprise.deploy.spi.TargetModuleID, org.netbeans.modules.j2ee.deployment.plugins.api.DeploymentChangeDescriptor)}
     * must provide (reasonably fast) redeploy functionality.
     *
     * @return <code>true</code> if deploy on save is supported
     * @since 1.47
     */
    public boolean isDeployOnSaveSupported() {
        return false;
    }

    /**
     * Performs reload of the artifacts when the deploy on save is requested.
     * All chenged files are alredy prepared at required location before this
     * call. Returns object tracking the reload.
     *
     * @param module module owning the artifacts
     * @param desc description of changes
     * @return object tracking the reload
     * @since 1.47
     */
    public ProgressObject deployOnSave(TargetModuleID module, DeploymentChangeDescriptor desc) {
        throw new UnsupportedOperationException("Deploy on save not supported");
    }
}

This method will be called by infrastructure each time the class has been changed (deployed project only).

API

Documentation

Testing

Performance

  • Save operation will be slower.

Risks

TBD

Additional information

Sources

The branch for Compile on Save is here:

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