IntelliJ IDEA: Managing Dependencies

In this screencast, we’re going to take a look at managing dependencies in IntelliJ IDEA. We’ll look at different ways to add dependencies to your project, and how to add, update and remove dependencies using Package Search.

Related Links

Pair programming in Java with an 8 year old

Recently I asked my 8 year old if he would be interested in doing some Java programming with me, and he was. This was such a fun experience, I wanted to share it with you.

Why Java?

In the past, we have done part of a Scratch course by Felienne. So I know there are other programming languages out there that are made specifically for kids. However, I wanted to show him something that is a bit more like what his dad (also a software developer) and I do all day.

It was an explicit decision on my part not to bore him with Java syntax just yet, but instead to focus on what the program should do and getting a bit of understanding of how programming works. While most of the code was written by me, the behavior of our little application was based on our collective ideas.

Hello world!

We used IntelliJ IDEA Community Edition 2022.3, and I opened a new project using Java and Maven, thinking we would get started with a simple Hello World program (as you do).

New Project wizard in IntelliJ IDEA with Java and Maven selected, as well as JDK temurin-17
New Project wizard

It turned out that IntelliJ IDEA already includes the Hello World example when opening a new project, which was a nice surprise.

Hello world! program in Java
Hello world!

First, I asked him to run the program by clicking the run button (green triangle) in the gutter. He asked me what it means to “run” the program, so I explained this means having the computer execute the program, doing the thing the code tells it to do.

When we ran the program, we saw that the text “Hello world!” was printed in the command line. I tried explaining that “public static void main” is the main method, telling the computer where to start, but to be honest I’m not sure he understood that just yet.

Asking for user input

Next, I asked him whether he would like to print something else and what we would need to change in order to do so. He knew we had to change the green text (the String) to something else. He changed the word “world” in this String to his name and ran the program again.

My next suggestion was to ask the user for their name so the computer would be able to greet other people too. Here I briefly explained we would need some way to capture the user’s input. To do so, I added a Scanner and the variable “name”. After I made these changes, he ran the program and tested that it worked when he input his name.

A simple Java program using Scanner to output a question, capture the input and print the result
Asking for user’s name

Next, we discussed what else to ask the user. He wanted to ask for their favorite color and provide the “computer’s” favorite color as a response to their answer. We added another question and captured another variable to return to the user.

A simple Java program using Scanner to output a question, capture the input and print the result
Asking for name and favorite color

Selecting a language

Of course, while the kids speak some English, it is not their native language. So we decided to translate the output to Dutch to make it a little easier for him to understand. Next, he suggested we should give the user the option of using the program either in Dutch or in English. We started with a simple if/else statement and duplicated code blocks of asking the same questions in either Dutch or English, depending on the input.

A Java programming using an if/else statement to select a language
Selecting a language

He was quick to point out that we should think about what to do if the user provided a language or input we didn’t know. Good question! So we proceeded to add logic for that as well.

A Java program checking that input is a valid option before proceding.
Validate input

Next, we ran the program several times to check that it worked for each valid option, as well as (multiple) invalid options.

Next steps

Finally, we discussed what potential next steps we could take with this program. We had several ideas:

  • He wanted to know if it would be possible to remove the duplication somehow; for example, by getting the Dutch or English text from somewhere so we wouldn’t have to duplicate all the code. In our current program, the code for the Dutch version and English version is duplicated, meaning that for every additional question we want to ask the user, we have to make sure to duplicate that.
  • In one of my tests, I showed him that the computer would just capture and return whatever the user’s input was. The example I used was to answer “Hello, what is your name?” with a full sentence: “Hi, my name is Marit” to which the computer would reply “Hello Hi, my name is Marit, what is your favorite color?” which is a bit weird. So that is something to think about.

Takeaways

The most important thing is that we had fun. He was motivated to add new things to the program and to test that they worked. My choice to not focus on the details of Java syntax, but on the general program instead seems to have worked because he had fun and wanted to continue. He is already asking me when we can do this again, and has ideas of what we could do next.

The program was written based on his ideas and he did write some of it himself, mainly the Strings and some of the “System.out.println()” lines, after I showed him how to use IntelliJ IDEA live templates to do so; if you type “sout” and press Enter (or Return on Mac), IntelliJ IDEA will expand that to “System.out.println()” which he thought was very helpful.

