Java 在编译时检查传递给方法的字符串参数是否具有@deprecated注释
我想验证传递给方法的字符串是否已弃用。e、 g:Java 在编译时检查传递给方法的字符串参数是否具有@deprecated注释,java,validation,compiler-construction,annotations,Java,Validation,Compiler Construction,Annotations,我想验证传递给方法的字符串是否已弃用。e、 g: public class MyRepo @Deprecated private static final String OLD_PATH = "old_path"; private static final String NEW_PATH = "new_path"; //... public load(Node node){ migrateProperty(node, OLD_PATH
public class MyRepo
@Deprecated
private static final String OLD_PATH = "old_path";
private static final String NEW_PATH = "new_path";
//...
public load(Node node){
migrateProperty(node, OLD_PATH , NEW_PATH );
//load the properties
loadProperty(node, NEW_PATH);
}
//I want to validate that the String oldPath has the @Deprecated annotation
public void migrateProperty(Node node, String oldPath, String newPath) {
if(node.hasProperty(oldPath)){
Property property = node.getProperty(oldPath);
node.setProperty(newPath, (Value) property);
property.remove();
}
}
//I want to validate that the String path does not have the @Deprecated annotation
public void loadProperty(Node node, String path) {
//load the property from the node
}
}
我能找到的最近的标记是。首先,您的“@deprecated”标记只是一个JavaDoc标记,而不是注释,因此它与编译器无关
如果使用@Deprecated
注释,您将在使用Deprecated字段的行中收到Deprecated警告:
@Deprecated
private static final String OLD_PATH = "old_path";
private static final String NEW_PATH = "new_path";
您也可以保留JavaDoc@deprecated
标记,但只有在提供一些解释的情况下,它才有用。javadoc标记必须位于/***/当然是代码>
但是,如果要在运行时在migrateProperty()
方法中检查传递的字符串是否来自不推荐使用的变量,这是不可能的。方法调用得到的是对堆上字符串的引用。弃用仅指字段,该字段可能只能在调用方法之前进行检查。弃用的“旧”(Java 5之前,基于JavaDoc)注释存储在编译的类文件中,但遗憾的是,无法通过反射进行访问
如果您可以选择使用“real”注释(@java.lang.Deprecated),那么当然可以使用反射来获取类的所有声明字段,检查它们是否是带有@Deprecated注释的静态字符串,并将它们与传递的方法参数进行比较
然而,这听起来相当难听,我鼓励您找到一种不同的方法来检查不需要的参数。我不知道您的用例到底是什么,但我认为您不能用@Deprecated做您想做的事情。当您将某些内容标记为已弃用时,您标记的是字段、方法或类,而不是值。您在loadProperty中获得的所有访问权限都是值
以你为例,我很容易打电话给你
new MyRepo().loadProperty("old_path");
完全不引用旧路径或新路径。解决方案很简单,您需要在方法中显式检查匹配项。(添加了isDeprecated方法)。如果愿意,可以保留@Deprecated注释作为指示
public class MyRepo {
@Deprecated
private static final String OLD_PATH = "old_path";
private static final String NEW_PATH = "new_path";
private boolean isDeprecated(String path) {
return OLD_PATH.equals("old_path");
}
//...
public load(Node node){
migrateProperty(node, OLD_PATH , NEW_PATH );
//load the properties
loadProperty(node, NEW_PATH);
}
//I want to validate that the String oldPath has the @Deprecated annotation
public void migrateProperty(Node node, String oldPath, String newPath) {
if (!isDeprecated(oldPath)) {
throw new Exception(oldPath + " is not deprecated");
}
if(node.hasProperty(oldPath)){
Property property = node.getProperty(oldPath);
node.setProperty(newPath, (Value) property);
property.remove();
}
}
//I want to validate that the String path does not have the @Deprecated annotation
public void loadProperty(Node node, String path) {
if (isDeprecated(path)) {
throw new Exception(path + " is deprecated, please use " + NEW_PATH);
}
//load the property from the node
}
}
如果需要将此模式应用于多个类,当然可以使其更加严格。检查“.class”文件是否符合“编译”时间要求?允许对.class文件进行多次检查。您可以编写自定义插件来检查字段、方法和参数(以及许多其他内容)。这是一张旧报纸
如果你能写一个,我会对使用这段代码非常感兴趣:)我的方法是把它变成编译器已经擅长的东西:类型检查
基于您的示例中常数的使用,我将假设您有一组已知的潜在值,这表示enum
s
public class MyRepo
private enum Preferred {
PATH("new_path"),
OTHER_THING("bar");
private String value;
Preferred(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
private enum Legacy {
PATH("old_path"),
OTHER_THING("foo");
private String value;
Legacy(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
public load(Node node){
migrateProperty(node, Legacy.PATH, Preferred.PATH);
//load the properties
loadProperty(node, Preferred.PATH);
}
public void migrateProperty(Node node, Legacy oldBusted, Preferred newHotness) {
if (node.hasProperty(oldBusted)) {
Property property = node.getProperty(oldBusted);
node.setProperty(newHotness, (Value) property);
property.remove();
}
}
public void loadProperty(Node node, Preferred path) {
//load the property from the node
}
}
如果这不符合您的需要,请添加有关您的使用场景以及您试图解决的潜在问题的更多信息
如果您真的打算通过注释来实现这一点,那么似乎有一种方法。Java6在javac
中内置了注释处理API,这些API似乎是编译器的插件。他们可以做你想做的事,而且还可以做很多,但至少乍一看,他们似乎相当深奥。这看起来是一个很好的介绍:您的注释将字段OLD\u PATH
标记为已弃用,而不是字符串“OLD\u PATH”
。在对migrateProperty
的调用中,传递的是字符串,而不是字段。因此,该方法不知道值来自哪个字段,也无法检查它是否有注释
通过注释,您可以声明一些关于Java元素的内容,比如类、字段、变量和方法。不能对对象(如字符串)进行注释
您链接到的文章讨论了注释形式参数。同样,注释的是参数,而不是参数(传递的值)。如果将@Something放在方法参数中,则此参数将始终独立于此方法的调用方传递的值进行注释
你能做的是——但我不确定这是否是你想要的——如下所示:
@Deprecated
private static final String OLD_PATH = "old_path";
private static final String NEW_PATH = "new_path";
public load(Node node){
migrateProperty(node,
getClass().getDeclaredField("OLD_PATH"),
getClass().getDeclaredField("NEW_PATH") );
// ...
}
//I want to validate that the String oldPath has the @Deprecated annotation
public void migrateProperty(Node node, Field<String> oldPath, Field<String> newPath) {
if ( oldPath.getAnnotation(Deprecated.class) == null ) {
// ... invalid
}
// ...
}
@已弃用
私有静态最终字符串OLD\u PATH=“OLD\u PATH”;
私有静态最终字符串NEW\u PATH=“NEW\u PATH”;
公共负载(节点){
migrateProperty(节点,
getClass().getDeclaredField(“旧路径”),
getClass().getDeclaredField(“新路径”);
// ...
}
//我想验证字符串oldPath是否具有@Deprecated注释
public void migrateProperty(节点节点、字段oldPath、字段newPath){
if(oldPath.getAnnotation(弃用的.class)==null){
//…无效
}
// ...
}
在这种情况下,您实际上传递的是字段,而不是它的值。在编译时根本不可能这样做
首先,@Distributed注释可以引用字符串字段,但无论如何都不会附加在字符串值中
其次,即使您可以以某种方式用注释标记字符串值,Java类型系统中的任何内容都不允许您声明只能传递带有特定注释的值——注释信息甚至不一定在编译时可用
由于第1点,注释处理无法工作。由于第2点,所有其他方案仅在运行时有效
要实现编译时检查,最自然的方法是创建一个包含字符串所有有效值的枚举。编译器在生成的类文件中确实包含了基于JavaDoc的@deprecated标记。否则,在针对提供的第三方库(甚至是标准API)进行编译时,不推荐使用警告将不可用。我已将示例代码更改为使用@Deprecated。我没有收到任何警告,除了通过变量敲打。不过,我不想看到任何警告,我想验证@Deprecated注释是否存在于f上