私は自分のプログラムに注釈を付け始め、nullness 注釈を書き始めました。ガイドラインに従って、クラスの 1 つに注釈を付け、 としてマークしました@AnnotatedFor({"nullness"})
。このプログラムは、Oracle JDK 1.7.u21 を使用して Java 7 プラットフォームでコンパイルされています (技術的な制限により、JDK 8 に切り替えることはできません)。このクラスは、ナノ化されていないサードパーティ (Google Guava) および JDK ライブラリ メソッドの束を使用するため、次のように Maven コンパイラ プラグイン引数に-AskipUses=...
とともにオプションを含めます。-AuseSafeDefaultsForUnnanotatedSourceCode
<properties>
<project.checker.annotatedJdk>${org.checkerframework:jdk7:jar}</project.checker.annotatedJdk>
<project.checker.typeAnnotationsJavac>${org.checkerframework:compiler:jar}</project.checker.typeAnnotationsJavac>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<fork>true</fork>
<annotationProcessors>
<annotationProcessor>org.checkerframework.checker.nullness.NullnessChecker</annotationProcessor>
</annotationProcessors>
<compilerArgs>
<arg>-Xbootclasspath/p:${project.checker.annotatedJdk}</arg>
<arg>-J-Xbootclasspath/p:${project.checker.typeAnnotationsJavac}</arg>
<arg>-AuseSafeDefaultsForUnannotatedSourceCode</arg>
<arg>-AskipUses=com\.google\.common\.|java\.math</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
クラスのソースコード:
package pkg;
import java.util.*;
import java.math.BigDecimal;
import com.google.common.base.*;
import com.google.common.collect.Ordering;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.qual.AnnotatedFor;
@AnnotatedFor({"nullness"})
public class Indicator implements Comparable<Indicator> {
private static final BigDecimal DEFAULT_SORT_ORDER;
private static final Ordering<Indicator> ORDERING;
public static enum IndicatorComparator implements Comparator<Indicator> {
INSTANCE;
@Override
public final int compare(Indicator left, Indicator right) {
/* nulls-last */
if (left.sortOrder != null && right.sortOrder != null) {
return left.sortOrder.compareTo(right.sortOrder);
} else if (left.sortOrder != null && right.sortOrder == null) {
return -1;
} else if (left.sortOrder == null && right.sortOrder != null) {
return 1;
} else {
return 0;
}
}
}
static {
DEFAULT_SORT_ORDER = BigDecimal.valueOf(0.0);
ORDERING = Ordering.from(IndicatorComparator.INSTANCE).nullsLast();
}
private final int id;
private @Nullable String code;
private @Nullable BigDecimal sortOrder;
private boolean isGroup;
private Indicator(Builder builder) {
id = builder.id;
code = builder.code;
sortOrder = builder.sortOrder;
isGroup = builder.isGroup;
}
/* equals and hashcode are not overriden by purpose -- the default version will do */
@Override
public int compareTo(final Indicator other) {
return ORDERING.compare(this, other);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("id", id)
.add("code", code)
.add("sortOrder", sortOrder)
.add("isGroup", isGroup)
.toString();
}
public int getId() {
return id;
}
public Optional<String> getCode() {
return Optional.fromNullable(code);
}
public Optional<BigDecimal> getSortOrder() {
return Optional.fromNullable(sortOrder);
}
public boolean isGroup() {
return isGroup;
}
public void setCode(@Nullable String code) {
this.code = code;
}
public void setSortOrder(@Nullable BigDecimal sortOrder) {
this.sortOrder = sortOrder;
}
public void setGroup(boolean group) {
this.isGroup = group;
}
public static class Builder {
private int id;
private @Nullable String code;
private @Nullable BigDecimal sortOrder;
private boolean isGroup;
public Builder() {
sortOrder = DEFAULT_SORT_ORDER;
}
public Builder id(int id) {
this.id = id;
return this;
}
public Builder code(@Nullable String code) {
this.code = code;
return this;
}
public Builder sortOrder(@Nullable BigDecimal sortOrder) {
this.sortOrder = sortOrder;
return this;
}
public Builder isGroup(boolean isGroup) {
this.isGroup = isGroup;
return this;
}
public Indicator build() {
return new Indicator(this);
}
}
}
プロジェクトをビルドすると、次のようなエラーが発生するため、チェッカーは「スキップ」オプションを無視しているようです
COMPILATION ERROR :
-------------------------------------------------------------
pkg/Indicator.java:[38,48] error: [argument.type.incompatible] incompatible types in argument.
found : @UnknownKeyFor double
required: @KeyForBottom double
38 行目に進みます。
DEFAULT_SORT_ORDER = BigDecimal.valueOf(0.0);
または 39:
pkg/Indicator.java:[39,52] error: [argument.type.incompatible] incompatible types in argument.
found : IndicatorComparator
required: Comparator<Indicator>
または 38 再び:
pkg/Indicator.java:[38,47] error: [assignment.type.incompatible] incompatible types in assignment.
found : @UnknownInitialization @Nullable BigDecimal
required: @Initialized @NonNull BigDecimal
-AskipUses=
などなど・・・オプションを使って解消したつもりだったのですが、色々なチェッカーエラーでログがオーバーフローしてしまいました。
私は何か間違ったことをしていますか?
UPD 07.12.2015: クラスの完全なソース コードを添付しました。UPD 14.12.2015: ソース コードが更新されたため、ケースの再現がはるかに簡単になりました。