Using annotation to ensure that value returned by method is not discarded

∥☆過路亽.° 提交于 2019-12-02 17:58:43

You could also check out jsr305 it defines a @CheckReturnValue annotation. It's compatible with findbugs and generates a warning when someone forgets to handle the return value.

Guavas Splitter uses it: http://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/base/Splitter.java

I must say that I love annotations that can guide static code analysis.

Pascal Thivent

I'm not sure of the feasibility - especially in a portable way - but have a look at Roman Numerals, in our Java (GitHub code) from Adrian Kuhn. He used annotation processing AND Sun's javac private API to adds Roman numeral literals to Java by visiting the source code to do some replacement.

Maybe you could use a similar approach to:

  • find calls to your annotated method in the source code
  • check if the result is assigned (won't be easy IMO)
    • generate a compiler warning if not

And don't miss the following resources from Adrian's post:

You may also like

Reference

Related questions

In a nut: you'd like to have a @Deprecated like annotation which would assist the compiler/IDE to warn/error when the method is been called without assigning its result? You can't achieve this without modifying the Java source code and the compiler. The particular method has to be annotated and the compiler has to be aware of them. Without modifying the source and/or compiler, you can at highest create kind of an IDE plugin/setting which recognizes the cases and generates an error/warning accordingly.


Update: you could write a framework/plugin around it which checks the called method and errors accordingly. You would only like to have the annotation available during runtime. You can do this by annotating the annotation using @Retention (RetentionPolicy.RUNTIME). Then, you can use Method#getAnnotation() to determine if this annotation is available. Here's a kickoff example how such a framework could do this job:

package com.example;

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

public class Test {

    public static void main(String[] args) throws Exception {
        if (Test.class.getMethod("f", new Class[0]).getAnnotation(Undiscardable.class) != null) {
            System.err.println("You should not discard the return value of f()!");
        } else {
            f();
        }

        System.out.println(f());
    }

    public static @Undiscardable int f() {
        return 42;
    }
}

@Retention(RetentionPolicy.RUNTIME)
@interface Undiscardable {}

Still then, to get the compiler do the job instead, you have to do a bit more work.

On Android you can use @CheckResult to show a warning if return value isn't used.

public class ImmutableObject {

    public final int value;

    public ImmutableObject(int value) {
        this.value = value;
    }

    @CheckResult
    public ImmutableObject addOne() {
        return new ImmutableObject(value + 1);
    }
}

This will issue a warning:

ImmutableObject obj = new ImmutableObj();
obj.addOne();  // Warning here
ImmutableObject obj2 = obj.addOne();  // No warning

If using RxJava, you can also use @CheckReturnValue.

You do not need to define an annotation. You could define a rule when a method is invoked:

  1. the method has a void return type;
  2. the result of the method is used as the argument for another method invocation; or
  3. the result of the method is assigned to a variable.

You could implement a Processor that enforces this rule or implement a Checkstyle that enforces this rule.

Disclaimer: Actually, I have the same question and not yet a complete solution. BUT:

I have an idea how this could be done in a clean way, which I want to post here, while trying to get it done:

  1. One may use AspectJ to invoke code after a specific method has been called. For example

    @AfterReturning(pointcut=“call(int Foo.m(int))”, returning=”x”)
    public void doSomething(int x){ ... }
    could be used. The return value x is passed to your method.
  2. Your method could then watch for the reference count of the return value. If the return value is Garbadge Collected it was thrown away and you could issue a warning, see, e.g., http://java.dzone.com/articles/letting-garbage-collector-do-c

Of course, I would prefer an annotation and compile time support for this, since the above is maybe only suitable in a testing environment and maybe not in production (due to its performance impact).

Any comments if this could work?

You have a problem and the problem is that people may mistakenly forget to use the returns of methods. By using annotations you are telling the library writer that they must be responsible for reminding their callers to not throw away the results of certain methods.

While it seems like a good idea, I don't think it is. Do we want to clutter up code with notices to users about their poor practice? There are plenty of products that look at code and tell you when you are doing something wrong (or undesirable) like Lint, Sonar and even JavaDocs to a lesser extent.

What if you disagree with what the library writer has said, are we now expected to use @SuppressWarnings("return-discarded").

While this might be helpful as a learning aid, my point is more to do with the separation of concerns than helping novice programmers. The code (and annotations) in the class should be related to the function of the class and not setting out the policy of when and how to use it's methods.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!