What I noticed was that he was able to think about what the program should do, and had a rough understanding of how the code worked. Once we were done, he was able to explain our little program to his dad, and pointing to the relevant points in the code while explaining what they did. So I have the impression he has some understanding of how it works.

Overall, we had fun together coding and it was awesome to see how his mind worked when thinking about what the program should do and how, and how to test it. We are very much looking forward to continuing our little experiment.

Our code can be found on GitHub.

Viewing dependencies in IntelliJ IDEA

In this blogpost we’re going to take a look at different ways to view your external dependencies in IntelliJ IDEA.

Introduction

If you’re working on a real-world application, your project will probably use external libraries and frameworks. Occasionally, you might want to see which dependencies your project uses, for various reasons.

There are several ways to view dependencies in IntelliJ IDEA. Each view has a different focus.

Dependency management config file

You can find direct dependencies in the dependency management config file. Direct dependencies are the dependencies that your project depends on directly. They are declared in the dependency management config file.

One example is this pom.xml in a Maven project.

A pom.xml file opened in IntelliJ IDEA
Maven pom.xml file

Another example is the build.gradle in a Gradle project.

Gradle build.gradle file

Note that the dependency management config file includes only declared dependencies and not their transitive dependencies (or the dependencies that these declared dependencies depend on).

Project tool window

In the Project tool window, âŒ˜1 (on Mac) or Alt+1 (on Windows/Linux), under External Libraries we can see all the JAR files needed by our application, including the transitive dependencies. However, we cannot tell the difference between direct dependencies and transitive dependencies. One declared dependency might bring in multiple JAR files.

Project tool window

Build tool window

To see direct dependencies and their transitive dependencies, we can look in the Build tool window. There is no shortcut to open the Build tool window. We can open it by clicking Quick Launch in the bottom-left and selecting Gradle, or Maven depending on what we’re using.

Open the Maven Build Tool Window in the Quick Launch menu
Open the Gradle Build Tool Window in the Quick Launch menu

Alternatively, we can open it by using Recent Files, âŒ˜E (on Mac) or Ctrl+E (on Windows/Linux), and typing “gradle” or “maven”, or the name of your build system.

Open the Gradle Build Tool Window using the Recent Files popup

Open the Maven Build Tool Window using the Recent Files popup

The Build tool window shows you each IntelliJ IDEA module separately, and each module’s “Dependencies” folder shows you all your dependencies in a hierarchical structure. We can expand our dependencies to see their transitive dependencies.

Gradle Build Tool Window showing dependencies
Maven Build Tool Window showing dependencies

Dependency tool window

Finally, we can view and manage dependencies in the Dependencies tool window. The Dependencies tool window becomes available when the current project has at least one supported module. All types of dependencies are supported for Maven. For Gradle only a top level dependencies { } block is supported in the build script.

Since there is no shortcut to open the Dependencies tool window directly either, we can again use Recent Files, âŒ˜E (on Mac) or Ctrl+E (on Windows/Linux), and type in “dependencies” to open the Dependencies tool window.

Open the Dependencies Tool Window using the Recent Files popup

Alternatively, we can open it by clicking Quick Launch in the bottom-left and selecting Dependencies.

Open the Dependencies Tool Window in the Quick Launch menu

Here we can see our project’s direct dependencies. Select “All Modules” to see the dependencies for all modules, or select an indivual module to see the dependencies for that specific module. The Dependencies tool window shows direct dependencies, and not their transitive dependencies.

Dependencies Tool Window

We can see details about a selected dependency in the dependency details pane.

Dependency Details Pane

The dependency details pane displays the information about the selected dependency, such as:

  • Repository or repositories where it’s available, for example Maven Central
  • A description if it is available
  • GitHub information if the dependency sources are hosted on GitHub
  • The licence under which an open source library is available
  • A link to the project website, documentation and readme
  • List of usages in the current module.
  • Authors if available
  • Supported Kotlin or Multiplatform platforms if it is a Kotlin Multiplatform dependency

Summary and Shortcuts

Now we know the different ways in which we can view our project’s dependencies in IntelliJ IDEA, and the different focus for each view.

