This handout describes how to perform common Java development tasks in Eclipse and on the command-line.

Contents:

Using the Unix Command Line

A few CSE 331 tasks require connecting to a Linux machine and running some commands from the command-line. Understanding the instructions below may require some basic understanding of how to use a shell to perform command-line actions. That is described (in more depth than we need) in CSE390A, which has materials posted online. Alternately, you can read the Unix tutorials provided by the student ACM chapter. While these tutorials are old and have some dated information about machine names and such, the basics of the Unix command line have not changed in decades.

Running Automated Tasks with Ant

Ant is a tool that can be used to automate many common tasks, such as compiling, testing, and running code. It is also used to validate a CSE 331 assignment submission. The instructions for Ant are stored in a “buildfile” named build.xml in each assignment's directory.

The buildfile specifies a set of targets that it supports, such as build and test. Note that the “help” target will output information about the supported targets in our buildfile. The validate target works only on attu.

To run Ant for assignment N from the command line, do the following:

cd ~/workspace331/cse331/src/hwN
ant target

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.

To compile all source files for a particular assignment, change your current directory to ~/workspace331/cse331/src/hwN/, where N is the desired assignment number. Now type on the command-line:

ant build

This will run an Ant script that uses the instructions denoted in build.xml 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.

If you would like to manually compile files without the use of an Ant script, you can use javac to compile one or more source files into class files for execution by the Java interpreter. The following commands:

cd ~/workspace331/cse331/src
javac -Xlint -d . -g [more options] hwN/file1.java hwN/file2.java ...

will generate class files hwN/file1.class, hwN/file2.class, etc., for each specified source file. Type "man javac" at the attu prompt for more information on javac options. You should almost always use the -g option, which will provide improved debugging output, and also the -Xlint option, which provides stricter compiler warnings.

Running Java Programs

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

Here is how to run Java programs from the command-line:

cd ~/workspace331/cse331/src
java -cp ../bin -ea hwN.theClassYouWantToRun

The -cp flag tells java where to find the .class files produced by javac, which contain the compiled source code. And the -ea flag enables assertions.

For example, if you wish to run the PolyGraph class from hw1, you would run:

java -cp ../bin -ea hw1.PolyGraph

Note that you do not include .java or .class at the end of the class name.

Testing Java Programs with JUnit

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

For more information, visit:

The test Ant target can be used to run the tests for each homework.

To run JUnit without using Ant, change to the ~/workspace331/cse331/src directory and invoke java org.junit.runner.JUnitCore for the text interface with the name of the test class as a parameter. For example, if I wanted to run RatTermTest, I could type:

cd ~/workspace331/cse331/src
java -cp ../bin:../lib/junit-4.11.jar org.junit.runner.JUnitCore hw1.test.RatTermTest

Here, we need to add lib/junit-4.11.jar to the class path. This jar file contains the .class files for JUnit itself, including the class file for org.junit.runner.JUnitCore.

Using javadoc to generate specs

Oracle's Java Development Kit includes javadoc, a tool that produces specifications from source code annotated with special comments. The comments may include "tags", which are introduced by an at-sign (@). (In addition to the standard javadoc tags, CSE 331 includes some custom tags used only for this course.)

Here is how to use the tool from the cse331/src directory:

Notes and Troubleshooting:

After running the ant doc target, you should check the output. You may find that you need to add line breaks (<br>) or paragraph breaks (<p>) to your javadoc comments for readability. Also, if you omit certain tags, subsequent text may fail to appear in the output. Finally, since much of the text of javadoc comments is inserted in a HTML document, you must be careful with text that can be interpreted as HTML markup, such as the less-than (<) and greater-than (>) characters. For instance, if you write:

@effects Adds <x> and <y>

