Editing, Compiling, Running, and Testing Java Programs

This handout describes how to perform common Java development tasks in the Allen Center software labs with IntelliJ and the command line.

Contents:

Using the Unix Command Line

A few CSE 331 tasks require connecting to a Linux machine and running commands from the command line. To understand the instructions may require some basic understanding of how to use a shell to perform command-line actions. This material is covered (in more depth than we need) in CSE391, which has materials posted online.

Starting IntelliJ

You should have already performed the initial setup. If you are working on your own computer or a CSE Linux Home VM, and you are working through the handouts in the recommended order, you should have installed IntelliJ. Else, it is installed on the department machines.

When importing up your project on IntelliJ, use the Version Control instructions to setup your project. You should pick Gradle as the external model you are importing the project from.

Starting IntelliJ on Linux

You may be able to click and icon or search for IntelliJ in your program launcher.

Otherwise, go to the directory where IntelliJ is installed and then go into the bin subdirectory. Then type the following command:

./idea.sh

IntelliJ will start up, display a splash screen, and then potentially show a settings import dialog:

Screenshot:
IntelliJ Workspace Selection in Windows

IntelliJ is asking you whether to import settings. If you have used IntelliJ before, pick the first option and locate the settings. Otherwise, pick the second option.

Starting IntelliJ on Windows

From the start menu, search for IntelliJ.

IntelliJ will start up, display a splash screen, and then potentially show a settings import dialog:

Screenshot:
IntelliJ Workspace Selection in Windows

IntelliJ is asking you whether to import settings. If you have used IntelliJ before, pick the first option and locate the settings. Otherwise, pick the second option.

IntelliJ generics errors configuration

We expect your code to not have any generics-related problems. For example, the following code is unacceptable:

List myList = new ArrayList();
myList.add("foo");

The generic type List of myList should be parametrized, for instance, to String by replacing the first line with List<String> myList = new ArrayList<String>(); Note that List<String> myList = new ArrayList(); is also incorrect.

By default, IntelliJ does not show generics problems as errors. You can run a generify tool to ensure that your code contains acceptable generics.

To make this configuration, go to Refactor » Generify..., update the preferences as required and click on Preview. Use this to ensure that all the changes being made are correct, and click Do Refactor.

Opening Files; Managing Multiple Files

Open the Project View in IntelliJ if you are not already using it (View » Tool Windows » Project).

You can open multiple files in IntelliJ by double-clicking each of them from the Project View pane. Once you have multiple files open, you can switch between them quickly by holding down Ctrl and hitting Tab to bring up a dropdown box of open files, and then using the arrow keys to select the file whose editor you wish to bring into focus. You can also navigate through different files using the tabs on top of the editor pane.

Creating New Files

New Java files

To create a new Java source file (with the .java extension), right click on the package you want to add the file to New » Java Class. A window will pop up, asking you for the name of the class. Choose a name for your class (e.g. MyClass) Type this name in the "Name" field and click Finish.

(If you want your new class to be executable, it will need a main method.)

Screenshot: New Java Class

New Text files

There is a similar procedure for creating new non-Java files such as text files. Right click on the directory you want to add the file to New » File. In the resulting dialog box, type the desired filename. If you want to create a new directory, you can do so by appending the directory name in front of your desired filename. For example, if you want to create a file problem0.txt in the directory hw1/answers, but the answers directory does not yet exist, you can choose hw1 as the parent directory, and then type answers/problem0.txt as the file name, and IntelliJ will create the new directory and file for you.

Editing Java Source Files

Here are some useful actions that you can perform when editing Java code:

Autocompletion

Autocompletion is the ability of an editor to guess what you are typing after you type out only part of a word. Using autocompletion will reduce the amount of typing that you have to do as well as the number of spelling mistakes, thereby increasing your efficiency.

IntelliJ continuously parses your Java files as you are editing, so it is aware of the names of variables, methods, etc... that you have declared thus far.