IntelliJ IDEA Shortcuts Used

Here are the IntelliJ IDEA shortcuts that we used.

NamemacOS ShortcutWindows / Linux Shortcut
Open / Close Project Tool Window⌘1Alt+1
Recent Files⌘EControl+E
Shortcuts

Related Links

IntelliJ IDEA: Viewing Dependencies

If you’re working on a real-world application, your project will probably use external libraries and frameworks. Occasionally, you might want to see which dependencies your project uses, for various reasons. There are several ways to view dependencies in IntelliJ IDEA. Each view has a different focus.

Viewing Dependencies

Related Links

IntelliJ IDEA: Resolving Merge Conflicts in Git

When you work in a team, you may come across a situation when somebody pushes changes to a file you are currently working on. If these changes do not overlap, the conflicting files are merged automatically. However, if the same lines were affected, Git cannot randomly pick one side over the other, and asks you to resolve the conflict. In this screencast, we’re going to take a look at resolving merge conflicts.

IntelliJ IDEA: Resolving Merge Conflicts in Git

Links

Selecting dependencies

This blogpost was also published on Medium.

Open source software is everywhere. Most likely you are using some open source projects either at work and/or in your side projects.

Pros and cons of using dependencies

One of the upsides of using Java as a programming language, is that there are libraries and frameworks available to do many of the things we want to do in our projects, but don’t necessarily want to write ourselves. Using existing libraries and frameworks helps us deliver business value faster.

Unfortunately, there are also downsides to using external dependencies. The most dangerous being when security vulnerabilities are found in libraries many of us use, like the Log4Shell vulnerability in the log4j logging library that was disclosed in December 2021 and the Spring4Shell vulnerability in Spring in March 2022. These vulnerabilities were so severe that we had to patch all our services ASAP. Even if the version of a dependency you use does not have any known vulnerabilities, you might need to update them for other reasons.

In addition, adding dependencies to your project also has an impact on the size of your binary. For example, Brian Vermeer has created a demo to show the number of lines of code written versus number of lines pulled in by Spring. Granted, he admits that “this was the most useless Rest endpoint you could ever write”, but this demo clearly shows how the code pulled in by dependencies can overshadow to amount of code you write yourself.

A balancing act

This means we have to think carefully about which dependencies we want to use. Some developers try to add little or no external dependencies to their projects. This is one way to avoid the downsides mentioned above. Another argument may be that it gives you more control over the code in your project. Of course, the downside here is that you have to write everything yourself, which might not always be the best idea. For example, I’d rather use JUnit and Mockito than write my own testing and mocking frameworks.
On the other hand, we shouldn’t just add any library or framework, as we’ll have to not only implement them now, but also maintain them over time. Or even remove them in the future, which is not always easy. Some projects, like Lombok or Reactor, will be present throughout your code base and hard to remove should you ever want to (for example, when moving to Kotlin & coroutines).

Most of us will be somewhere in the middle; we don’t want to write everything ourselves, and we will use certain frameworks and libraries that offer us some useful functionality, but we also want to make sure we can continue to maintain our project without having to (urgently) update dependencies or rewrite our code because something is vulnerable or otherwise outdated.

What to consider when selecting dependencies for your project

The best time to check your dependencies is before you add them. The second-best time is now. So take a critical look at any dependencies you’re adding or already using and consider the following:

Do we really need this dependency?

To make it worth it to use a dependency, it has to solve our problem and do so without adding new problems. We need to consider if the project fits our needs. We can do so by reading the documentation, and by seeing what experience other users already have with a particular tool. Keep in mind that, just because other users are enthusiastic about a particular library, that doesn’t necessarily mean it’s right for you. Their context or use case might be different from your own. There might be other libraries out there offering similar functionality that are a better fit for your project.

Also consider how much of the library you’ll actually use. If it is only a small part, consider other solutions. For example, do we really need to import StringUtils to use it for one or several String functions, or can we write them ourselves? (And, if we moved to Kotlin since then, we might be able to replace them with standard Kotlin functionality.) Or are we already using another library for this particular problem? For example, we won’t need gson if we are already using jackson (or vice versa)?

Is the project well maintained?

