如何故意导致自定义java编译器警告消息?

pim*_*ttc 74 java javac compiler-warnings

我要做一个丑陋的临时黑客,以便在我们等待修复外部资源时解决阻塞问题.除了用一个可怕的评论和一堆FIXME来标记它之外,我很乐意让编译器抛出明显的警告信息作为提示,所以我们不要忘记把它拿出来.例如,类似于:

[javac] com.foo.Hacky.java:192: warning: FIXME temporary hack to work around library bug, remove me when library is fixed!
Run Code Online (Sandbox Code Playgroud)

有没有办法可以使用我选择的消息引起有意的编译器警告?如果做不到这一点,最简单的事情是添加到代码中以抛出现有警告,可能在违规行的字符串中有一条消息,以便在警告消息中打印出来?

编辑:不推荐的标签似乎没有为我做任何事情:

/**
 * @deprecated "Temporary hack to work around remote server quirks"
 */
@Deprecated
private void doSomeHackyStuff() { ... }
Run Code Online (Sandbox Code Playgroud)

在eclipse或sun javac 1.6(从ant脚本运行)中没有编译器或运行时错误,它肯定正在执行该函数.

bar*_*jak 85

我认为将由编译器处理的自定义注释是解决方案.我经常编写自定义注释来在运行时执行操作,但我从未尝试在编译时使用它们.所以,我只能指出你可能需要的工具:

  • 编写自定义注释类型.本页介绍了如何编写注释.
  • 编写注释处理器,处理自定义注释以发出警告.运行此类注释处理器的工具称为APT.你可以在这个页面找到一个indroduction .我认为您在APT API中需要的是AnnotationProcessorEnvironment,它可以让您发出警告.
  • 从Java 6开始,APT被集成到javac中.也就是说,您可以在javac命令行中添加注释处理器.javac手册的这一部分将告诉您如何调用自定义注释处理器.

我不知道这个解决方案是否真的可行.当我找到一些时间时,我会尝试自己实现它.

编辑

我成功实施了我的解决方案 作为奖励,我使用java的服务提供商工具来简化其使用.实际上,我的解决方案是一个包含2个类的jar:自定义注释和注释处理器.要使用它,只需在项目的类路径中添加此jar,并注释您想要的任何内容!这在我的IDE(NetBeans)中正常工作.

注释代码:

package fr.barjak.hack;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE})
public @interface Hack {

}
Run Code Online (Sandbox Code Playgroud)

处理器代码:

package fr.barjak.hack_processor;

import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;

@SupportedAnnotationTypes("fr.barjak.hack.Hack")
public class Processor extends AbstractProcessor {

    private ProcessingEnvironment env;

    @Override
    public synchronized void init(ProcessingEnvironment pe) {
        this.env = pe;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (!roundEnv.processingOver()) {
            for (TypeElement te : annotations) {
                final Set< ? extends Element> elts = roundEnv.getElementsAnnotatedWith(te);
                for (Element elt : elts) {
                    env.getMessager().printMessage(Kind.WARNING,
                            String.format("%s : thou shalt not hack %s", roundEnv.getRootElements(), elt),
                            elt);
                }
            }
        }
        return true;
    }

}
Run Code Online (Sandbox Code Playgroud)

要将生成的jar作为服务提供者启用,请在jar中添加该文件META-INF/services/javax.annotation.processing.Processor.此文件是一个必须包含以下文本的acsii文件:

fr.barjak.hack_processor.Processor
Run Code Online (Sandbox Code Playgroud)

  • 小注意:没有必要覆盖`init`并设置`env`字段 - 你可以从`this.processingEnv`获得`ProcessingEnvironment`,因为它是`protected`. (8认同)
  • Eclipse中默认关闭注释处理.要打开它,请转到项目属性 - > Java编译器 - >注释处理 - >启用注释处理.然后在该页面下面是一个名为"Factory Path"的页面,您需要在其中配置具有您要使用的处理器的jar. (4认同)
  • +1,很棒的研究!这绝对是做到这一点的"正确方法"(如果单元测试不实用),并且它具有超越常规警告的优势. (3认同)

