Skip to content

Dealing with libraries

David Bürgin edited this page Apr 3, 2016 · 18 revisions

Dealing with libraries

We have eliminated two errors and with that two bugs, but there are still 35 more to go. Fortunately, there’s a realisation to be had in the next few error messages, and it will cut down our work considerably.

Unannotated libraries

The topmost errors are again in Owner. The checker reports an error on almost every call to ToStringCreator.append in the following code.

    @Override
    public String toString() {
        return new ToStringCreator(this)
            .append("id", this.getId())
            .append("new", this.isNew())
            .append("lastName", this.getLastName())       // line 151
            .append("firstName", this.getFirstName())
            .append("address", this.address)
            .append("city", this.city)
            .append("telephone", this.telephone)
            .toString();
    }

For example, this is the error reported on line 151:

[151,49] [argument.type.incompatible] incompatible types in argument.
  found   : @Initialized @Nullable String
  required: @Initialized @NonNull Object

It looks like the checker assumes that the signature of ToStringCreator.append is really this:

public ToStringCreator append(@NonNull String fieldName, @NonNull Object value)

The assumption that all references are non-null by default makes an other appearance, but this time in code that we don’t control. org.springframework.core.style.ToStringCreator is a class from the Spring Framework library, which is not annotated for nullness.

What to do? Unsurprisingly, since unannotated libraries are the norm, the Checker Framework manual dedicates an entire chapter to this conundrum. Here, let’s go with the cheapest option: simply ignore the errors.

Ignoring library usage

The Checker Framework’s annotation processors can be configured with standard javac -A command-line flags. Two of the more useful flags are

  • -Alint, which turns on additional optional checks, and
  • -Awarns, which turns errors into warnings, so that compilation succeeds notwithstanding any errors found.

The flag most useful for our current task is -AskipUses. -AskipUses instructs the checker to ignore problems with usage of code below a certain package. In the case of the Spring Framework the package to ignore is org.springframework.

One small complication here is that our project, the Pet Clinic, lives in the package org.springframework.samples, which is inside the package of the Spring Framework itself. Instead of excluding org.springframework we’ll have to exclude all Spring packages that are not org.springframework.samples. A bit tedious, so do feel free to copy and paste the list of packages I’ve prepared here. This goes in the compiler configuration in the POM, just after the other <arg> element.

<arg>-AskipUses=org\.springframework\.beans\.|org\.springframework\.core\.|org\.springframework\.dao\.|org\.springframework\.data\.|org\.springframework\.format\.|org\.springframework\.jdbc\.|org\.springframework\.orm\.|org\.springframework\.stereotype\.|org\.springframework\.ui\.|org\.springframework\.util\.|org\.springframework\.validation\.|org\.springframework\.web\.</arg>

I’ve committed this flag in my seventh commit 5195081.

I ask you to also ignore the Joda-Time library, which is responsible for two more errors. See the small follow-up commit 2787184.

With this configuration-only change we’ve managed to cut the number of errors in half. See for yourself by running mvn -Pchecker compile and turn the page.