If a project is no longer maintained, we run the risk of having to urgently replace it if security vulnerabilities are found. To see if a project is actively maintained, you can check when the last release was, and how frequently new versions come out; you can find this information for example on Maven repository. You can also check when the last commit was, and whether the project is maintained by one person, or a group of active maintainers. A project that depends on one particular person runs the risk of becoming unmaintained if that person no longer has the time and energy to maintain that project. Maintaining a successful open source project can be a thankless task and maintainer burnout is real. With multiple maintainers the load and risk can be shared. You might want to look into how many open Issues and Pull Requests (PR) there are, and the interaction on those Issues & PR’s. You can find this information on GitHub or wherever the code for the project is kept.

How popular is the project?

A popular project might have more stars, watches and forks on GitHub. Although these metrics don’t necessarily mean that people are using it; they might have starred it to try it out later. These metrics might be useful when comparing similar tools, but not necessarily when comparing different tools.

A widely used project will likely have more people talking and writing about it. Having a large number of users means more people who are able to help out others. It also means there are more potential contributors, but unfortunately a high number of users doesn’t always translate to a high(er) number of contributors. And just because a project is popular doesn’t mean it’s right for you.

What is the community like?

Consider whether the community is friendly and welcoming. How do they interact with their users and (potential) committers? How do they respond when issues are reported? Do they review PR’s quickly and offer constructive feedback? Friendly maintainers often make for a more friendly community.
They might be active in official support channels like Slack, Gitter or mailing lists, or help answer questions on StackOverflow, write talks and blog posts or find other ways to share their knowledge.

Is it easy to use?

Finally, consider whether the project easy to implement & use, and whether you like using it. Developers have personal preferences with regard to almost everything in software development, including which tools they like to use. If a popular framework doesn’t work for you, and you have options, choose something else!
Part of whether a project is easy to use might include how well documented a project is. Good documentation can help make it easier to use. Consider looking at the official documentation, as well as blogs and content created by users. The official documentation will (hopefully!) explain how a project is meant to be used.

What is the latest stable version? Are there any open vulnerabilities?

Once you’ve decided to import a dependency, make sure to add the latest stable version. We don’t want to add an older or unstable versions that we then have to update. And we definitely don’t want to import a dependency that has known vulnerabilities that have not (yet) been fixed! We want to keep our software secure and maintainable.

Where to find this information

As mentioned, there are several places where we can look for information about a dependency we are considering. One is Maven repository where we can find open source packages, their versions, whether there are any known vulnerabilities and more.

For example, when we look at Jackson Databind on Maven repository we see a list of versions and their release dates, we see the number of usages by other artifacts for each version, and we see a warning in red for versions with known vulnerabilities.

Jackson Databind on MvnRepository
Jackson Databind on MvnRepository

When we look at the details of a version with known vulnerabilities (Jackson Databind v2.13.2 in this example), we see the CVE number for this vulnerability which links to the details for this CVE). There is also a warning in yellow that there is a new version for this artifact with the link to that version.

Details for a vulnerable version of Jackson Databind
Details for a vulnerable version of Jackson Databind

Another is to find the project’s code on GitHub, to look at the code itself, see when the latest commit was, look at open Issues and PR’s, and check Insights for more details on contributors, frequency of commits and other activity.

Jackson Databind repository on GitHub
Jackson Databind repository on GitHub

We can look for official documentation and read (or at least scan) it to see whether the project is a good fit for us, and whether it is well documented.
Other information might take a bit more effort to find: Go into the support channels and ask questions. Search for blog posts (or YouTube videos, if you prefer) and other places where you can find information. We might even check StackOverflow to see whether there is a tag for this dependency, how many (open) questions there are, etc.

JetBrains has created a Package Search website that can be used to search for Java and Kotlin libraries and get a lot of this relevant information, including the latest (stable) version, links to relevant tags on StackOverflow, links to the official docs and the code, and if the project is on GitHub the number of stars, watchers and forks on the Information tab. A list of versions (similar to the one on Maven repository) can be found on the Versions tab.

Jackson Databind on JetBrains' Package Search
Jackson Databind on JetBrains’ Package Search

The Package Search plugin is even bundled in IntelliJ IDEA 2021.2+. So, if you are using IntelliJ IDEA, you can search straight from your IDE!

