How do I force a Java subclass to define an Annotation? - java

If a class defined an annotation, is it somehow possible to force its subclass to define the same annotation?
For instance, we have a simple class/subclass pair that share the #Author #interface.
What I'd like to do is force each further subclass to define the same #Author annotation, preventing a RuntimeException somewhere down the road.
TestClass.java:
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
#interface Author { String name(); }
#Author( name = "foo" )
public abstract class TestClass
{
public static String getInfo( Class<? extends TestClass> c )
{
return c.getAnnotation( Author.class ).name();
}
public static void main( String[] args )
{
System.out.println( "The test class was written by "
+ getInfo( TestClass.class ) );
System.out.println( "The test subclass was written by "
+ getInfo( TestSubClass.class ) );
}
}
TestSubClass.java:
#Author( name = "bar" )
public abstract class TestSubClass extends TestClass {}
I know I can enumerate all annotations at runtime and check for the missing #Author, but I'd really like to do this at compile time, if possible.

You can do that with JSR 269, at compile time.
See : http://today.java.net/pub/a/today/2006/06/29/validate-java-ee-annotations-with-annotation-processors.html#pluggable-annotation-processing-api
Edit 2020-09-20: Link is dead, archived version here : https://web.archive.org/web/20150516080739/http://today.java.net/pub/a/today/2006/06/29/validate-java-ee-annotations-with-annotation-processors.html

I am quite sure that this is impossible to do at compile time.
However, this is an obvious task for a "unit"-test. If you have conventions like this that you would like enforced, but which can be difficult or impossible to check with the compiler, "unit"-tests are a simple way to check them.
Another possibility is to implement a custom rule in a static analyzer. There are many options here, too.
(I put unit in scare-quotes, since this is really a test of conventions, rather than of a specific unit. But it should run together with your unit-tests).

You could make an Annotation (e.g. #EnforceAuthor) with #Inherited on the superclass and use compiler annotations (since Java 1.6) to catch up at compile time. Then you have a reference to the subclass and can check if another Annotation (e.g. #Author)) is missing. This would allow to cancel compiling with an error message.

Related

Java - Why is RetentionPolicy.CLASS the default

In the javadoc for java.lang.annotation.RetentionPolicy it says that:
SOURCE: Annotations are to be discarded by the compiler.
CLASS: 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.
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.
I understand, that RUNTIME is used to access it using the reflection API, SOURCE for compiler related information (and maybe documentation) and CLASS, as far as I could find out, for special cases, like bytecode manipulation tools, etc. and also compiler related stuff, like #FunctionInterface.
But why is CLASS the default? I expect most annotations to be annotated with RUNTIME, because I think, that most programmers use annotations to specify metadata, that should be read through the reflection API at runtime, because the average programmer doesn't play around with the generated bytecode (at least I've never done it).
So why is RUNTIME not the default? Is there any use case for CLASS, that at I'm not aware of? Or is this just another case of this decision was made long ago, for now unknown or irrelevant reasons and can't be changed, because that would break stuff.
At least for beginners, it may be very confusing and can lead to bugs, that the code
package test;
import java.lang.annotation.Annotation;
import test.Test.Example;
#Example("example")
public class Test {
public static void main(String[] args) {
Annotation[] annotations = Test.class.getAnnotations();
if (annotations.length == 0) {
System.out.println("Class Test has no annotations");
} else {
System.out.println("Class Test has the following annotations:");
for (Annotation annotation : annotations) {
System.out.println("\t" + annotation.toString());
}
}
}
// #Retention(RetentionPolicy.RUNTIME)
public static #interface Example {
public String value();
}
}
outputs "Class Test has no annotations" without the #Retention meta annotation.

How to verify that an annotation is only used on certain classes?

