Contract Checking in Maven Build

303 views Asked by At

I'm working on a Java codebase in IJ and currently building with Maven. I would like to supplement some of the code with some form of contracts that will get picked up in the Maven build. So far, I've been unsuccessful in my search for such a capability off the shelf:

  • OpenJML, but that seems to require its own tool to analyse your code and I couldn't find a way to integrate it easily into the build.
  • Jetbrains Contracts. These will raise a warning in IntelliJ via an inspection, but they don't affect the build.

Note: I only care about compile-time-checkable contracts here. I have JUnit to throw at the Runtime side of things.

Contracts to Enforce:

I've added this section to answer the comment asking what kind of contracts I'd like to enforce. Ideally, I'd like the most powerful solution possible conditional on that solution being complete. When I say complete here I mean a language of contracts & a contract checker such that every statement in the language can be checked as good/bad by the checker at compile time. I'm aware this may be a big ask, but I'd be happy with even the simplest of contracts e.g. those offered by Jetbrains.

For a concrete example, consider this function:

public static Long safeToLong(String value) {
    if (value == null) {
      return null;
    }
    try {
      return Long.parseLong(value);
    } catch (NumberFormatException e) {
      return null;
    }
  }

This successfully passes the Jetbrains contract:

@Contract("null -> null")

And fails this contrived contract:

@Contract("null -> !null")

But with the above, contrived, bad contract, the Maven build still works just fine. The build doesn't pick up the inspection results- these are only visible from within IJ. I'd like to be able to hook into the build and fail if any contracts are violated.

1

There are 1 answers

1
Colm Bhandal On

Here is a solution, that works for IntelliJ Contracts. It's a bit messy, but it works:

  • Download/clone Bentolor's CLI inspector tool into your working directory i.e the directory where the .idea folder is
  • Create an IJ inspection profile with just these inspections enabled: Constant conditions and exceptions and Contract Issues
  • Create an inspection scope if you like - this will restrict your inspections to run only on certain files
  • Edit that .ideainspect file that comes with Bentolor's tool, setting your inspection profile & scope that you've just defined, or use project defaults if you haven't defined any
  • Also in the .ideainspect file, set the ideahome property to the path where you've insalled IJ e.g. ideahome= C:\Program Files (x86)\JetBrains\IntelliJ IDEA Community Edition 15.0.6
  • Finally, to include this in the Maven build, add the following to your POM.xml:
<plugin>
    <groupId>org.codehaus.gmavenplus</groupId>
    <artifactId>gmavenplus-plugin</artifactId>
    <version>1.6.1</version>
    <executions>
      <execution>
        <phase>verify</phase>
        <goals>
          <goal>execute</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <properties>
      </properties>
      <scripts>
        <script>file:///${project.basedir}/idea-cli-inspector/ideainspectMvn.groovy</script>
      </scripts>
    </configuration>
    <dependencies>
      <dependency>
        <groupId>org.codehaus.groovy</groupId>
        <artifactId>groovy-all</artifactId>
        <!-- any version of Groovy \>= 1.5.0 should work here -->
        <version>2.5.0</version>
        <type>pom</type>
        <scope>runtime</scope>
      </dependency>
      <dependency>
        <groupId>commons-cli</groupId>
        <artifactId>commons-cli</artifactId>
        <version>1.2</version>
      </dependency>
    </dependencies>
  </plugin>

Troubleshooting

If you get this EXCEPTION_ACCESS_VIOLATION bug while running the inspections, you may be able to fix it by adding -Dswing.noxp=true to the end of the file bin\idea64.exe.vmoptions where IJ is installed- the fix is documented at the end of this IJ crash thread.

Gradle Variant

To add this to your Gradle build it's simpler than in the Maven case. Just add this task to your build.gradle file:

task inspect(type:Exec) {
  workingDir '/idea-cli-inspector'

  //on windows:
  commandLine 'cmd', '/c', 'groovy ideainspect.groovy'
}