then <x> and <y> will be interpreted as HTML tags in the output (and won't be displayed by a browser). It's usually better to just write

@effects Adds x and y

Report any weird behavior or complaints about javadoc to cse331-staff@cs.washington.edu.

Cloning the project from GitLab

You always edit your own personal copy of files that are under git control. Before you can make such edits, you must “clone” your own copy of the repository's master files. This means that you are copying code from the master branch from another source (GitLab in our case) into your own local, personal copy. You need to do this step only once at the beginning of the quarter. If you are tempted to use this command at other times, you most likely want git's “pull” command, which incorporates changes from the repository into your existing local copy. In the case that you plan to work at both UW CSE and home, you will need to do these setup steps both while logged into a department machines and from your home computer so you have a local copy on both machines.

The following instructions assume you wish to clone your personal Gitlab repository that is located at https://gitlab.cs.washington.edu/cse331-17au-students/cse331-17au-YourCSENetID. Make sure this URL takes you to your own project!

Execute the following commands at the Linux prompt to check out the project to ~/cse331-17au-YourCSENetID:

  cd ~/
  git clone git@gitlab.cs.washington.edu:cse331-17au-students/cse331-17au-YourCSENetID.git

Note for those who are new to the command line: When you try to type passwords in the command line, you may be alarmed that you can't see any text entered. To protect your password your typing simply isn't being shown. Just type your password as normal and press enter.

Pulling Changes from Gitlab

Git's "pull" command updates your local copy of files to reflect changes made to the repository by other people (or by you when working on a different computer system). The only changes made by people other than you will be made by the CSE 331 staff when we are adding new homeworks to your repositories. If you work at home and at UW CSE, you will need to commit and push on each machine when you are done on one machine and then pull when you start on another machine. That will propogate your changes to local machine.

Git usually does a good job of merging changes made to multiple copies (say, the copy on your home computer and the copy on attu) even if those changes are to different parts of the same file. However, if both people change the same line of a file, then git cannot decide which version should take precedence. In this case, git will signal a conflict during git pull, and you must resolve the conflict manually. This can be an unpleasant task.

To minimize the possibility of conflicting changes being made simultaneously, you should pull frequently and commit/push frequently.

To update your local copy on the command line, go to the root of your repository (e.g. ~/cse331-17au-YourCSENetID) and run:

git pull origin master

or just

git pull

which defaults to using master. This command will display a list of files that have been updated.

Committing Changes

After making changes to, adding, or removing files, you must “commit” your changes to git. This step will cause git to record your changes to the repository, so that your changes are backed-up and available to other people working on the repository, or to you when working on a different computer system.

Be aware that in git, committing changes does not change the remote copy of your repository on GitLab. To do this, you must “push“ a single (or series) or commits to the remote repository

In general, you should “pull” any new files or changes before committing your latest code. (And, if the pull results in any conflicts, you should resolve them before committing.) If you forget to pull, git will abort and remind you to pull first.

It is a good idea to commit your changes frequently. It backs up your work, thus enabling you to revert to an earlier version of your code if you find yourself going down a wrong path. Also, when you are working with others, it minimizes conflicts.

To perform a commit on the command line, first, enter the directory in which the file(s) you wish to commit are located. For example:

  cd ~/cse331-17au-YourCSENetID/src/hwN

Next, to list all the changes you have made since the last git pull, type:

  git status

This will print some output saying either you have no changes, or show your staged (to be committed), unstaged (not to be committed), and untracked (files not added to git) files. Untracked files show up when you create a new file in a directory which is under git control. Git will not automatically add these files to the repository to avoid extraneous files from being added.

Below is an example of output you might see in a git status:

  Changes to be committed:
    (use "git reset HEAD ..." to unstage)

    modified:   Ball.java

  Changes not staged for commit:
    (use "git add ..." to update what will be committed)
    (use "git checkout -- ..." to discard changes in working directory)

    modified:  Box.java

  Untracked files:
    (use "git add ..." to include in what will be committed)

    NewFile.java

Now you can add a file (or directory) as follows:

  git add NewFile.java

Then, you can commit your staged files to the local git repository by running:

  git commit -m "a descriptive log message"

Alternatively, you can stage (add) and commit all of your unstaged commits in one command as follows:

  git commit -am "a descriptive log message"

If you omit the message flag -m "a descriptive log message" from your commit command, git will throw you into an editor where you can enter a message. Remember, at any time you can check the git status and see which files are staged, unstaged, and untracked.

Adding and committing files only stores the changes in the local (working) copy of your repository. To update the remote GitLab copy of your repository and store all of your locally committed changes there, use the push command after you have committed the changes you want to save.

  git push

You must be sure to push your changes, or they will not be stored in the remote GitLab copy of the repository and, in particular, will not be available when the CSE331 staff pulls files from your repository for grading.

Pushing Changes to Gitlab

Git commits exist only in your local copy of your Gitlab Repository. Pushing your changes will update your master repository on Gitlab. Make sure to do this! Grading your homework assignments requires the work you have to done to exist in the original repository. If it does not, when the TAs check out your repo for grading, they will be unable to see the work you have done.

When commiting your changes, if you chose to do the Commit and Push option, then no other work is needed. But if you just hit Commit, then follow these steps to push your commits to your original repo:

To push your last comitted local changes to the repository on the command line, go to the root of your repository (e.g. ~/cse331-17au-YourCSENetID) and run:

git push origin master

or just

git push

which defaults to using master.

Tagging Commits

In git, commits can be “tagged“ with a short phrase without spaces. This can be used to mark important versions of the repository, like an alpha-1.0 or release-version. For CSE 331, tags are required to mark final versions of assignments that are ready to be turned in. The correct tag to use for a final version of an assignment in your repository is hwN-final, where N is the homework number (e.g., hw3-final).

To tag the most recent commited version at the command line, go to the root of your repository (e.g. ~/cse331-17au-YourCSENetID) and run:

git tag -a TAG_NAME -m "MESSAGE"

where TAG_NAME is a name for the tag (usually, something like hw3-final in our case) and MESSAGE is any commment you want to leave for yourself about the tag (e.g., "final version of hw3").

(It is important to use exactly this command for creating tags. Some of the other commands you can find in the Git documentation create "lightweight" tags that cannot be pushed to the server.)

The command above creates the tag in your local repository, but you also need to push it to Gitlab. That is particularly important when turning in your homework because the staff uses the hwN-final tags to figure out which version of your code to grade. If your tag is not pushed to Gitlab along with your code, the staff will not know which is your final version.

You can push tags just by adding the --tags command to git push:

git push origin master --tags

This command should display that the names of the tags that were pushed, so if you create a tag and then push but do not see the tag listed, you may have done something wrong. (You can always double check by cloning another copy of your master repository and seeing if the tag shows up there.)

Resolving Conflicts

When you pull changes into your local repository and you have local changes that have not yet been pushed, git tries to merge the changes together. Usually, it succeeds.

The most common case of this is when the staff pushes out new sets of starter files for each homework. After this happens, you may be unable to pull any changes until your local copy is all up to date with the new starter files. This is especially likely if you have made commits that you haven't pushed to GitLab yet.

Usually, git can perform these merges without any difficulties. However, sometimes git is unable to merge the files together when there are two different changes to the same line of a file. In this case, git will signal a conflict during the pull such as Automatic merge failed; fix conflicts or you may see the notice that You have unmerged paths.

Git conflicts are rare — most students will never encounter one — but if you do get a git conflict, you need to resolve it. This is a very brief primer about resolving conflicts; you can read the git documentation to get the full story. Also, it's better to prevent a merge conflict than to have to resolve it later on.

On the command line, to see the status of all your files, run:

git status

This will tell you, for each file and directory, whether it is currently in a conflicted state or not, i.e., whether that files contains local changes that conflict with the changes it is trying to integrate.

When git detects a file conflict, it changes the file to include both versions of any conflicting portions (yours and the one from the repository), in this format:

  <<<<<<< filename
  YOUR VERSION
  =======
  REPOSITORY'S VERSION
  >>>>>>> 4e2b407... -- repository version's revision number

For each conflicting file, edit it to choose one of the versions (or to merge them by hand). Be sure to remove the <<<<<<<, =======, and >>>>>>> lines. (Searching for "<<<" until you've resolved all the conflicts is generally a good idea.)

Once you have made these edits, then you can tell git that you have resolved the conflicts by staging the file as you normally would:

  git add src/hw2/test/SpecificationTests.java

Adding and Removing Directories

Git does not track directories like regular files. It only keeps track of the individual files and creates the directories that they reside in as necessary. So, if you create a directory, with the usual command

  mkdir dirname

git will not notice its existence until you add a file from that directory into your commit.

To delete a directory or file from the repository, use the standard rmdir or rm command. To remove a directory and all of its contents, use:

  rm -rf dirname

After adding or deleting a directory, you must perform a commit for the change to be reflected in the repository.

Tracking Changes

To see the change log, which lists all of the changes that have been comitted, use the command:

  git log

To see differences between the working copy and the repository's latest copy:

  git diff filename(s)

Omit filename to see differences for all files. Each commit is associated with a long hash value, which you can see in git log as commit 2d03d7...

To see changes compared to a particular commit version, enter:

  git diff REVISION filename(s)

Where REVISION is either a commit hash, like 2d03d7... or HEAD for the repository's most recent master version.

Viewing an old version of a file

You can show an old version of a file under git control with commands like the following:

  git show HEAD:MyFile.java
  git show 7ff8dc80:MyFile.java
  git show HEAD@{2013-03-14}:MyFile.java

As seen in the first command, HEAD means the most recent commit on your local copy of the repository. The second command uses a commit hash and the third uses a date.

You can also revert to an older version of a file under git control:

  git checkout HEAD MyFile.java

This command changes your working copy — that is, your local directory — but it does not change the repository. Do not attempt to edit the old version of the file in your working copy. Doing so will result in nasty merge conflicts and confusion.

To reset all of the files under git control to a previous version, use the following command:

  git reset HEAD

Note, checkout and reset are complicated and can have adverse affects on your local repository. You MAY lose data playing with these commands, and you should only use them with full understanding of what they do.

You should save a copy of the file (e.g. git stash) somewhere, then git pull your working copy to the current version of the file. Now, edit the current version in whatever way you like, possibly copying some or all of the differences from the old version that you saved. You can discard the old version when you are done; there is no need to check it in into GitLab.