Say I have an annotation #Annotate and a class A. How can I check whether #Annotate is used on class A and its subclasses only (probably at compile time)?
So, if we have:
/* Example 1 */
public class A {
}
public class B extends A {
}
public class C {
}
How do I check that class A and class B can be annotated by #Annotate but class C is not allowed (and might raise a compile error).
If we go with the decision that this would be checked at compile time:
/* Example 2 */
public class A {
}
#Annotate
public class B extends A {
}
Example 2 will not raise a compile time error because #Annotate is used on a subclass of A. Example 3, however, will raise an compile error because #Annotate is not used on a subclass of A.
/* Example 3 */
#Annotate
public class C {
}
However, this does not have to be checked at compile time in anyway. I just personally thought that it makes sense to do so.
You should write an annotation processor. An annotation processor can generate new Java files and, more relevantly for your case, issue compile-time warnings.
You will invoke it at compile time by running the java compiler like this: javac -processor MyProcessor MyFile.java. If regular javac or your annotation processor issues any warnings, then compilation fails.
Your annotation processor's logic is specific to your #Annotate annotation and is simple: permit the annotation only on classes that subclass A. There are various tutorials on the web about how to write an annetation processor, in addition to the Oracle documentation I linked above.
You can use my checker-framework.
Just Simply add annotation #CheckType on your annotation
#Target(TYPE)
#CheckType(value = A.class, type = Type.EXTEND_ALL)
public #interface OnlyOnA {
}
Now it can check if it is annotated on A or its subclass.
It will raise a compile error
eclipse snapshot
maven snapshot

Grails: can't have an abstract method in a non-abstract class ERROR

