I use Spring to build a ModelMap, which is rendered and then parsed by Mustache. For this reason, I have some classes that only exist to wrap data for Mustache's convenience.
These classes have fields and methods that are never used in the code, but are in fact used by Spring (and, in turn, Mustache). I want to explicitly state that this is intentional by annotating the class with a custom annotation #ForMustache that looks like this:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.SOURCE)
public #interface ForMustache {
}
My goal is basically a fancy way of saying #SuppressWarnings("unused") // For Mustache.
I attempted to annotate ForMustache with #SuppressWarnings("unused"), but its effects apply inside my annotation instead of being propagated to the type annotated with #ForMustache.
Can I proxy or imitate #SuppressWarnings("unused") with another annotation?
The #SuppressWarnings annotation is meant for the compiler and other compile time tools that work directly on the source files.
It is also specified as
#Retention(RetentionPolicy.SOURCE)
public #interface SuppressWarnings { ...
meaning it's not supposed to be available anymore at runtime. This means that even springs meta-annotation aware processing can't see it anymore.
Given enough time, you could build an annotation processor that, during compile-time, transforms a custom #ForMustache annotation into a #SuppressWarnings so the compiler can pick it up. In similar fashion Lombok can turn
#Data
class Foo {
private final String value;
}
into a) code that compiles and doesn't complain about no assignment to a final field and b) it wouldn't generate a warning because it generates a public getter for the field. Those can only be assumed to be used / they are usable from places outside the compiler's reach.
Besides putting #SuppressWarnings everywhere, your only chance is to remove the condition that causes the warning.
Disable the check with a compiler option
add public getters or other code so the fields are used (with lombok for example)
hook into the compile process.
Related
Is there way to do compile-time annotation processing in Java?
Consider this example:
#Name("appName")
private Field<String> appName;
public void setAppName(String name) {
appName.setValue(name);
}
public String getAppName(String name) {
return appName.getValue();
}
public void someFunction() {
String whatFieldName = appName.getName();
}
Where the annotation Name will be processed at compile-time to set the value for Field That is without the common runtime annotation processing. As such, when appName.getName(); (the Field) is accessed it will return the typed value.
Yes, there is, but, no, it cannot change existing files. You can 'plug in' to the compiler and be informed of any annotations; as part of this, you can see signatures (so, field declarations, method signatures, types, etc) but no contents (so not the expression used to initialize a field, and not the contents in the {} of a method declaration), and you can make NEW files, even java files, but you can't edit existing ones.
Project Lombok does edit them, but that is quite the framework to make that possible.
There are some crazy tricks you can use. Project lombok uses one trick (reflect its way into compiler internals, fix everything from there, install agents and plugins in IDEs). Another trick is to use a java source file as a template, of sorts. You name your class some funky (so if you want, say, public class AppDescriptor, you'd actually make the java file AppDescriptorTemplate.java and put public class AppDescriptorTemplate inside. This file has the annotation precisely as you pasted. Your annotation processor can then, during compilation, generate AppDescriptor.java, writing the impls of all methods as simple pass-throughs (a field of type AppDescriptorTemplate is generated, and all methods in ADT are copied over, and the implementations are all one-liners that just invoke that method on the template class). The template class can be package private. In this specific scenario it sounds like you can generate virtually the whole thing based off of pretty much only "appName", though.
Lombok plugs straight into the build and is therefore virtually entirely transparent, in the sense that you simply type in your IDE and the methods it generates just appear as you type, whereas 'normal' annotation processors that e.g. use the XTemplate trick do not work that way and require the build system to kick in, every time. It can be a bit of a productivity drain.
I have a Java package that contains annotations used by external clients. The package appeared before Java 8, so historically these annotations have targets ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE. Now the package requires at least Java 8 version. Semantically the annotations in the package are applicable to the types, so e.g. when the method is annotated, the annotation effectively applies to the method return type. Now clients want to annotate generic type arguments as well (e.g. List<#MyAnnotation String>). Since we dropped the support of Java 7 and below, it seems quite natural to set the annotation target to ElementType.TYPE_USE and, to reduce ambiguity, remove the existing targets.
Here's the question: are there any compatibility risks for existing clients when replacing ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE targets with TYPE_USE? Is it possible that the existing code will stop compiling? What about binary compatibility? May it cause any runtime problems if the class-files compiled before the change are used together with newer annotations pack at runtime?
Annotations' retention policy is CLASS if this matters.
There are a number of source compatibility issues that may arise during this change:
Methods with void return type cannot be annotated anymore. #MyAnnotation void method() {} is compilable with ElementType.METHOD target but not compilable with TYPE_USE target.
When a qualified type is used in the source code, the TYPE_USE annotation must appear after the qualifier. E.g. void method(#MyAnnotation OuterClass.InnerClass param) {} is a valid code with ElementType.PARAMETER target, but should be updated to void method(OuterClass.#MyAnnotation InnerClass param) {} after changing to TYPE_USE.
Annotation applied to arrays will have a different meaning. E.g. before the migration #MyAnnotation String[] getData(); annotates the method getData, so the annotation clients likely assume that annotation is applied to the return type (an array of strings). After the migration, the same code means that the annotation is applied to the array component (string). This might cause a behavioral change, depending on the annotation semantics and how it's processed by clients. To preserve the meaning, clients should update such a code to String #MyAnnotation [] getData();.
Such a change makes all usages of the annotations in Kotlin code invalid. In Kotlin, there's strict syntactical difference between TYPE_USE annotations and others. E.g. a PARAMETER annotation must be used as fun(#MyAnnotation param : String) {...}. This is incorrect for TYPE_USE annotation, which must be used as fun(param : #MyAnnotation String) {...}. If your clients use Kotlin they will have to fix every single annotation use.
Such a change disallows using your annotations in Groovy code. Currently, as Groovy documentation says, Groovy does not support the TYPE_PARAMETER and TYPE_USE element types which were introduced in Java 8. If your clients use Groovy they won't be able to use your annotation package anymore.
No problems should arise at runtime though. As annotations' retention policy is CLASS (not RUNTIME), while the annotations present in class files they are ignored by the runtime. It's not necessary to add your annotation pack to the classpath at all.
Here's the java-doc of NonNull annotation of Lombok:
If put on a parameter, lombok will insert a null-check at the start of
the method / constructor's body, throwing a {#code
NullPointerException} with the parameter's name as message. If put on
a field, any generated method assigning a value to this field will
also produce these nullchecks. Note that any annotation named {#code
NonNull} with any casing and any package will result in nullchecks
produced for generated methods (and the annotation will be copied to
the getter return type and any parameters of generated methods), but
only this annotation, if present on a parameter, will result
in a null check inserted into your otherwise handwritten method.
WARNING: If the java community ever does decide on supporting a single
{#code #NonNull} annotation (for example via JSR305), then this
annotation will be deleted from the lombok package.
If the need to update an import statement scares you, you should use
your own annotation named {#code #NonNull} instead of this one.
What is the simplest way to have my own annotation, let's say NonNullNonnull, and Lombok to inject null-check based on my annotation?
Update: my question is hot to have an annotation to use for method arguments.
First, you need to name it nonNull (casing is irrelevant). NotNull will not be recognized by Lombok. Additionally you need to set another Lombok annotation (e.g. #Data, #Setter, ...), so that your type gets processed by Lombok.
Summarizing your custom annotation isn't probably as valuable as the #lombok.NonNull-annotation itself. An example where you benefit from the #lombok.NonNull-annotation, where your custom annotation wouldn't even be processed, is, when your type doesn't contain any other Lombok annotation, e.g.:
class NoLombokAnnotationsAnywhere {
void testMe(#lombok.NonNull String nonNull) { /* .. */ }
}
will produce a NullPointerException as soon as you call new NoLombokAnnotationsAnywhere().testMe(null). Whereas this wouldn't throw anything with your custom annotation. Of course this only applies as long as you don't have any other Lombok annotations there. As soon as the type gets processed by Lombok, your annotation gets processed too.
If you have your own NonNull-annotation, then you can add just another Lombok-annotation that seems appropriate and Lombok adds a null-check for you, e.g.:
#Data
class NonNullData {
#mycustom.Nonnull
String value;
}
// Calling the following throws a NullPointerException as expected
new NonNullData(null);
You may also find the following issue relevant: Support annotations named #NotNull as well as #NonNull
I understand that annotations serve a purpose to modify code without actually BEING code, such as:
#Author(
name = "Benjamin Franklin",
date = "3/27/2003"
)
But I don't understand how using the annotation is any better/ clearer/ more concise than just saying name = "Benjamin Franklin" ? How does the addition of annotations strengthen the code?
EDIT: Sorry for another questoin, but I know that #Override can help prevent/ track spelling mistakes when calling methods or classes, but how does it do that? Does it help the actual program at all?
Annotations are just metadata. On their own they serve little to no purpose. There must be an annotation processor, either at the compiler or run time level that uses them for something.
With an annotation like
#Author(
name = "Benjamin Franklin",
date = "3/27/2003"
)
for example, some annotation processor might read it with reflection at run time and create some log file that this author wrote whatever it's annotating on that date.
Annotations are metadata.
#Override annotation is used to make sure that you are overriding method of a superclass and not just making a method with the same name. Common mistakes here consist of:
spelling the method's name wrong
equal(Object o) instead of equals(Object o)
putting different set of arguments
MyString extends String { public boolean equals(MyString str) {} }
equals(MyString str) is not overriding the method equals(Object o) and therefore will not be used by standard Java comparators (which is used in some standard functions, such as List.contains() and this is prone to error situation).
This annotation helps compiler to ensure that you code everything correctly and in this way it helps program.
#Deprecated annotation doesn't make program not to compile but it makes developers think about using the code that can and/or will be removed in a future releases. So they (developers) would think about moving onto another (updated) set of functions. And if you compile your program with the flag -Xlint compilation process will return with an error unless you remove all usages of deprecated code or explicitly mark them with annotation #SuppressWarnings("deprecation").
#SuppressWarnings is used to suppress warnings (yes, I know it's Captain Obvious style :)). There is a deprecation suppression with #SuppressWarnings("deprecation"), unsafe type casting with #SuppressWarnings("unchecked") and some others. This is helpfull when your project compiler have a compilation flag -Xlint and you cannot (or don't want to) change that.
There are also annotation processors that you integrate into your program build process to ensure that program code meets some sort of criteria. For example with IntelliJ Idea IDE annotation processor you can use #Nullable and #NotNull annotations. They show other programmers when they use your code so that can transfer null as a certain parameter to a method or not. If they transfer null it will cause exception during compilation or before executing a single line method's code.
So annotations are quite helpful if you use them to their full potential.
Annotations are most likely used by other programs. Examples include:
#Override
IDE (compiler?) ensures that the signatures match
#Deprecated
IDE marks occurences, compiler warning
#FXML
JavaFX can use these annotations initialize variables in a controller class when an .fxml File is inflated (see http://docs.oracle.com/javafx/2/get_started/fxml_tutorial.htm). They are also used by JavaFX Scene Builder.
Annotations works as a way to marking up the code. Several frameworks uses it, and some others make a great use of it producing your own.
Besides, is important to understand that annotations are the equivalent to meta-data, but is much more than that, since it works as a tag language for the code.
Java #Annotation
#Annotation(from Java 5) adds a metadata which are used for instruction in compile, deployment and run time. It is defined by RetentionPolicy
RetentionPolicy defines a lifetime
RetentionPolicy.SOURCE: It is visible only in compile time(#Override, #SuppressWarnings, #StringDef). For example it can be used by apt to generate some code
RetentionPolicy.CLASS: It is visible in compile and deployment time(.class). For example it can be used by ASM or Java AOP paradigm like AspectJ
RetentionPolicy.RUNTIME: It is visible in deployment and run time. For example it can be used java reflection using getAnnotations(). Dagger 2 uses #Scope annotation
Create a custom Annotation
#Retention(<retention_policy>) //optional
#Target(<element_type>) //optional to specify Java element like, field, method...
#Inherited // optional will be visible by subclass
#Documented // optional will be visible by JavaDoc
#interface MyAnnotation {
//attributes:
String someName();
}
using
#MyAnnotation(someName = "Alex")
public class SomeClass {
}
I have some questions about working of annotations in java.
If annotations cannot be converted to bytecode then where does this information go?
where does the meta-data goes?
How Java Reflection uses this information?
How compiler deals with annotations?
When we say,
#Override
public void doSomething(){
}
What does a java compiler do with it?
I know that it checks the method signature so that the method should be a perfectly overridden method, but how?
There are three types of annotations see http://download.oracle.com/javase/6/docs/api/java/lang/annotation/RetentionPolicy.html
#Override is a special case as the compiler does additional checks.
#Override is a source type annotation - used to check if a particular method follows the contract of an overriden method - hence it isn't available at runtime (and therefore logically doesn't exist in the compiled bytecode).
I know that it checks the method signature so that the method should be a perfectly overridden method, but how
In the process of reading the source files and converting them to bytecode, e.g., not using reflection at all. See The Java Programming Language Compiler - javac for additional compiler information.
Annotations have a RetentionPolicy, which specifies if the annotation will be stored in the class file (RetentionPolicy.CLASS, RetentionPolicy.RUNTIME) or will be discarded by the compiler (RetentionPolicy.SOURCE).
The #Override method has a RetentionPolicy of RetentionPolicy.SOURCE (meaning it is discarded by the compiler and not available at runtime via Reflection) and a target of ElementType.METHOD (meaning that this method can only be annotated on method declarations only).
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.SOURCE)
public #interface Override {
}
Only annotations with a RetentionPolicy of RetentionPolicy.RUNTIME can be read by Reflection.
At first, there were 2 kinds of annotations: Runtime accessible (2 kinds) and not runtime accessible. The behavior of annotation is done by retention policy through annotation of annotation declaration :-). Example:
#Retention(RetentionPolicy.RUNTIME) // effectively visible to JVM Runtime
public #interface MethodInfo {
String author() default "unspecified";
String lastModification() default "unspecified"; // Format: yyyy-mm-dd
ImplementationStatus implementationStatus();
}
JVM runtime visible annotations can be accessed through reflection during annotated code execution (or when it is loaded by the JVM). You utilize those annotations as metadata holders. Metadata can be processed by other code to do various things eg. to check annotated method implementation status before a given method is executed.
But someone must write code to use the annotation matedata through reflection! The best example is an application server (AS) that loads classes on demand from JAR files placed is some particular directory. AS can contain code that checks each loaded class for static methods annotated by the #Initialization annotation and executes those methods right away. This annotation type is defined by AS and those who create JARs and classes for AS use it during development.
Annotations that are not available during runtime are used and worked out during compilation. #Override is good example. Custom source only annotations can be used by compiler plugins or if code is compiled by other code on demand.
This one is simple. Compiler just checks the super class for method with same name and same number of parameters, their order and types. If method has #Override annotation and such method hasn't been found an error is generated.
More interesting question is how compiler deals with annotations which has mean at runtime. I assume they are added in byte-code but in some special section with meta information. So, in runtime jvm has access to the meta section. As a prove, you can always call getAnnotations() on any class object.
Compiled annotations (which are ultimately constant data) live the class file and can be accesses with the appropriate methods getAnnotations() and friends.