I am writing a library, so I don't often use the methods in my classes within the same project. As such, my IDE (IntelliJ IDEA) keeps warning me that the methods are unused.
Of course, the obvious solution is to place #SuppressWarnings("unused") before the classes. I don't like this; it doesn't describe the reason I'm writing that annotation and is very verbose. I would love to make an annotation like #LibraryClass which is just an alias of #SuppressWarnings("unused").
In short, I want to be able to change this:
#SuppressWarnings("unused")
public class MyLibraryClass {
public void myLibraryMethod() {
doSomething();
}
}
to this:
#LibraryClass
public class MyLibraryClass {
public void myLibraryMethod() {
doSomething();
}
}
but I have no idea how to do this! I tried all this, and it compiles, but the IDE still warns of unused methods:
#SuppressWarnings("unused")
#Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
#Retention(RetentionPolicy.SOURCE)
public #interface Library {
SuppressWarnings superAnnotation() default #SuppressWarnings("unused");
String[] value() default {"unused"};
}
To do one aspect of what you're asking for - attaching some kind of compile-time logic to annotations - you need to look into annotation processing. An annotation processor hooks into the Java runtime, like an agent, and gets informed about annotations and given an option to process it. To use that, you'd have to put your annotation-processor jar on the IDE's classpath.
Some links:
http://hannesdorfmann.com/annotation-processing/annotationprocessing101
http://programmaticallyspeaking.com/playing-with-java-annotation-processing.html
However, that wouldn't allow you to change the way that Intellij detects unused methods, which seems to be closer to your specific use case. What you could do there is to modify the Intellij 'unused method' inspection so that it incorporates a check for the custom annotation you've defined. YMMV, I've never had to do that at the class level before.
https://gist.github.com/itzg/5e90609cde1473ef9d4d
Related
In Java I have the possibility to "implement" annotations.
Sample Java annotation:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface JavaClassAnno {
String[] value();
}
Sample Java "implementation":
class MyAnnotationLiteral
extends AnnotationLiteral<JavaClassAnno>
implements JavaClassAnno { // <--- works in Java
private String value;
public MyAnnotationLiteral(String value) {
this.value = value;
}
#Override
public String[] value() {
return new String[] { value };
}
}
Trying to port that to Kotlin doesn't work as it says that the annotation is final and therefore can not be inherited, i.e. the following will not work:
class MyAnnotationLiteral(private val internalValue: String)
: AnnotationLiteral<JavaClassAnno>(),
JavaClassAnno { // <--- doesn't work in Kotlin (annotation can not be inherited)
override fun value(): Array<String> {
return arrayOf(internalValue)
}
}
How do you "implement/extend" annotations the Kotlin way? Could not find any reason why Kotlin differs in that regard to Java. Any hint how to solve that problem or any sources that tell why it is that way are welcome.
The following question contains a use case for this constellation: Dynamically fire CDI event with qualifier with members.
Basically you require something like this to narrow down which qualifier should trigger based on its members.
Note that this would also apply to a Kotlin annotation as well as it seems that a Kotlin annotation can not be open and therefore not be implemented/extended too.
What I found so far is rather mentioning #Inherited as a problem:
https://discuss.kotlinlang.org/t/inherited-annotations-and-other-reflections-enchancements/6209
https://youtrack.jetbrains.com/issue/KT-22265
But I did not find any reason why the annotation is not implementable/inheritable as it is in Java.
I also asked this question now here: https://discuss.kotlinlang.org/t/implement-inherit-extend-annotation-in-kotlin/8916
Update: Finally I found something regarding this design decision, namely the following issue (while I was opening my own issue for it): Annotations inheritance. Either prohibit or implement correctly. As it seems the decision was to "prohibit" it, even though there are no (visible?) comments, discussions or other sources about that decision.
Added the following issue: https://youtrack.jetbrains.com/issue/KT-25947
As of Kotlin 1.3, this case is not supported. To create custom instances of annotations one has to resort to Java for now. One of the reasons for this design decision is that making annotations interfaces is too JVM-specific and wouldn't map well to other platforms.
I'm trying to understand the use of 'Annotations' a bit better.
I understand that:
How to access annotations in my code for example via this complete tutorial.
I can create methods to perform desired operations
To understand this better, I created a virtual problem as following:
There are Annotations TestAnnotation1, TestAnnotation2, TestAnnotation3(definition is available latter in the question). I wants to execute the methods of class MethodsExecutorClass as following:
When TestClass.java compiles then execute CommonMethod() and RetentionPolicySOURCEMethod()
When TestClass.class loads then execute CommonMethod() and RetentionPolicyCLASSMethod()
Whenever testMethod() method of TestClass.java executes then execute CommonMethod() and RetentionPolicyRUNTIMEMethod()
By this example I wants to understand following:
Can I instruct Java compiler (javac) or Java Runtime Environment (jvm) to execute a method in my class(e.g. CommonMethod()andRetentionPolicySOURCEMethod()methods ofMethodsExecutorClass`).
Can I delegate the monitoring (i.e. searching the methods/classes which are using my annotation etc.) to any other entity(which is available in Java SE).
I want to do something like #Override and #deprecated annotations. We don't do something extra. Although on Oracle javadoc site, here it is clearly mentioned that The Java platform has always had various ad hoc annotation mechanisms. and #deprecated is one of them. But I wondered If I can do something like this.
Definitions should look like as following:
MyAnnotations.java:
#Retention(RetentionPolicy.SOURCE)
public #interface TestAnnotation1
{
String className();
}
#Retention(RetentionPolicy.CLASS)
public #interface TestAnnotation2
{
String className();
}
#Retention(RetentionPolicy.RUNTIME)
public #interface TestAnnotation3
{
String className();
String methodName();
}
MethodsExecutorClass.java:
class MethodsExecutorClass
{
public static void CommonMethod()
{
System.out.println("In method: CommonMethod()");
}
public void RetentionPolicySOURCEMethod()
{
System.out.println("In method: RetentionPolicySOURCEMethod()");
//Also print annotation arguments e.g. Class name etc
}
public void RetentionPolicyCLASSMethod()
{
System.out.println("In method: RetentionPolicyCLASSMethod()");
//Also print annotation arguments e.g. Class name etc
}
public void RetentionPolicyRUNTIMEMethod()
{
System.out.println("In method: RetentionPolicyRUNTIMEMethod()");
//Also print annotation arguments e.g. Class name etc
}
}
TestClass.java:
#TestAnnotation1(TestClass.class)
#TestAnnotation2(TestClass.class)
class TestClass
{
#TestAnnotation2(TestClass.class, "testMethod()")
public void testMethod()
{
System.out.println("In method: testMethod()");
}
}
May you help me in achieving this? (Please no guess or assumptions, but presumptions would be also helpful).
I'm not sure if this can be achieve, but looking forward.
Annotations with retention policy RetentionPolicy.SOURCE are only available during compilation time of the code so your compiler should support your annotation to use it, otherwise it's not possible to handle the annotation. Usually, such annotations are used to detect possible problems at compilation time, for example, annotation #Override. That's why your first problem can't be implemented in usual ways.
Annotations with retention policy RetentionPolicy.CLASS are available only in .class files and can be used via JVMs. Please see this answer how it can be used. The second your problem also can't be implemented via standard ways.
Commonly used annotations are with retention policy RetentionPolicy.RUNTIME that are available via reflection mechanism in Java. But to solve your third problem you have to use some method invocation interceptors, for example, via Aspect Oriented Programming. After that you can get method's annotations via method.getDeclaredAnnotations().
Can I instruct Java compiler (javac) or Java Runtime Environment (jvm)
to execute a method in my class(e.g.
CommonMethod()andRetentionPolicySOURCEMethod()methods
ofMethodsExecutorClass`).
No, you can't.
Can I delegate the monitoring (i.e. searching the methods/classes
which are using my annotation etc.) to any other entity(which is
available in Java SE).
You can do it via AOP, for example, use the library AspectJ.
When I don't assign result of BigDecimal.divide() method to a variable, I get a nice warning from IntelliJ Idea:
Result of BigDecimal.divide() is ignored.
Can I somehow get the same warning for my own (side-effect free) functions? Something like assigning a Java annotation to my function.
This is the "Result of method call ignored" inspection. By default, it only reports a couple of special methods, including all methods of java.lang.BigDecimal. In the inspection configuration you can add other classes and methods that should be reported in this way.
The "Report all ignored non-library calls" check box selects all classes in your project.
If you want to use annotations, you can annotate single methods or entire classes with the JSR 305 annotation
javax.annotation.CheckReturnValue
Since IDEA 2016.3 you can even use the error prone annotation
com.google.errorprone.annotations.CanIgnoreReturnValue
to exclude single methods from return value checking. Using both annotations, you can write a class like this:
import javax.annotation.CheckReturnValue;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
#CheckReturnValue
class A {
String a() { return "a"; }
#CanIgnoreReturnValue
String b() { return "b"; }
void run() {
a(); // Warning
b(); // No warning
}
}
I've created an Annotation
/**
* Highlights this method is declared in XML
*/
public #interface FromXML {
}
I'm using this on methods that look like this:
#FromXML
public void onSomethingClick(View v){
}
The v variable is needed by the Android reflection system to call this method.
However the input var v is unused, so my IDE warns me of this. I like this warning and want it on for the rest of my code.
To hide the warning I could do
#SuppressWarnings("unused")
#FromXML
public void onSomethingClick(View v){
}
or I could add a param tag
But I would rather that the IDE (eclipse) reads my #FromXML annotation and doesn't give me the warning.
I know you can't extend an Annotation, but thats basically what I want to do.
Is there a way I can add my annotation to be recognised as a 'suppress warnings' annotation.
or
Is there a way to code my annotation to 'act like' suppress warnings?
You can always create a plugin for Eclipse, that would scan through the source and find these annotations in your case #FromXML and add an extra annotation in your case #SuppressWarnings.
You could create a Command for it and when that command is fired you would run this plugin.
Creating Eclipse Plugin
Hope this helps.
UPDATE - IT WAS A FLUKE CANNOT BE DONE USING THIS (TRIED IT):
Or Using AspectJ for removing the warnings
Adding warnings in Eclipse using AspectJ
This tutorial uses AspectJ for adding warnings to eclipse if developer uses System.out.println() in the code. So the reverse can be done to remove the warning when annotation is present.
UPDATE 2: There is a way in Eclipse to create custom annotation processor or editting the bundeled annotation processor (that generates the unused variable warning). So will have to tweak that processor in a custom way.
Some great links:
Tutorials for Eclipse Annotation processor development
Java Development Tools - Annotation Processing Tools
I think you could create an interface defining this method. That way, your class will override the method and there should not be any warning.
FromXML.java:
public #interface FromXML {
}
MyInterface.java:
public interface MyInterface {
#FromXML
public void onSomethingClick(View v);
}
MyClass.java
public MyClass implements MyInterface {
#Override
#FromXML
public void onSomethingClick(View v){
}
}
EDIT :
Another solution could be to define your method as abstract. Indeed, as I understand your code, your methods are just declaration (Implementations are in a XML file). So, your problem is more a design problem than an IDE problem (your IDE is just right about the warning). The reality is that your method is abstract and is defined somewhere else.
Thus, defining your method as abstract will solve the problem but you'll have to make the class abstract:
public abstract class MyClassUsingOnSomethingClick {
/*
* All the class implementation can be here as the normal class.
*/
#FromXML
public abstract void onSomethingClick(View v);
}
I know you'll say that this solution make it impossible to create object easily but you'll have two solutions then:
1 - Create your objects inline:
MyClassUsingOnSomethingClick a = new MyClassUsingOnSomethingClick() {
#Override
#FromXML
public void onSomethingClick(View v) {}
};
2 - Create a factory method in your abstract MyClassUsingOnSomethingClick:
public static final MyClassUsingOnSomethingClick createEmptyMyClassUsingOnSomethingClick() {
return new MyClassUsingOnSomethingClick() {
#Override
#FromXML
public void onSomethingClick(View v) {}
};
}
// and then, create with: :
MyClassUsingOnSomethingClick a = MyClassUsingOnSomethingClick.createEmptyMyClassUsingOnSomethingClick();
Even is I understand that you would prefer a faster solution, I believe that this solution is the cleanest because:
It respects the Object Oriented Programming philosophy.
It is not specific to an IDE.
It avoids Annotation Processing Tool (which, in my opinion should be used very wisely)
Ok I can't do this in any easy way or form.
Looking at the annotation package http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/package-summary.html
I can't extend an annotation:
Why is not possible to extend annotations in Java?
I can't implement another annotation java.lang.Override
I can't mimic / mock / pretend to be #Override
If I add #Override to my #FromXML it is NOT inherited down the chain.
The only way would be to create an Eclipse plugin that recognises my annotation and stops the warning. Shame because I can't find an easy way to do this.
I also went down the route of creating an interface for my #FromXML entry points, this was very nice and communicated my Activity was of a type and therefore I didn't need the annotation anymore, perhaps this design change is the answer.
do they by annotation mean a comment in a code with // or /* */?
No, an annotation is not a comment. An annotation is added to a field, class or method, using the syntax #Annotation. One of the best known annotations is #Override, used to signal a method is overriding one from a super class. For example:
public class MyClass {
#Override
public boolean equals(Object other) {
//...
}
}
See http://download.oracle.com/javase/1,5.0/docs/guide/language/annotations.html for more info.
No, annotations take the form:
#Annotation(property="A")
public class {
#Annotation(property="B")
Object field;
#Annotation(property="C")
public void method() {
}
}
Annotations can be placed on classes, methods or fields. They can provide information at runtime via reflection or compile time via apt (short for Annotation Processing Tool and not the apt package manager).
They are defined as:
#interface Annotation {
String property();
}
See http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html for more
Actually, before Java5 (i.e. 1.3 or 1.4), comments (// or /* */) were the only way to add annotation (i.e. "metadata") to be acted upon.
One classic example is the way the unit-testing framework TestNg propose all its Java5 #Annotations as comments if you are using TestNg with Java 1.4.
But that means, for Testng to launch the proper test suite, it had to access the sources of your program, not just the compiled binary.
Unlike Javadoc tags, Java annotations can be reflective in that they can be embedded in class files generated by the compiler and may be retained by the Java VM to be made retrievable at run-time.
No.
An annotation is a special construct introduced with java 1.5. An annotation adds some meta information to a java class, method or variable. This meta information can be evaluated at compile time (e.g. for generating some extra code with apt) or at runtime (e.g. to match a class to a database table).
Example for a built in annotation:
#Deprecated // this is an annotation
public void myMethod() {
...
}
Annotations are not just for java they also exist in c++, they are somehow similar with those from java.
// MyCode.h
# include <CodeAnalysis/SourceAnnotations.h>
using namespace vc_attributes;
class CMyClass
{
public:
void f ( [Pre ( Valid = Yes )] int *pWidth );
// code ...
};
// MyCode.cpp
#include "MyCode.h"
void CMyClass::f ( [Pre (Valid = Yes)] int pWidth )
{
}
You can check the MSDN for more information:
http://msdn.microsoft.com/en-us/library/ms182036(VS.80).aspx
An annotation is not a comment but it is used for many purposes such as error debugging as well it is the instruction set to the compiler but it hasn't any effect on the runtime code.
#override,#deprecated and others are the examples of annotation. It can be used with methods,constructors,parameters,variables.
Annotations are used to give detailed information to the compiler whereas Comments are for the convenience of the programmer so that he know how the code is structured.
of course not, but I think annotation ≈ comment.
the core of them is describe, but annotation has more confinement, you are not easy to make mistak, also, you can find mistake in compile time.