Conclusion

Carefully consider which dependencies to use, taking into account at least some of the things we have discussed here. The best time to do so is before you start using them. But don’t forget to periodically check the dependencies in your existing codebase to see if you still use them, and still want to use them based on the considerations above. Don’t be afraid to remove them if they no longer bring you value.

Using Git Interactive Rebase

This article was published on Foojay.io on August 25, 2022.

This tutorial will cover how to clean up your Git commit history with Git interactive rebase, both via the IntelliJ IDEA UI and from the command line.

Git interactive rebase allows you to change individual commits, squash commits together, drop commits or change the order of the commits.

This allows you to clean up your Git commit history to make it linear and meaningful, which can make it easier to understand the history of the project in the future.

Open the Git window in IntelliJ IDEA using âŒ˜+9 on Mac (or Alt+9 on Windows & Linux). In the Git log window we can see the commits that were made to the project.

We will use a Git demo project available on GitHub. This example uses TDD (Test Driven Development) to add a new feature.

In TDD, we start by adding a failing test, writing the minimum of code we need to get that test to pass and finally do some refactoring.

Even though we made the necessary changes in multiple commits, we don’t need to keep all these individual commits for future reference.

Using Git interactive rebase in the UI

We can use Git Interactive Rebase in IntelliJ IDEA as follows:

In the Git history, identify the commit from where you want to clean up your history. That will be the oldest commit in the series of commits you want to clean up; in this example, the first failing test that we added.

Right-click on the commit from where you want to clean up your history and select “Interactively Rebase from Here…“.

IntelliJ IDEA context menu with the option "Interactively Rebase from Here..." highlighted in blue

This will open the “Rebasing Commits” popup window with a list of the commits that were done on top of the selected commit.

IntelliJ IDEA "Rebase Commits" dialog

Notice there are several options at the top of this popup, that become active when we select one or more of the commits:

  • Reword allows us to change the commit message of a specific commit.
  • The Squash button is actually a dropdown that allows us to choose between Squash and Fixup. Both options will combine the changes made in the selected commits into one commit. If we select squash, by default the individual commit messages will be combined. If we select fixup, the commit message of the fixup commit will be discarded. You can select fixup while in the “Rebasing Commits” popup with âŒ„+F on Mac (or Alt+F on Windows & Linux)
  • Drop allows us to drop one or more commits.

Changing the order of the commits

Let’s say we want to change the order of the commits; we want to keep the unrelated change, but separately from the changes for the new feature. We can select this commit and use the up and down buttons on the top left to change where in the order this commit will be.

List of commits in the "Rebase Commits" dialog window, with one commit selected.
List of commits in the "Rebase Commits" dialog window, with the  selected commit moved down.

Once we’re sure about the order, select “Start Rebasing“. We see in the Git log that the order of the commits has changed.

Combining multiple commits into one commit

Next, we want to combine multiple commits where we added the tests and implemented the new feature. Let’s reopen the “Rebasing Commits” window and select those commits.

List of commits in the "Rebase Commits" dialog window, with several commits in a row selected.

Now, because we want to combine those commits into one commit with one commit message we select “Fixup“, and then select “Start Rebasing“.

The Squash dropdown selected, with the Fixup option selected in the "Rebase Commits" dialog window.
List of selected commits in the "Rebase Commits" dialog window, shown in a tree structure ready for Fixup.

In the Git log, we can see that multiple individual commits are now combined into one commit with one commit message.

Drop a commit

Finally, we want to drop the commit with a mistake that we made. Let’s reopen the “Rebasing Commits” window, select the mistaken commit, select “Drop” and select “Start Rebasing“.

List of commits in the "Rebase Commits" dialog window, with one commits selected.
List of commits in the "Rebase Commits" dialog window, where the selected commit it shown with strike through.

We see in the Git log that the commit is dropped.

Rename a commit

Now that we have cleaned up our commit history, we might want to rename the commit where we added the new feature. We have several options to do so.

We can do so using Git interactive rebase, in the “Rebasing Commits” popup, by selecting the commit you want to rename and clicking the “Reword” button at the top of the popup. This will open a small editor pane where you can reword the commit message for this commit, apply the change to the message and select “Start Rebasing“.

