Annotation with multiple parameters with conditional default value - java

I'm creating a custom annotation named #Skip as shown below.
#Retention (RetentionPolicy.RUNTIME)
#Target ({ElementType.TYPE, ElementType.METHOD})
#Inherited
public #interface Skip {
public String comment() default "";
public String bug() default "";
}
Is it possible to set conditional default value on the comment and bug? What I'm trying to achieve is, if comment is provided, bug must be optional, if bug is provided comment is optional. I can do this check at run-time, but I want to find out if we can do it at compile time. This way, eclipse will show a compilation error if at least one of these is not provided by the developer.

You could check these things at compilation time using an annotation processor.
Have a look at the Javadoc for a starting point.
If you package the processor in the same jar as the annotation and register the processor as a service, it will be exucted automagically when compiling an annotated class (must be in a different jar).

Related

How can I make annotations more semantic?

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

How can I specify the type of the field that an Annotation should be applied to in Java?

I'm creating a simple annotation, to help me inflating settings inside my Android application. The annotation is this:
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface CoreSettings {
String name() default "";
}
I want to ensure it will only be used in fields which type extends a custom class named BaseSettings. In the example below, MainSettings extends the abstract class BaseSettings.
public class MainActivity extends BaseActivity {
#CoreSettings("prefs")
MainSettings settings;
(...)
}
How can I do it?
Yes, you can cause the compiler to issue an error message if you write the annotation on a field of the wrong type.
You cannot do this using just the #Target meta-annotation. In addition, you need to write an annotation processor. The annotation processor will examine each occurrence of the annotation #CoreSettings in your source code, and it issues an error (just like any other compiler error) if #CoreSettings is applied to a type that does not extend BaseSettings. This is a short, simple annotation processor to write.
You will only get the compile-time warning when running the annotation processor, but you can add the -processor ... command-line argument to javac in your project's buildfile.

How to get custom annotation from source code in java?

I'm trying to use a custom annotation to get some statistics for unit test. Another guy has defined a custom annotation as follows:
#Retention(RetentionPolicy.SOURCE)
#Target( { ElementType.METHOD, ElementType.TYPE})
public #interface TimsID {
String id();
String description() default "";
}
What I need to do is extracting this annotation from all unit tests in our project.
Here comes the problem:
the RetentionPolicy is defined as SOURCE, I don't know how to get it in the unit test.
I know that if it's a RUNTIME, it may be read reflectively like this:
Class<TestExample> obj = TestExample.class;
// Process #TimsID
if (obj.isAnnotationPresent(TimsID.class)) {
Annotation annotation = obj.getAnnotation(TimsID.class);
TimsID TimsID = (TimsID) annotation;
}
But now it's 'SOURCE', annotations will not be recorded in the class file by the compiler or retained by the VM at run time, so they can't be read reflectively.
The guy who defined the custom annotation said the reason he chooses "SOURCE" is that we just need to statistic this annotation in source code, we don't need to write these custom annotations in class file or even runtime, so we need annotation analysis only in source code.
I've accomplished this work, and here is the step and code.
SOURCE retention is aimed to be used only during compilation process. You may look into APT (Annotation Processing Tool) for more information on how to perform such kind of compile-time annotation processing logic. (However I wonder if it can do what you want)
You'll have to change the RetentionPolicy in the source code, unfortunately. There's no other way to make the annotation available for reflection at runtime, even in tests.

Spring AOP: get access to argument names

I'm using Spring 3.x, Java 6.
I have an #Around aspect with the following joinpoint:
#Around("execution(public * my.service.*.*Connector.*(..))")
So, I'm basically interested in intercepting all calls to public methods of classes with the class name ending with "Connector". So far so good.
Now, in my aspect I would like to access the actual argument names of the methods:
public doStuff(String myarg, Long anotherArg)
myarg and anotherArg
I understand that using:
CodeSignature signature = (CodeSignature)jointPoint.getSignature();
return signature.getParameterNames();
will actually work but only if I compile the code with the "-g" flag (full debug) and I would rather not do it.
Is there any other way to get access to that kind of runtime information.
Thanks
L
Unfortunately you can't do this :-(. It is a well known limitation of JVM/bytecode - argument names can't be obtained using reflection, as they are not always stored in bytecode (in the contrary to method/class names).
As a workaround several frameworks/specification introduce custom annotations over arguments like WebParam (name property) or PathParam.
For the time being all you can get without annotations is an array of values.
Check the implementations of org.springframework.core.ParameterNameDiscoverer.
Annotations like #RequestParam used by spring inspect the parameter name if no value is set. So #RequestParam String foo will in fact fetch the request parameter named "foo". It uses the ParameterNameDiscoverer mechanism. I'm just not sure which of the implementations are used, by try each of them.
The LocalVariableTableParameterNameDiscoverer reads the .class and uses asm to inspect the names.
So, it is possible. But make sure to cache this information (for example - store a parameter name in a map, with key = class+method+parameter index).
But, as it is noted in the docs, you need the debug information. From the docs of #PathVariable:
The matching of method parameter names to URI Template variable names can only be done if your code is compiled with debugging enabled. If you do not have debugging enabled, you must specify the name of the URI Template variable name in the #PathVariable annotation in order to bind the resolved value of the variable name to a method parameter
So, if you really don't want to include that information, Tomasz Nurkiewicz's answer explains the workaround.
In Java 8 there is a new compiler flag that allows additional metadata to be stored with byte code and these parameter names can be extracted using the Parameter object in reflection. See JDK 8 spec. In newer versions of hibernate org.springframework.core.ParameterNameDiscoverer uses this feature. To use it compile using javac with this flag:
-parameters Generate metadata for reflection on method parameters
Access parameters using reflection's Parameter class.
I am not sure if its a best way, but I added a Annotation on my method:
My Annotation:
#Retention (RetentionPolicy.RUNTIME)
#Target (ElementType.METHOD)
public #interface ReadApi
{
String[] paramNames() default "";
}
#ReadApi (paramNames={"name","id","phone"})
public Address findCustomerInfo(String name, String id, String phone)
{ ..... }
And in the Aspect:
#Around("aspect param && #annotation(readApi)")
public Object logParams(ProceedingJoinPoint pjp,
ReadApi readApi)
{
//use pjp.getArgs() and readApi.paramNames();
}
This is probably a hack but i did not want to compile with more options to get information. Anyways, its working well for me. Only downside is that i need to keep the names in annotation and method in sync.

annotation = comment?

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.

Categories

Resources