CTRL+Space can be used to autocomplete most things inside the IntelliJ Java editor. For example, if you have declared a variable named spanishGreeting in the current class, and have typed the letters spanishGree in a subsequent line, IntelliJ can infer that you mean to type spanishGreeting. To use this feature, press CTRL+Space while your cursor is at the right of the incomplete name. You should see spanishGree expand to spanishGreeting.

IntelliJ can also help you autocomplete method names. Suppose you have a variable myList of type List, and you want to call the method clear. Begin typing "myList." — at this point, a pop-up dialog will display a list of available methods for the type List, and you can select the appropriate method with the arrow keys. You can force the popup to appear with CTRL+Space.

Organizing Imports

You can press CTRL+ALT+o to organize your imports in a Java file. IntelliJ will remove extraneous import statements and try to infer correct ones for types that you refer to in your code but have not yet been imported. (If the name of the class that needs to be imported is ambiguous – for example, there is a java.util.List as well as a java.awt.List – then IntelliJ will prompt you to choose which one to import.)

Viewing Documentation

Although you can directly browse the Java 11 API and other documentation at the Oracle website, it is often useful to be able to cross-reference parts of your code with the appropriate documentation from within your editor.

Note that you need to generate the API documentation locally before you can view docs for classes in the assignment. Use the javadoc task on gradle to do the same.

IntelliJ provides multiple ways to look at documentation of code directly from the IDE. Their website contains documentation on how to do this.

If you are adding documentation of code that is written by you, you will need to prepend the file location with file:///.

Running Automated Tasks with Gradle

Gradle is a build system, which automates development tasks. To invoke Gradle, run the command ./gradlew in directory ~/cse331-19sp-YourCSENetID.

The most common command is ./gradlew build. It runs the "build" task, which checks your program for common errors, compiles your program, runs tests, and generates documentation. Using a build system like gradle is better than you having to remember to run each of those tasks separately. Run ./gradlew tasks to see a list of other tasks you can use.

Command line

To run Gradle from the command line:

cd ~/cse331-19sp-YourCSENetID
./gradlew target

In the above, replace target with the name of the task you want gradle to run. If you use Windows, change ./gradlew to gradlew.bat.

Command line troubleshooting

A timeout error such as "read timed out", or "Could not resolve all artifacts", indicates a network connection problem. Try your command again. If that does not work, then add the --offline command-line option to your ./gradlew command.

If you get

Could not create service of type ScriptPluginFactory using BuildScopeServices.createScriptPluginFactory().

and rerunning the command gives the same error, then email support@cs, pasting in the exact command you ran (including the directory you ran it from) and the exact output.

If you get

Execution failed for task ':clean'.
> Unable to delete file: ...

then run ./gradlew cleanByRenaming

If Gradle hangs and produces no output for a long time, run the following command

kill -9 $(lsof -t +D ~/.gradle) && rm -rf ~/.gradle

(which itself may take many seconds, but generally less than a minute, to run) and try again. If the command fails, you can run this instead:

mv ~/.gradle ~/.gradle-DELETEME

IntelliJ

To run Gradle in IntelliJ there are 2 different tool windows you could run it from:

  1. Using the Gradle tool window on the right side of the IntelliJ. (If you do not have a Gradle tool window on the right side, you can activate by selecting View > Tool Windows > Gradle)
    Screenshot: IntelliJ Gradle Tool Window

    You can select the task you want to run under each folder. For example, the command ./gradlew build on the command line is equivalent to selecting build > build in the tool window. For this class, most of the tasks you are able to run are under build, validation, and other.

    You can also run the task you want by clicking on the Execute Gradle Task icon, and typing in the name of the task you would like to execute.

  2. Using the IntelliJ Terminal tool window at the bottom of IntelliJ.
    Screenshot: IntelliJ Terminal Tool Window

    You will be able to run most ./gradlew comannd line targets on this terminal.

Compiling Java Source Files

You must compile your source code before running it. The javac compiler is used to transform Java programs into bytecode form, contained in a class file. Class files are recognized by their .class extension. The bytecode in class files can be executed by the java interpreter.

Command line

To compile all source files:

cd ~/cse331-19sp-YourCSENetID
./gradlew build