Open dialog to Reword the commit message.

You can also edit the commit message directly in the Git log window. Right-click the commit you want to rename and select “Edit Commit Message” or press F2 on macOS, Windows or Linux.

IntelliJ IDEA context menu with option "Edit Commit Message" highlighted.

This will open a “Edit Commit Message” popup, where you can edit the commit message and click “Ok” (or “Cancel“) when you are done.

IntelliJ IDEA "Edit Commit Message" dialog.

See which Git commands were executed

To see which Git commands IntelliJ IDEA performed, open the “Console” tab in the Git window.

Using Git interactive rebase from the command line

Let’s take a look at how to use Git interactive rebase from the command line.

In the Git history, identify the commit just before the commit from where you want to clean up your history. In this example, that will be the last commit before we started adding the new feature.

Find the commit hash for this commit in the “Commit Details” to the right of the Git history in the Git window and copy this commit hash. (Spoiler: the commit hash in this example is 34bb0f99.)

IntelliJ IDEA Git history, showing the details of a selected commit, with the commit hash `34bb0f99` highlighted.

Open the Terminal window, using âŒ„F12 on Mac (or Alt+F12 on Windows & Linux) and type git rebase -i 34bb0f99 (where 34bb0f99 is the commit hash we copied above).

Terminal with the command `git rebase -i 34bb0f99`

This will open an editor in the terminal with the list of commits that were done on top of the selected commit. Each line in this file is an individual commit.

Terminal with vi editor open, showing a list of commits.

By default, Git will use whatever you have set as your default text editor. If you haven’t set one, it will fall back to the vi editor, which is what we will use in this tutorial.

Changing the order of the commits

Let’s say we want to change the order of the commits; we want to keep the unrelated change, but separately from the changes for the new feature. We can do so by changing the order of the lines (individual commits) to reflect the order we want.

In the editor in the terminal, switch to edit mode by pressing I to be able to edit this file.

We can change the order of the lines by removing the commit we want to move from the list and inserting it in the place where we want it.

In vi, we can do so as follows:

  • Place the cursor anywhere on the line you want to move (in this example the commit “Unrelated changes”) and remove this line by typing dd.
  • Move the cursor to the line where you want to reinsert this commit (in this example, the end of the file) and type p.
  • Note: you do not need to switch to edit mode to do so.
Terminal with vi editor open, showing a list of commits. The bottom commit is highlighted.

Once we’re sure about the order, we need to save the file. Press esc to exit edit mode and type :wq to save the file.
Note: If you made changes to the file that you do not want to save, type :q! to force quit.

The interactive rebase will be applied. We see in the Git log that the order of the commits has changed.

Combining multiple commits into one commit

Next, we want to combine multiple commits where we added the tests and implemented the new feature. In the terminal, type git rebase -i 34bb0f99 to start rebasing. If you have already run this command, you can press the up arrow â†‘ in the terminal to show the last used command(s).

This will again open an editor in the terminal with the list of commits.

Switch to edit mode in the editor in the terminal. In vi, you can do so by pressing I.

For each of the commits we want to combine, replace “pick” with “fixup”.

Note that we use “fixup” because we want to use one commit message for the combination of the commits. Alternatively, we could use “squash” to combine the individual commit messages into the new commit message.

Terminal with vi editor open, showing a list of commits. For several commits `pick` is replaced with `fixup`.

Once we have correctly edited all the commits we want to combine, save the file.
In vi, press esc to exit edit mode and type :wq to save the file.
The interactive rebase will be applied. In the Git log, we can see that multiple individual commits are now combined into one commit with one commit message.

Drop a commit

Finally, we want to drop the commit with a mistake that we made. In the terminal, type git rebase -i 34bb0f99 to start rebasing.

To drop a commit, remove that commit from the list of commits. In this example, we will remove the commit “Mistake”.

In vi, we can remove a line by placing the cursor anywhere on the line we want to remove and typing dd. Alternatively, we can switch to edit mode by pressing I and removing the line manually. Press escto exit edit mode.

Terminal with vi editor open, showing a list of commits.

Save the file by typing :wq and the interactive rebase will be applied. We see in the Git log that the commit is dropped.

Summary

