Java 注释 - 限制具有相同字段元素值的注释的基数(出现)
Java Annotation - Restrict cardinality (occurrance) of annotation with same field element value
我有以下条件,需要 Java 带有特定字段值的注释在 class 的任何字段中恰好出现一次。 Java 8 可以吗?
我的批注
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) //can use with fields only.
public @interface TestAnnotation{
public String id();
}
使用注解的class就像
@TestAnnotation(id="test")
private String testString;
@TestAnnotation(id="test1")
private String test1String;
@TestAnnotation(id="test2")
private String test2String;
我想要的只是防止程序员使用类似
的东西
@TestAnnotation(id="test2")
private String test2String;
@TestAnnotation(id="test2")
private String test3String;
即具有特定 id@TestAnnotation(id="test2")
的相同注释 不能在字段上使用两次。至少 id="..."
在 class.
中的 @TestAnnotaion
个应用字段中应该是唯一的
您似乎已经明白,这可以通过注释处理器实现。
这是一个例子:
package mcve.proc;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface IDExample {
String id();
}
package mcve.proc;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
import javax.tools.*;
import java.util.*;
@SupportedAnnotationTypes("mcve.proc.IDExample")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class UniqueIDProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
Elements elements = processingEnv.getElementUtils();
Types types = processingEnv.getTypeUtils();
Map<TypeElement, Set<VariableElement>> map = new HashMap<>();
// Find each of the fields annotated with @IDExample.
for (Element elem : roundEnv.getElementsAnnotatedWith(IDExample.class)) {
if (elem.getKind() == ElementKind.FIELD) {
VariableElement var = (VariableElement) elem;
TypeElement decl = (TypeElement) var.getEnclosingElement();
// Group them by declaring class.
map.computeIfAbsent(decl, key -> new HashSet<>()).add(var);
}
}
// Now for each set of fields annotated with @IDExample...
for (Set<VariableElement> fields : map.values()) {
Map<String, Set<VariableElement>> fieldsByID = new HashMap<>();
// Group them by ID.
for (VariableElement field : fields) {
String id = field.getAnnotation(IDExample.class).id();
fieldsByID.computeIfAbsent(id, key -> new HashSet<>()).add(field);
}
fieldsByID.forEach((String id, Set<VariableElement> fieldsWithID) -> {
// For each set of fields which have duplicate IDs,
// cause a compilation error on each annotation.
if (fieldsWithID.size() > 1) {
for (VariableElement field : fieldsWithID) {
// This is all just finding the annotation mirror so
// the compilation error appears in the right place.
TypeMirror idExampleMirror =
elements.getTypeElement(IDExample.class.getName()).asType();
AnnotationMirror annotation =
field.getAnnotationMirrors().stream()
.filter(mirror -> types.isSameType(idExampleMirror, mirror.getAnnotationType()))
.findFirst().get();
AnnotationValue value =
annotation.getElementValues().entrySet().stream()
.filter(e -> e.getKey().getSimpleName().contentEquals("id"))
.map(e -> e.getValue())
.findFirst().get();
// Actually cause the compilation error.
String errorMessage = String.format("\"%s\" is a duplicate ID.", id);
processingEnv.getMessager()
.printMessage(Diagnostic.Kind.ERROR,
errorMessage,
field,
annotation,
value);
}
}
});
}
return false;
}
}
有关于如何使注释处理正常工作的教程 here。例如,要让上面的示例处理器正常工作,您可以大致执行以下操作(取决于您的 IDE,我假设):
- 为两个 类
mcve.proc.IDExample
和 mcve.proc.UniqueIDProcessor
创建一个 project/separate jar。
- 在那个 jar 中,创建一个目录
META-INF/services
。
- 在该目录中,创建一个名为
javax.annotation.processing.Processor
(无文件扩展名)的文本文件,其内容是注释处理器的完全限定名称 mcve.proc.UniqueIDProcessor
。
- 将 project/jar 作为库导入到您的主项目中。
- 可能添加
mcve.proc.UniqueIDProcessor
作为注释处理器,例如如果需要这样的设置 exists/is,您的项目属性。我知道 Netbeans 就是这样做的。我不知道其他 IDEs.
我有以下条件,需要 Java 带有特定字段值的注释在 class 的任何字段中恰好出现一次。 Java 8 可以吗?
我的批注
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) //can use with fields only.
public @interface TestAnnotation{
public String id();
}
使用注解的class就像
@TestAnnotation(id="test")
private String testString;
@TestAnnotation(id="test1")
private String test1String;
@TestAnnotation(id="test2")
private String test2String;
我想要的只是防止程序员使用类似
的东西@TestAnnotation(id="test2")
private String test2String;
@TestAnnotation(id="test2")
private String test3String;
即具有特定 id@TestAnnotation(id="test2")
的相同注释 不能在字段上使用两次。至少 id="..."
在 class.
@TestAnnotaion
个应用字段中应该是唯一的
您似乎已经明白,这可以通过注释处理器实现。
这是一个例子:
package mcve.proc;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface IDExample {
String id();
}
package mcve.proc;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
import javax.tools.*;
import java.util.*;
@SupportedAnnotationTypes("mcve.proc.IDExample")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class UniqueIDProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
Elements elements = processingEnv.getElementUtils();
Types types = processingEnv.getTypeUtils();
Map<TypeElement, Set<VariableElement>> map = new HashMap<>();
// Find each of the fields annotated with @IDExample.
for (Element elem : roundEnv.getElementsAnnotatedWith(IDExample.class)) {
if (elem.getKind() == ElementKind.FIELD) {
VariableElement var = (VariableElement) elem;
TypeElement decl = (TypeElement) var.getEnclosingElement();
// Group them by declaring class.
map.computeIfAbsent(decl, key -> new HashSet<>()).add(var);
}
}
// Now for each set of fields annotated with @IDExample...
for (Set<VariableElement> fields : map.values()) {
Map<String, Set<VariableElement>> fieldsByID = new HashMap<>();
// Group them by ID.
for (VariableElement field : fields) {
String id = field.getAnnotation(IDExample.class).id();
fieldsByID.computeIfAbsent(id, key -> new HashSet<>()).add(field);
}
fieldsByID.forEach((String id, Set<VariableElement> fieldsWithID) -> {
// For each set of fields which have duplicate IDs,
// cause a compilation error on each annotation.
if (fieldsWithID.size() > 1) {
for (VariableElement field : fieldsWithID) {
// This is all just finding the annotation mirror so
// the compilation error appears in the right place.
TypeMirror idExampleMirror =
elements.getTypeElement(IDExample.class.getName()).asType();
AnnotationMirror annotation =
field.getAnnotationMirrors().stream()
.filter(mirror -> types.isSameType(idExampleMirror, mirror.getAnnotationType()))
.findFirst().get();
AnnotationValue value =
annotation.getElementValues().entrySet().stream()
.filter(e -> e.getKey().getSimpleName().contentEquals("id"))
.map(e -> e.getValue())
.findFirst().get();
// Actually cause the compilation error.
String errorMessage = String.format("\"%s\" is a duplicate ID.", id);
processingEnv.getMessager()
.printMessage(Diagnostic.Kind.ERROR,
errorMessage,
field,
annotation,
value);
}
}
});
}
return false;
}
}
有关于如何使注释处理正常工作的教程 here。例如,要让上面的示例处理器正常工作,您可以大致执行以下操作(取决于您的 IDE,我假设):
- 为两个 类
mcve.proc.IDExample
和mcve.proc.UniqueIDProcessor
创建一个 project/separate jar。 - 在那个 jar 中,创建一个目录
META-INF/services
。 - 在该目录中,创建一个名为
javax.annotation.processing.Processor
(无文件扩展名)的文本文件,其内容是注释处理器的完全限定名称mcve.proc.UniqueIDProcessor
。 - 将 project/jar 作为库导入到您的主项目中。
- 可能添加
mcve.proc.UniqueIDProcessor
作为注释处理器,例如如果需要这样的设置 exists/is,您的项目属性。我知道 Netbeans 就是这样做的。我不知道其他 IDEs.