Kev*_*Day 37

我见过的一种技术是将其与单元测试联系起来(你单元测试吧?).基本上,一旦实现外部资源修复,您就会创建一个单元测试失败.然后你评论单元测试,告诉别人一旦问题解决后如何撤消你的粗暴黑客.

这种方法的真正含义是,撤消黑客攻击的触发器是解决核心问题本身的问题.

  • 我在一场 No Fluff Just Stuff 会议上听说过这个(不记得主持人是谁)。我以为它很光滑。不过,我绝对推荐这些会议。 (2认同)
  • 我想看看这种方法的一个例子 (2认同)

Luc*_*ein 13

一些快速且不那么脏的方法,可能是使用@SuppressWarnings带有故意错误String参数的注释:

@SuppressWarnings("FIXME: this is a hack and should be fixed.")
Run Code Online (Sandbox Code Playgroud)

这将生成警告,因为编译器无法将其识别为要禁止的特定警告:

不支持的@SuppressWarnings("FIXME:这是一个黑客,应该修复.")

  • 它不能用于抑制字段可见性警告或lint错误. (4认同)
  • 讽刺的是分散注意力。 (3认同)

WRe*_*ach 12

一个好的黑客应该得到另一个...我通常通过在hacky方法中引入一个未使用的变量来为所描述的目的生成编译器警告,因此:

/**
 * @deprecated "Temporary hack to work around remote server quirks"
 */
@Deprecated
private void doSomeHackyStuff() {
    int FIXMEtemporaryHackToWorkAroundLibraryBugRemoveMeWhenLibraryIsFixed;
    ...
}
Run Code Online (Sandbox Code Playgroud)

这个未使用的变量将生成一个警告(取决于您的编译器)将看起来像这样:

WARNING: The local variable FIXMEtemporaryHackToWorkAroundLibraryBugRemoveMeWhenLibraryIsFixed is never read.

这个解决方案不如自定义注释好,但它的优点是它不需要提前准备(假设编译器已配置为对未使用的变量发出警告).我建议这种方法只适用于短暂的黑客攻击.对于长期存在的黑客攻击,我认为创建自定义注释的努力是合理的.


Art*_*lin 8

我写了一个用注释执行此操作的库:Lightweight Javac @Warning Annotation

用法很简单:

// some code...

@Warning("This method should be refactored")
public void someCodeWhichYouNeedAtTheMomentButYouWantToRefactorItLater() {
    // bad stuff going on here...
}
Run Code Online (Sandbox Code Playgroud)

编译器会向您的文本发出警告消息

  • 谢谢!见http://meta.stackexchange.com/questions/57497/limits-for-self-promotion-in-answers (2认同)

Pet*_*ore 5

如何将方法或类标记为@Deprecated?这里的文档.请注意,有@Deprecated和@deprecated - 大写D版本是注释,小写d是javadoc版本.javadoc版本允许您指定一个任意字符串来解释正在发生的事情.但编译器在看到它时不需要发出警告(尽管许多人都这样做).注释应始终引发警告,但我不认为您可以添加解释.

这里更新的是我刚刚测试过的代码:Sample.java包含:

public class Sample {
    @Deprecated
    public static void foo() {
         System.out.println("I am a hack");
    }
}
Run Code Online (Sandbox Code Playgroud)

SampleCaller.java包含:

public class SampleCaller{
     public static void main(String [] args) {
         Sample.foo();
     }
}
Run Code Online (Sandbox Code Playgroud)

当我运行"javac Sample.java SampleCaller.java"时,我得到以下输出:

Note: SampleCaller.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Run Code Online (Sandbox Code Playgroud)

我正在使用sun的javac 1.6.如果您想要诚实的善意警告而不仅仅是注释,请使用-Xlint选项.也许这会通过Ant正确渗透.

  • 对于记录,"@ Deprecated"仅适用于各种类(因此对私有方法没用). (3认同)