Now we know how to use git interactive rebase either from the IntelliJ IDEA UI or from the command line. Give them a try and use whichever way you prefer.

IntelliJ IDEA Shortcuts Used

Here are the IntelliJ IDEA shortcuts that we used.

NamemacOS ShortcutWindows / Linux Shortcut
Open the Git Tool Window⌘9Alt+9
Open the Commit Window⌘0Alt+0
Open the Terminal⌄F12Alt+F12
Select Fixup (in the “Rebasing Commits” popup)⌄F12Alt+F
Edit commit message (in the Git Log)F2F2
IntelliJ IDEA shortcuts

Git commands Used

Here are the Git commands that we used.

Nameterminal command
Git interactively rebase from a specific commit with commit hash, for example 11aa23bcgit rebase -i 11aa23bc
Use this commitpick
Fixup this commit (add changes to previous commit under the same commit message)fixup
Squash this commit (add changes to previous commit and combine commit messages)squash
Git commands

vi Shortcuts Used

Here are the shortcuts that we used.

NameShortcut
Open interactive (edit) modeI
Exit interactive (edit) modeesc
Remove line (note: not in edit mode)dd
Reinsert line (note: not in edit mode)p
Write and quit:wq
Force quit:q!
vi shortcuts

Related Links

Using Git interactive rebase in IntelliJ IDEA

Git interactive rebase allows you to change individual commits, squash commits together, drop commits or change the order of the commits. This allows you to clean up your git commit history to make it linear and meaningful, which can make it easier to understand the history of the project in the future. Let’s take a look at how this works.

For more information, see Using Git Interactive Rebase.

How to pass the Java SE 8 Programmer I exam

This article was first published on Medium.

This post describes how I passed the Java SE 8 Programmer I exam.

Why take the exam

Opinions differ on how useful it is to pass this exam. It certainly isn’t easy. You’ll need to know quite a lot about Java syntax, and what the compiler will or will not allow you to do. However, it does not teach you to be a good Java programmer; you don’t have to write any actual code, and the code examples provided are definitely not clean code. They might even be anti-patterns.

Exam guide

When I took the exam, there was only one study guide available for Java 8:

OCA: Oracle Certified Associate Java SE 8 Programmer I Study Guide: Exam 1Z0-808 by Jeanne BoyarskyScott Selikoff

Overall, this guide was very helpful. It covers what you need to know, and provides practice questions at the end of each chapter, as well as several practice exams (which are also accessible online). It also provides great tips on how to pass the exam. The best tip for me was: for each question, if one of the options is “does not compile”, check if the code example will compile before looking at any of the other answers.

Personally, I found the book very helpful. Although some topics weren’t quite clear enough for me, and I did end up googling additional information.

In the mean time, other guides have become available. Since I didn’t use them, I can’t comment on their quality. I might try the guide by Mala Gupta, as I found her Java 7 version to be quite concise (which is helpful if you need to know exactly what will or won’t compile).

Practice

Another thing I did was write lots of code snippets to figure out some details; this way you see exactly what will compile or not, and what the result will be. It will help you find some common mistakes everyone makes when first starting out (missing semi-colons and brackets, etc.). And running code with a debugger will help you understand better what’s going on.

Mock exams

Apart from studying the exam topics, both by reading and trying out code, I found practice exams essential. Practice taking the exam as much as you can! Any exam guide will likely offer one or more practice exams. In addition, you can buy more mock exams.

In my case, I bought exams from Enthuware, which are good quality and not very expensive. They helped me learn the how to answer the types of questions you might expect on the exam, as well as to manage my time. (Pro tip: mark questions you’re not sure of and come back to them later. Do answer them; an answer that may or may not be correct, is better than no answer which is sure to be incorrect).

In addition, it showed me which areas were my weakest. Then, I would research those topics some more and clear up any confusion I had before doing another mock exam. Once I was consistently passed the mock exams, I also passed the actual exam.

Course

Because my employer at the time paid for it, I also did a course at Oracle. This one week course covers all of the topics, with some exercises. It is useful to have an instructor to help explain things to you. If you don’t take the course, you might have to ask friends or coworkers. In my opinion, doing more mock exams (even if you pay for them yourself) is better value for money. But if your employer is willing to pay for the course, it can’t hurt.