Grails version: 2.3.4
Java version: 1.7.0_79
I was developing an uploader to AWS S3, from a demo, in a standalone app which was in the latest version of Grails. It is working and I've now been trying to implement it into my older Grails main app.
I'm coming into an error on server start with regards to this line of code:
import grails.validation.Validateable
import org.springframework.web.multipart.MultipartFile
abstract class FeaturedImageCommand implements Validateable {
MultipartFile featuredImageFile
Long id
Long eventId
Integer version
static constraints = {
id nullable: false
version nullable: false
eventId nullable:false
featuredImageFile validator: { val, obj ->
if ( val == null ) {
return false
}
if ( val.empty ) {
return false
}
['jpeg', 'jpg', 'png'].any { extension -> // <1>
val.originalFilename?.toLowerCase()?.endsWith(extension)
}
}
}
}
The error reads:
Can't have an abstract method in a non-anstract class. The class 'FeaturedImageCommand' must be declared abstract or the method 'java.lang.Class.annotationType()' must be implemented.
I'm assuming my java and grails versions are causing this, but I'm really hoping there is a way around this without updating them?
Thank you.
Well Validateable is an annotation type, and the annotationType() method comes from the Annotation interface, which all #interface types implicitly inherit.
(Your code is ... odd. Why would you want to "implement" an annotation as a class? My understanding is that you won't be able to use a class defined as subclass of an #interface as an annotation ...)
If you are trying to declare annotations with a type hierarchy, that is not permitted by the Java syntax. (The JLS says this explicitly.)
If you (really) want a class that implements an #interface then you will need to implement that method. (And I have no idea how you got away with not doing this previously. Validateable is an #interface in all versions that I can see on the Grepcode site.)

instantiating a Scala class using reflection Java's `newInstance`

For some special use-case I have a small utility to load Java classes from jars using a dynamic class loader DynamicClassLoader. This works fine for Java classes contained in jars. Loading Scala classes from a jar also works without problems. However, instantiating the loaded Scala class leads to the following exception. It looks like the Scala class has private default constructor? Note the compiled Scala class name ending with $
java.lang.IllegalAccessException: Class XXX can not access a member of class ScalaClassYYY$ with modifiers "private"
The snippet below illustrates the idea of what I'm trying to achieve and gives a bit more context. The exception happens at the annotated line:
// deploy and register the new code
byte[] jarBytes = (byte[]) ((Object) message.getAttachment("jar"));
String registerClassName = message.getAttachment("register");
logger.debug("the register is '" + registerClassName + "'");
DynamicClassLoader loader = new DynamicClassLoader(jarBytes);
Class<?> registerClass = loader.lookUp(registerClassName);
// ===> this is where the java.lang.IllegalAccessException happens
IRegisterExecutor registerExecutor = (IRegisterExecutor) registerClass.newInstance();
registerExecutor.register();
Any ideas how to fix?
Obviously, you need to make the default constructor public (it won't work for Java classes without a public default constructor either). E.g.
class ScalaClassYYY() {
...
}
or if you want primary constructor to take some arguments,
class ScalaClassYYY(arg1: Int) {
def this() = this(0)
}
But from
Note the compiled Scala class name ending with $
it seems like you are actually trying to instantiate a Scala object:
object ScalaClassYYY { ... }
In this case, you shouldn't create a new instance and instead use the existing one:
(IRegisterExecutor) registerClass.getField("MODULE$").get(null);
EDIT:
I don't see in your answer how you add a default public constructor to a Scala class that does NOT require any parameters.
A class (not an object) that doesn't require any parameters has a default public constructor already (my first example).
Actually in Java all classes by default offer a public default constructor
No. Only those classes which have no constructors which take arguments.
remove the "(it won't work for Java classes without a public default constructor either)" because it is wrong
The documentation for Class.newInstance() says
IllegalAccessException - if the class or its nullary constructor is not accessible.
So I am pretty sure it's right. If it does work for Java classes without a public default constructor, this seems to be a major bug in the class loader you use. You can test it with a Java class which looks like this:
public class TestClass implements IRegisterExecutor {
public TestClass(int dummy) {}
// some implementation for IRegisterExecutor methods to get it to compile
}

Understanding annotation in Java

I was trying to go through some online material to learn annotation in java.
In the following code, what happened to my dear "Hello world" string which I passed in this line: #Test_Target(doTestTarget="Hello World !")?
#Target(ElementType.METHOD)
public #interface Test_Target {
public String doTestTarget();
}
above is the annotation defined and below is its usage
public class TestAnnotations {
#Test_Target(doTestTarget="Hello World !")
private String str;
public static void main(String arg[]) {
new TestAnnotations().doTestTarget();
}
public void doTestTarget() {
System.out.printf("Testing Target annotation");
}
}
When I run this code it is only printing Testing Target annotation
Please help me out, I am completely new to annotation.
Annotations are basically bits of data you can attach to fields, methods, classes, etc.
The syntax for declaring annotations in Java is a little awkward. They look a bit like interfaces (they are, after all, declared with #interface), but they aren't really interfaces. I think you might have put the doTestTarget() method in your TestAnnotations class because you thought your annotation was an interface and you needed to implement it. This isn't true - you can delete this method and the call to it from your code if you wish and doing so won't cause you any problems.
Also, you might not have intended to put the annotation on the field str. Annotations apply only to what immediately follows them. As a result, your code doesn't compile, because you've applied your annotation to a field but declared that your annotation can only be applied to methods. Change #Target(ElementType.METHOD) to #Target(ElementType.FIELD) and your code should then compile.
As for what happens to the string Hello World !, it gets written to the .class file and is available to any tool that reads in Java classes. However, it wouldn't necessarily be available in the JVM at runtime. This happens because you didn't specify a #Retention for your #Test_Target annotation. The default value for #Retention is RetentionPolicy.CLASS, which means that the JVM might not bother to load them out of the class file. (See the Javadoc for the RetentionPolicy enum.)
I imagine you want to see some way of reading the value out of this annotation at runtime. If so, I'd recommend adding #Retention(RetentionPolicy.RUNTIME) to your annotation to make sure it will be available at runtime.
To access your annotation and the value contained within it at runtime, you need to use reflection. I've rewritten your TestAnnotations class as follows to give a quick demonstration:
import java.lang.reflect.Field;
public class TestAnnotations {
#Test_Target(doTestTarget="Hello World !")
private String str;
public static void main(String[] args) throws Exception {
// We need to use getDeclaredField here since the field is private.
Field field = TestAnnotations.class.getDeclaredField("str");
Test_Target ann = field.getAnnotation(Test_Target.class);
if (ann != null) {
System.out.println(ann.doTestTarget());
}
}
}
When I run this code, it gives me the following output:
Hello World !
In principle, adding an annotation by itself does not fundamentally alter the programs behaviour.
In your case, you created a new annotation type #Test_Target, which can by used on any method (as indicated by its #Target annotation).
Then you applied this not to a method, but to the str field (which should give a compiler error, I think).
Independently of this, you are creating an object with a doTestTarget method, and invoke it, and get the expected result (i.e. the method is executed).
If you want your annotation to do something more than simply be there and provide some information for the reader of the source, you have to use it - either with an annotation processor at compile time, or using reflection on run time (then you would need also #Retention(RUNTIME) as an annotation on Test_Target.)
In the spirit of learning, another way is to use the annotated class without targeting a method or field.
First declare your interface with the method you need and Retention Policy to Runtime
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
public #interface Test_Target {
public String doTestTarget() default "default string";
}
then annotate the interface created to your class. From your class find the annotated class and then call the method with it.
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
#Test_Target(doTestTarget="Hello World !")
public class TestAnnotations {
public static void main(String[] args) throws Exception
{
AnnotatedElement c = TestAnnotations.class;
if(c.isAnnotationPresent(Test_Target.class))
{
Annotation singleAnnotation = c.getAnnotation(Test_Target.class);
Test_Target tt = (Test_Target) singleAnnotation;
System.out.println(tt.doTestTarget());
}
}
}
the result is:
Hello World !

Categories