Category Archives: IntelliJ IDEA

IntelliJ IDEA: Configuring Default Project Settings

PROBLEM

When creating or checking out a project for the first time in IntelliJ IDEA, we may need to reconfigure the project settings. My biggest pain is IntelliJ IDEA will always use the wrong Maven version when I check out the project from the source control.

SOLUTION

The good news is there is a way to set up default project settings in IntelliJ IDEA.

In the Welcome dialog, select Configure -> Project Defaults.

From here, we can create all the default project settings, such as JDK version, Maven version, code style formatter and so on.

Advertisements

IntelliJ IDEA 14.1: Better equals(), hashCode() and toString()

PROBLEM

Let’s assume we want to create the default equals(), hashCode() and toString() with the following bean:-

public final class Person {
    private final String name;
    private final Collection<Car> cars;

    public Person(final String name, final Collection<Car> cars) {
        this.name = name;
        this.cars = cars;
    }

    public String getName() {
        return name;
    }

    public Collection<Car> getCars() {
        return cars;
    }
}

Most IDEs, including older version of IntelliJ, have code generation features that would create something similar to this:-

public final class Person {
    ...

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        final Person person = (Person) o;

        if (name != null ? !name.equals(person.name) : person.name != null) {
            return false;
        }
        return !(cars != null ? !cars.equals(person.cars) : person.cars != null);
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (cars != null ? cars.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "Person{" +
               "name='" + name + '\'' +
               ", cars=" + cars +
               '}';
    }
}

While it works, the generated code is usually crazy horrendous.

SOLUTION

With IntelliJ 14.x, it allows us to select templates from several proven libraries.

To generate equals() and hashCode(), select equals() and hashCode() option from the Generate pop-up dialog:-

There are several templates to choose from:-

Here’s an example of equals() and hashCode() using Guava and getter methods:-

public final class Person {
    ...

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        final Person person = (Person) o;
        return Objects.equal(getName(), person.getName()) &&
               Objects.equal(getCars(), person.getCars());
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getName(), getCars());
    }
}

To generate toString(), select toString() option from the Generate pop-up dialog:-

Again, there are several templates to choose from:-

Here’s an example of toString() using Guava:-

public final class Person {
    ...

    @Override
    public String toString() {
        return Objects.toStringHelper(this)
                .add("name", name)
                .add("cars", cars)
                .toString();
    }
}

IntelliJ IDEA: Generating Immutable Classes and Fields

PROBLEM

By default, IntelliJ IDEA generates mutable classes and fields.

One of the steps to achieve immutability is to make all classes and fields to be final.

SOLUTION

Making Fields Final

Go to Preferences... -> Code Style -> Java -> Code Generation tab

Under Final Modifier, check both Make generated local variables final and Make generated parameters final.

Making Classes Final

Go to Preferences... -> File and Code Templates -> Templates tab

Select Class and add final.

IntelliJ : Karma Integration

Overview

Although we can run karma start karma.conf.js on the command line to start Karma test runner, JetBrains provides a great Karma-IntelliJ integration to run and display the JavaScript test results within IntelliJ.

Prerequisites

Install Karma Plugin in IntelliJ

The first step is to install the Karma plugin created by JetBrains.

Create Karma “Run” Configuration

From the drop down list on top right of IntelliJ, select Edit Configurations….

In Run/Debug Configuration dialog, select + and then select Karma.

Enter a name, in this example, we call it Karma.

Use the drop down list to select a configuration file called karma.conf.js.

The Node interpreter and Karma package should already be defined, otherwise, use the drop down lists to select the right values.

On top right of IntelliJ, select the green Play button to run Karma test runner.

IntelliJ should now run Karma and display the familiar green/red bar based on the JavaScript test results.

There are few things we can configure here:-

  • Button 1 – When selected, IntelliJ will automatically rerun all the tests whenever we change the production or test JavaScript files.
  • Button 2 – When unselected, all passed tests are displayed.
  • Button 3 – When selected, all tests are expanded.

IntelliJ: Overriding Log4J Configuration Globally for JUnit

PROBLEM

Most of the time, we may have several Log4J configurations depending on the environments, for example:-

  • log4j.xml (Log4J) or log4j2.xml (Log4J2) – Production configuration using socket appender.
  • log4j-dev.xml (Log4J) or log4j2-dev.xml (Log4J2) – Development configuration using console appender.

Since log4j.xml and log4j2.xml are the default configuration files for Log4J and Log4J2, these configurations will always be used unless we override the configuration file path.

In another word, if we don’t override the configuration file path and we run our JUnit test cases offline from IntelliJ, it may take a very long time to execute them due to the broken socket connection. Further, it is not a good idea to clutter our production log files with non-production logs.

SOLUTION

To fix this, we need to configure IntelliJ to always use our development Log4J configuration.

First, on the menu bar, select Run -> Edit Configurations...

Then, delete all the existing JUnit configuration files.

Finally, expand Defaults -> JUnit.

Under VM options, specify the following system property:-

  • For Log4J, specify -Dlog4j.configuration=log4j-dev.xml
  • For Log4J2, specify -Dlog4j.configurationFile=log4j2-dev.xml

Please note the slight change on the system property name depending on the Log4J version.

Now, when we run our JUnit test cases from IntelliJ, it will always pick up the correct custom Log4J configuration file.

IntelliJ: Selectively Disable Line Wrap

PROBLEM

Sometimes, we have very lengthy statements that look like this:-