This will run a Gradle script to compile all the .java files into corresponding .class files. Note that if one or more of your files do not compile, you will receive error messages and no .class files will be generated for the files that do not compile properly.

IntelliJ

IntelliJ is set up by default to automatically recompile your code every time you save. Classes with compile errors are marked in the Project View with a red underline.

If your file is saved and IntelliJ says that it does not compile but you believe that it should, make sure that all of the files on which your file depends are saved and compiled. If that does not work, try refreshing your project or using Build » Rebuild Project to force IntelliJ to recognize the latest versions of everything.

Running Java Programs

Once you have compiled your source code into class files, you can execute it with the Java interpreter.

Command line

Typically, to run a program you will just type ./gradlew on the command line, possibly with a more specific target: ./gradlew target.

IntelliJ

To run a program, right click on the Java source file containing the main() method and choose Run 'FILENAME' where FILENAME is the file with the main() method.

There is also a button near the top-right-hand side of the IntelliJ window that looks like a
green 'play' button which will re-run the last application (or JUnit test, see below) that you ran.

Testing Java Programs with JUnit

JUnit is the testing framework that you will use for writing and running tests.

For more information, visit:

Running JUnit Tests

You can run JUnit from several different environments:

Command line

To compile your code and run tests:

./gradlew build

IntelliJ

JUnit is normally integrated with IntelliJ, but since we are using Gradle, we must tell IntelliJ to delegate work to Gradle.

  1. On the main menu, choose File > Settings for Windows and Linux or IntelliJ IDEA > Preferences for macOS
  2. Navigate to Build, Execution, Deployment > Build Tools > Gradle > Runner
  3. In the "Run tests using:" dropdown menu, select "Gradle Test Runner". Be sure to leave "Delegate IDE build/run actions to gradle" unchecked.

Now, if you run any tests, it will use Gradle to run it. To run any specific test file:

You can also run a specific test file from the command line using the --tests flag, such as in the following commands:

./gradlew test --tests packageName.SomeTestClass.someTestMethod
./gradlew test --tests *SomeTestClass.someTestMethod
./gradlew test --tests *SomeTestClass

The first two commands above will run a specific test method in a specific test class that you choose. The last one will run all the tests in a particular file.

To run all of the tests in your test suit, select Verification > test in the IntelliJ Gradle tool window.

A test result window should pop up near the bottom of the screen momentarily and run all the tests. Once the tests are done, you'll see a report of which tests failed and why: IntelliJ JUnit UI Example On the left, you can see a list of all tests classes run (in this case, only setup.FibonacciTest), as well as all test methods run within that class (in this case, there are four methods in that class). You may need to toggle the two buttons in the top left (marked with a blue box in the image) if you can't see all the tests - these buttons control which tests will be shown in the list below.

At the top-center of the window (indicated in the image by a red box) you can see a summary of all the tests run and how many succeeded/failed. You can see the status of each individual test on the left. In this example, the tests testThrowsIllegalArgumentException and testInductiveCase failed normally (the yellow "X") - that is, they failed because one or more of the requirements of the test were not met. By contrast, testBaseCase failed abnormally (the red "!"). This usually happens when an uncaught exception is thrown during the test, as is the case for this example. expectedIllegalArgumentException was the only test that passed. You can click once on any of the tests to see more details about why a test failed (and any System.out.print or similar output generated by the test). If a test failed abnormally, you can also see any relevant stack traces. These details show up in the right area of the window. In this example, testThrowsIllegalArgumentException is selected and we can see (highlighted by a red box in the image) a better description of what went wrong during the test.

You can also double-click on any of the tests in the left area to jump to that part of the testing code. Click the play button in the top left of the testing window to re-run all the tests shown, or the button right below it (play button on top of a red exclamation point) to re-run just the tests that failed.

CSE 331 JUnit Framework

Because your JUnit tests will likely have different class and method names than those of your classmates, there needs to be a standardized way of accessing every student's tests. Thus, each assignment comes with the JUnit test classes SpecificationTests and ImplementationTests. You will load all the JUnit tests you wrote in one of these two test suites.