Conclusion

If you want to pass the exam, it will take some work. Don’t just read a book, but practice; both with code and with mock exams.

The exam is not easy and therefore does show that you have a firm grasp of the language. However, it doesn’t show that you are able to use it well. For that, you’ll need actual experience.

Managing state in Cucumber-JVM using Spring

This article was first published on Medium.

A frequently asked question about Cucumber-JVM is how to share state between steps. This post describes how to use Spring with Cucumber to help you share objects between steps, without accidentally sharing state between scenarios (a common cause of flaky scenarios).

First of all, why not use static variables?

A solution often seen to share variables or objects between steps, is to declare static variables at the top of the step definitions file. However, there are several downsides this approach:

  1. As your project grows, you’ll probably want to divide your step definitions into different classes, divided into meaningful groups. At that point, you can no longer use the static variables declared in one step definition file.
  2. Using static variables might cause your tests to accidentally leak state into other scenarios, making them unreliable. Test automation is only any good if it is reliable.

Using Dependency Injection

The recommended solution to share state is to use Dependency Injection (DI). Cucumber supports several DI frameworks, including PicoContainer, Spring and Guice.

Using Dependency Injection with Cucumber will bring you several benefits:

  • You can safely share state between your steps
  • It will help improve the design of your test code; making it easier to share state between different step definition classes (so you can split them into meaningful groups).
  • It will create and manage instances of classes for you.

Choosing a Dependency Injection framework

If your project already uses Dependency Injection, you could use the framework you already have. If not, consider using PicoContainer; it’s very light-weight and easy to use (at least, this is my personal experience in side projects).

Since my team already uses Spring in our projects, we’ve opted to use Spring with Cucumber.

Adding the cucumber-spring dependency

In order to use Spring with Cucumber, we need to add a cucumber-spring dependency to our pom.xml:

<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<version>2.4.0</version>
<scope>test</scope>
</dependency>

Other dependencies

If you are using Spring and Cucumber in your project, you will already have those dependencies. Otherwise, you should add those as well.

Annotation based configuration

If you are using annotation based configuration, you can register your classes as Beans to be managed by Spring:

  • Add the @Component annotation to each of the classes you’d like Spring to manage for you.
  • Add an annotation to specify the scope: the @Scope("cucumber-glue"), in order to have cucumber-spring remove them after each scenario!
  • Add the location of your classes to the @ComponentScan of your (test) configuration.
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("your.package")
public class Config {
}

This approach works for any classes that you have defined yourself. This may include:

  • domain objects (like a “Customer” or an “Account”)
  • any other step definition files (if you have split your files)
  • any “services” or “helper” classes you extract to represent parts of the system your tests interact with (like PageObjects, REST API’s, etc.). The steps can then call these services/helpers, instead of each other.

If you are using classes that you have not defined yourself, you cannot annotate them as Components for Spring to find with the component scan. You will have to explicitly register them as Beans in your (test) configuration.

Here is an example, using Selenium WebDriver:

import org.openqa.selenium.WebDriver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
@ComponentScan("your.package")
public class Config {
    @Bean
    @Scope("cucumber-glue")
    public WebDriver webDriver() {
        // return a driver with desired capabilities
    }
}

In our latest projects, we are using SpringBoot. We can annotate our StepDefinitions class with @SpringBootTest(classes = [Config.class]);.

XML configuration

Alternatively, you can specify your beans in a .cucumber.xml file, like this. Here is an example (again using Selenium WebDriver; this could also be one of your own classes):

<bean class="org.openqa.selenium.WebDriver" scope="cucumber-glue" />

You can annotate your StepDefinitions with @ContextConfiguration("classpath:cucumber.xml").

Using the Beans

You can now use the Beans, by autowiring them where you need them.

For example, you can Autowire your WebDriver to your PageObject:

import org.openqa.selenium.WebDriver;
import org.springframework.beans.factory.annotation.Autowired;

public class PageObject {
    @Autowired
    WebDriver driver;    // the rest of your page object
}

Conclusion

As you can see, it is relatively easy to add Cucumber-Spring to manage state. You are now able to safely share state between your steps, as well as split your step definition files into meaningful groups.

This will make your project easier to understand and maintain, and your tests more reliable.