@Service
public class LengthOfStayHeuristicServiceImpl extends HeuristicService {
    @Override
    public Double compute(HeuristicBean heuristicBean) {
        ...
				
        setValue(map, surgeryLocationMap, LengthOfStayAlgorithm.VariableEnum.SURGERY_LOCATION_LUMBAR_OR_SACRAL_AND_LUMBOSACRAL_MINUS_CERVICAL_AND_NOT_SPECIFIED);
        setValue(map, surgeryLocationMap, LengthOfStayAlgorithm.VariableEnum.SURGERY_LOCATION_LUMBAR_OR_SACRAL_MINUS_LUMBOSACRAL);
        setValue(map, surgeryLocationMap, LengthOfStayAlgorithm.VariableEnum.SURGERY_LOCATION_CERVICAL_MINUS_NOT_SPECIFIED);

        return new LengthOfStayAlgorithm(map).run();
    }
}

When we reformat the code in IntelliJ, it becomes like this:-

@Service
public class LengthOfStayHeuristicServiceImpl extends HeuristicService {
    @Override
    public Double compute(HeuristicBean heuristicBean) {
        ...
				
        setValue(map,
                 surgeryLocationMap,
                 LengthOfStayAlgorithm.VariableEnum.SURGERY_LOCATION_LUMBAR_OR_SACRAL_AND_LUMBOSACRAL_MINUS_CERVICAL_AND_NOT_SPECIFIED);
        setValue(map,
                 surgeryLocationMap,
                 LengthOfStayAlgorithm.VariableEnum.SURGERY_LOCATION_LUMBAR_OR_SACRAL_MINUS_LUMBOSACRAL);
        setValue(map,
                 surgeryLocationMap,
                 LengthOfStayAlgorithm.VariableEnum.SURGERY_LOCATION_CERVICAL_MINUS_NOT_SPECIFIED);

        return new LengthOfStayAlgorithm(map).run();
    }
}

There are times we really don’t want the long statements to wrap around because they look very messy.

SOLUTION

While there is no option to selectively disable just the line wrap in IntelliJ, there is a way to selectively disable code formatting.

First, we need to enable the Formatter Control.

Now, we can annotate our code like this:-

@Service
public class LengthOfStayHeuristicServiceImpl extends HeuristicService {
    @Override
    public Double compute(HeuristicBean heuristicBean) {
        ...
				
        // @formatter:off
        setValue(map, surgeryLocationMap, LengthOfStayAlgorithm.VariableEnum.SURGERY_LOCATION_LUMBAR_OR_SACRAL_AND_LUMBOSACRAL_MINUS_CERVICAL_AND_NOT_SPECIFIED);
        setValue(map, surgeryLocationMap, LengthOfStayAlgorithm.VariableEnum.SURGERY_LOCATION_LUMBAR_OR_SACRAL_MINUS_LUMBOSACRAL);
        setValue(map, surgeryLocationMap, LengthOfStayAlgorithm.VariableEnum.SURGERY_LOCATION_CERVICAL_MINUS_NOT_SPECIFIED);
        // @formatter:on

        return new LengthOfStayAlgorithm(map).run();
    }
}

When we reformat the code, that portion of code will remain unformatted.

IntelliJ: Handling SVN Global Ignore List

PROBLEM

Every time we check out a project from SVN for the first time, we always have to remember to set the SVN ignore list in IntelliJ.

SOLUTION

NOTE: We only need to perform these steps just once per development machine.

To do so, we configure the SVN global ignore list and have IntelliJ to conform to that rule.

  • In Mac, go to IntelliJ IDEA -> Preferences. In Windows, go to File -> Settings.
  • In the preference dialog, go to Version Control -> Subversion.
  • Check Use system default Subversion configuration directory.
  • Note down Subversion configuration directory.
  • Close preference dialog.
  • Open [SVN_CONFIG_DIR]/config in a text editor.
  • Scroll to the [miscellany] section that looks something like this:-

    ...
    [miscellany]
    ### Set global-ignores to a set of whitespace-delimited globs
    ### which Subversion will ignore in its 'status' output, and
    ### while importing or adding files and directories.
    ### '*' matches leading dots, e.g. '*.rej' matches '.foo.rej'.
    # global-ignores = *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo
    #   *.rej *~ #*# .#* .*.swp .DS_Store 
    ### Set log-encoding to the default encoding for log messages
    # log-encoding = latin1
    ...
    

  • Uncomment global-ignores statement by removing #:-

    ...
    [miscellany]
    ### Set global-ignores to a set of whitespace-delimited globs
    ### which Subversion will ignore in its 'status' output, and
    ### while importing or adding files and directories.
    ### '*' matches leading dots, e.g. '*.rej' matches '.foo.rej'.
    global-ignores = *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo
       *.rej *~ #*# .#* .*.swp .DS_Store
    ### Set log-encoding to the default encoding for log messages
    # log-encoding = latin1
    ...
    

  • Add the following patterns:-

    ...
    [miscellany]
    ### Set global-ignores to a set of whitespace-delimited globs
    ### which Subversion will ignore in its 'status' output, and
    ### while importing or adding files and directories.
    ### '*' matches leading dots, e.g. '*.rej' matches '.foo.rej'.
    global-ignores = *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo
       *.rej *~ #*# .#* .*.swp .DS_Store
       .idea target .git .classpath .project .settings *.iml *.log *.bak *.class *.jar *.war *.ear 
       node_modules pom.xml.versionsBackup
    ### Set log-encoding to the default encoding for log messages
    # log-encoding = latin1
    ...
    

  • Save and close this config file.

Now, all the unnecessary files will not appear under “Changes” section in IntelliJ and they will not be committed into SVN.