I have written an annotation:
#Documented
#Retention(RUNTIME)
#Target(TYPE)
/**
* #author christian
*
*/
public #interface HeraklesObject {
}
I use it in an osgi environment (eclipse oxygen with tycho) in a bundle.
In another bundle (a test fragment to be specific) i check classes from the first bundle for this annotation, using:
class.getAnnotation(HeraklesObject.class)
I am sure, that the queried class has this annotation, but I get always null result.
The retention policy seems right to me, but I am not sure if a class loader issue is present and I don't know how I check this. Or do you see another cause? Thanks
Christian
Try to use
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.TYPE })
Also from How to get class annotation in java?
use
Class newClass = X.class;
for (Annotation annotation : newClass.getDeclaredAnnotations()) {
System.out.println(annotation.toString());
}
Does the bundle with the class whose runtime annotations you want to check contain or import the package with the HeraklesObject annotation class?
A class loader will load a class and, if the class of a runtime annotation class is not visible, just ignore the annotation. So you end up with a silent "failure". So check to make sure the package holding the runtime annotation is visible to the bundle holding the annotated class.
If you use Bnd to build the bundle, it should properly import the runtime annotation's package.
Related
We have feature files that have long tests that validate multiple things written in non-english language, the Given -> When -> Then structure doesn't make sense.
I tried replacing feature file keywords with *, and that works just fine, however here are the problems:
When writing a new step in a form of * Some step, and using Alt->Enter shortcut to generate a step definition, IntelliJ IDEA does... Nothing. It only opens the file where I wanted to put the definition without any added code. I've updated IDE and plugins to be latest.
There doesn't seem to be any way to have a "universal" annotation to use for asterisk steps, only Given, When, Then, And, But exists. It's not very logical to have a * Some step feature and #Given("Some step") definition.
Is there any workaround that I might use?
I think you can achieve this with few coding steps.
Say you have the scenario like this:
Feature: Generic annotation
Scenario: Testing annotations
* having asterix
* use custom generic annotation
Add custom annotation to your sources
package click.webelement.cucumber;
import io.cucumber.java.StepDefinitionAnnotation;
import io.cucumber.java.StepDefinitionAnnotations;
import org.apiguardian.api.API;
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#StepDefinitionAnnotation
#Documented
#Repeatable(MyStep.MySteps.class)
#API(status = API.Status.STABLE)
public #interface MyStep {
String value();
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#StepDefinitionAnnotations
#Documented
#interface MySteps {
MyStep[] value();
}
}
Now use it in your Step Definition
package click.webelement.cucumber;
public class StepDef {
#MyStep("having asterix")
public void doOne(){
System.out.println("Running having asterix");
}
#MyStep("use custom generic annotation")
public void doTwo(){
System.out.println("Running use custom generic annotation");
}
}
UPD
In order to make your Idea plugin work with your custom annotation you need to place that annotation to
io.cucumber.java.LANG package where LANG is the sub-package for your chosen language.
To make everything work as default you place it to
io.cucumber.java.en
I am a newbie to annotations. I have gone through a lot of tutorials explaining the concept of annotations. But nowhere do i find information about defining multiple annotations within a class. So pls give me some insight on defining and accessing multiple annotations.Below is the code where I define two annotations in a class and eclipse IDE presents me an error "The public type SampleAnn must be defined in its own file".. Is the reason for this error because of the java convention that "there should only one public annotation per class in the name of the class-name"?
#Documented
#Target(ElementType.LOCAL_VARIABLE)
#Inherited
#Retention(RetentionPolicy.RUNTIME)
public #interface MethodInfo{
int number1;
}
#Documented
#Target(ElementType.LOCAL_VARIABLE)
#Retention(RetentionPolicy.RUNTIME)
public #interface SampleAnn{
int number2;
}
You are right, you can have only a single top-level class in one file.
But what you can do:
public class MyAnnotations {
public #interface SampleAnn { ... }
public #interface MethodInfo { ... }
}
There should more generally be ONE public CLASS per class file and annotations are no exception. It is also important that any publicly defined entity has the same name as its java file's name, so I don't see how you could have two in the same file.
The annotations need to be in separate compilation units (files).
The regarding top-level classes the specification states:
This restriction implies that there must be at most one such type per
compilation unit. This restriction makes it easy for a Java compiler
to find a named class within a package. In practice, many programmers
choose to put each class or interface type in its own compilation
unit, whether or not it is public or is referred to by code in other
compilation units.
Specification
I have created my own annotation type like this:
public #interface NewAnnotationType {}
and attached it to a class:
#NewAnnotationType
public class NewClass {
public void DoSomething() {}
}
and I tried to get the class annotation via reflection like this :
Class newClass = NewClass.class;
for (Annotation annotation : newClass.getDeclaredAnnotations()) {
System.out.println(annotation.toString());
}
but it's not printing anything. What am I doing wrong?
The default retention policy is RetentionPolicy.CLASS which means that, by default, annotation information is not retained at runtime:
Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. This is the default behavior.
Instead, use RetentionPolicy.RUNTIME:
Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.
...which you specify using the #Retention meta-annotation:
#Retention(RetentionPolicy.RUNTIME)
public #interface NewAnnotationType {
}
Having the default Retention of an annotation does not mean that you can not read it at run-time.
Since
Annotations are to be recorded in the class file by the compiler
but need not be retained by the VM at run time. This is the default behavior.
It is possible to access them reading the .class file directly
This can be accomplished by using the ASM library (handling some corner cases, of course).
Check out its excellent User guide. In particular section 4.2 Annotations.
You may want to refer to the Spring framework's handling of such annotations (it uses shaded asm dependency):
SimpleAnnotationMetadataReadingVisitor
AnnotationMetadataReadingVisitor (deprecated)
My application allows developers to create some plugins. Сompliance with the requirements determined by base abstract class. Each plugin must have a name. I want to solve this problem by using annotations. So, I defined my own annotation Name as follows:
#Retention(RetentionPolicy.RUNTIME)
public #interface Name {
public String value();
}
I put this annotaion and base abstract class CommonPlugin into separate module and build it as JAR-file to share with developers.
Then I import package and put this annotation before the defenition of me test plugin as follows:
#Name("Test plugin")
public class TestPlugin extends CommonPlugin {
Then I reflect all given plugins through URLClassLoader and can't find necessary annotation at TestPlugin class. But if I define Name annotation into the same package the TestPlugin class is, I can find it. It should be so or am I doing something wrong?
Turning my coment into an answer so it can be accepted.
Make sure that the unqualified name Name refers to the same qualified name in all of your source files. In sources from different packages than the one containing the annotation, there should be a non-wildcard import for Name, and there should be no class with that name in that other package itself.
If a class is annotated with an annotation, does the definition of that annotation have to be in the runtime classpath in order to use the class? For example, given the annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface Component {}
can I execute the program
#Component
public class Test {
public static void main(String[] args) {
System.out.println("It worked!");
}
}
without having Component.class in the classpath? (In my test I could, but is this behavior defined by the spec?)
I ask because there are conflicting claims whether using an annotation from a library creates a dependency on that library.
Runtime annotations are meta information to be processed by annotation processor at the runtime. If there is an access to annotation at runtime, you definitely add annotations in the classpath. For example junit definitely need the annotations in the class path determine test methods.
If there is no processing of annotation is done, there is no need to have it the classpath.
Yes you can execute program without having Component.class in the classpath. More details here: Why doesn't a missing annotation cause a ClassNotFoundException at runtime?