SpecificationTests, as it name suggests, should contain only specification tests — that is, those tests that check only for features implied by the specification. Consequently, your specification tests should be valid tests for any other person's code that claims to satisfy the same specification, even if that implementation is inherently very different.

Conversely, ImplementationTests should contain implementation tests — that is, those tests that test only details that are specific to your implementation.

As an example, suppose you were implementing the following specification:

/**  Frobs the blarghnik.
  * @spec.requires b != null
  */
public void frob(Blarghnik b);

A specification test should never pass in a null parameter to this method — this would violate the specified pre-condition. However, your particular implementation might check for the null parameter and throw a NullPointerException. Your implementation test can safely exercise this case by passing in null.

Similarly, an iterator specification which does not specify the order in which elements are returned indicates that no specific order should be assumed in a specification test. Your implementation may happen to keep elements in a sorted list, and so your implementation test may wish to check that the elements returned by the iterator are sorted.

Before your submit each assignment, you should run tests and validate your assignment with ./gradlew build.

Using javadoc to generate specs

The javadoc tool produces API documentation (in HTML form) from source code annotated with special comments.

To run the Javadoc tool, issue this command:

./gradlew javadoc
You can find the generated API documentation, in HTML form, under build/docs/javadoc.

If IntelliJ fails due to unknown tags, you will need to add the tags to IntelliJ.

Javadoc tags

Your Java code comments contain "tags", which are introduced by an at-sign (@). The Javadoc tool formats these specially in the HTML output.

We have extended the javadoc tool to recognize additional CSE 331 tags, in adition to the standard tags. These additional tags declare specification fields for classes and requires, modifies, and effects clauses for methods. Note that all Javadoc tags must appear after all non-tag comments for classes and methods.

Customizing IntelliJ

You may need te specify the path to the git executable: In the Settings/Preferences dialog (Ctrl+Alt+S), select Version Control | Git in the left pane.

It is bad style to have tab characters in code files, because they display differently for different people. (Pressing the Tab key while using your editor is great, but that key should should insert spaces.) In IntelliJ IDEA, make sure that the Editor >> Code Style >> Default Indent Options : Use tab character checkbox is not selected.

331 extended Javadoc tags

IntelliJ will warn you about unrecognized the 331 Javadoc tags (@spec.*). There are two ways to eliminate the warnings.

  1. Disable the editor's Javadoc inspection.
    • On the main menu, choose File > Settings for Windows and Linux or IntelliJ IDEA > Preferences for macOS
    • Navigate to Editor > Inspections > Java > Javadoc and uncheck the box next to "Declaration has Javadoc problems".
  2. Add each of the extended tags as a known tag for IntelliJ.

    Using the keyboard shortcut:

    • Place the caret on the extended tag with a warning and press Alt + Enter.
    • Select "Add spec.* to custom tags".

    Using the settings panel

    • Open the Javadoc inspections settings by following the instructions in (1). You do not have to uncheck any boxes.
    • Select "Declaration has Javadoc problems" and naviage to Options > Additional Javadoc Tags and add all of the extended tags.

After you have done one of the above, the warnings for the extended tags will go away.

Google Java Format Plugin

Optionally, you could install the Google Java Format plugin to IntelliJ that will reformat your code using the google-java-format tool.

  1. On the main menu, choose File > Settings for Windows and Linux or IntelliJ IDEA > Preferences for macOS
  2. Navigate to Plugins
  3. In the search bar type "google-java-format" and select "Search in repositories".
  4. Install the plugin and restart IntelliJ. After you restart, you should be prompted to enable google-java-format for your project. Select "enable".

Troubleshooting IntelliJ

If the staff provides a new version of a library, IntelliJ will not automatically know about the library's new symbols (classes and methods). As a result, IntelliJ will not do completion and may issue warnings about them. To resolve the problem:

  1. git pull
  2. ./gradlew build
  3. In IntelliJ's Gradle window (View > Tool Windows > Gradle), click the refresh button at the end to refresh all libraries.