Creating Custom Java Compiler Errors Without Using Annotations - java

Is there a way to add processors to the compiler without making annotations?
Basically, I would like for the build to fail if a user did not implement an interface correctly (ie. postconditions are not fulfilled). At compile time, I would like to check if a class implements an interface, and if it does, run some code to check if the implementation is correct.
For example, I would like to ensure that classes that implement getErrorMoniker() return a string in camelCase.
public interface MyError {
public String getErrorMoniker();
}
public class MyErrorImplemented1 {
#Override
public String getErrorMoniker() { return "goodErrorMoniker"; }
}
public class MyErrorImplemented2 {
#Override
public String getErrorMoniker() {
return "BADERRORMONIKER"; // I would like a compile error here
}
}
Any suggestions would be appreciated.

A processor annotated with #SupportedAnnotationTypes("*") should in theory be able to processs all source files as it also applies to an empty set of annotations. From the documentation:
If there are no annotation types present, annotation processing still occurs but only universal processors which support processing "*" can claim the (empty) set of annotation types.
Although you goal to check for return values probably won't work, since this happens compile time, not runtime.

Related

Passing TYPE annotations to methods instead of marker interfaces

[ANSWER EDIT]: Short answer is that what I'm looking to do isn't possible. My question is a little misleading. I learnt that the Marker Interface pattern is actually what I called the Marked Annotations in my question (since the annotation you're creating is actually an interface). And checks on that can only be made at runtime. So if you're looking to make a compile time check with annotations well it's just not possible. An empty interface is the only option. Check answer to see how to do it at runtime.
I'm trying to avoid using marker interfaces in favor of marked annotations. Basically I want a bunch of classes be marked with this annotation, and pass instances of those classes to methods that accept that type. Here is my code:
MARKER ANNOTATION:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface Message {
}
CLASS:
#Message
public class MessageTypeA {
}
METHOD:
public class DatabaseWriter {
public void save(Message msg) {
//some code
}
}
CALLING CODE:
MessageTypeA msgA = new MessageTypeA();
DatabaseWriter writer = new DatabaseWriter();
writer.save(msgA);
However I get Error:(78, 23) java: incompatible types: MessageTypeA cannot be converted to Message
I'm not sure if what I'm doing is possible, but I read that marker interfaces can be replaced with marker annotations. Is it not possible in this case?
Thanks
The marker interface pattern is a way of adding metadata to your program types or obbjects that is readable in runtime.
See for example hibernate implementation of this pattern. Their insert method accepts a plain java.lang.Object, and is inside that method where the metadata from the various annotations is used.
So, following your example implementation, I'd go with something like this
public class DatabaseWriter {
public void save(Object msg) {
if (msg.getClass().isAnnotationPresent(Message.class)) {
//some code
}
}
}
In your example, MessageTypeA and Message are unrelated in the class hierarchy. A method call is legal only if the expression's type is a subtype of the formal parameter's type.
One way to establish a subtyping relationship is with an interface, as you already noted.
Another way to establish a subtyping relationship is with type qualifiers (expressed as type annotations).
TYPE QUALIFIER HIERARCHY:
#Message
|
#MessageTypeA
where #MessageTypeA is a subtype of #Message, and #Message means an unknown type of message. #Message is the default if no type annotation is written.
LIBRARY
public class DatabaseWriter {
public void save(Object msg) {
// some code that can run on any old message
}
public void saveA(#MessageTypeA Object msg) {
// some code that is specific to MessageTypeA
}
}
CLIENT
Object msg = ...;
#MessageTypeA Object msgA = ...;
DatabaseWriter writer = new DatabaseWriter();
writer.save(msg); // legal
writer.save(msgA); // legal
writer.saveA(msg); // compile-time error
writer.save(msgA); // legal
There is no run-time overhead or representation: the enforcement is done at compile time.
A tool that enables you to build pluggable type-checkers that enforce correct usage is the Checker Framework. (Disclaimer: I am a maintainer of the tool, but it is a regular part of the development toolchain at Amazon, Google, Uber, etc.)
You can define your own type system in a few lines of code. However, still consider using Java subtypes rather than type qualifiers.

How to append a method to existing class using annotation processing in java / kotlin?

I'm new to annotation processing and code generation. I want to find out how can I perform such operation like appending new method to existing class. Here is an example of what I want to do:
Assume that we have a class with with custom annotations like this one:
class SourceClass {
#CustomAnnotation
fun annotatedFun1(vararg argument: Any) {
//Do something
}
#CustomAnnotation
fun annotatedFun2(vararg argument: Any) {
//Do something
}
fun someOtherFun() {
//Do something
}
}
And the result I want to get - extended copy of that class:
class ResultClass {
fun hasFunWithName(name: String): Boolean {
return (name in arrayOf("annotatedFun1", "annotatedFun2"))
}
fun callFunByName(name: String, vararg arguments: Any) {
when (name) {
"annotatedFun1" -> annotatedFun1(*arguments)
"annotatedFun2" -> annotatedFun2(*arguments)
}
}
fun annotatedFun1(vararg argument: Any) {
//Do something
}
fun annotatedFun2(vararg argument: Any) {
//Do something
}
fun someOtherFun() {
//Do something
}
}
I've already found out how to create annotation processor. I'm looking for a method to save all existing fields, properties and methods in source class and to append a few more methods to it.
If it is possible to modify class without creating new one - it would be perfect, but in all tutorials only new classes are created and I didn't find any example where all contents of source class are being copied to another one.
Please, do not advise to use reflection. I need this for android and so reflection is not the option cause of resources cost. I'm looking for compile-time solution.
It is required for custom script language implemented in app and should be used to simplify wrapper classes structure. When this job is done directly in code - it looks awful when such method count exceeds 20 per class.
Here is a good example of Java Annotation Processing I recently worked with.
It's an implementation of #Immutable annotation.
Check out ByteBuddy or Kotlin Poet to understand how additional code generation works.
For Kotlin you do almost the same, check this manual for Kotlin-specific steps.
With Kotlin, you can use extension functions and that is the recommended way of adding new functionality to existing classes that you don't control. https://kotlinlang.org/docs/reference/extensions.html
You may be abel to follow the pattern used by Project Lombok. See How does lombok work? or the source code for details.
Another option would be to write a new class that extends your source class:
class ResultClass : SourceClass {
fun hasFunWithName(name: String): Boolean {
return (name in arrayOf("annotatedFun1", "annotatedFun2"))
}
fun callFunByName(name: String, vararg arguments: Any) {
when (name) {
"annotatedFun1" -> annotatedFun1(*arguments)
"annotatedFun2" -> annotatedFun2(*arguments)
}
}
}
Or perhaps use composition instead and implemnent cover methods for all the public methods in SourceClass.
If you are not tied to doing this using annotation processing, you could use a separate piece of custom code to process the source code files before compiling. Maybe use a regular expression like /#CustomAnnotation\s+.*fun (\w+)\s*\(([^)]*)\)/gm (Test on Regex101) to find the annotated methods.
If I understood the requirement correctly, the goal is to implement something like described below.
You have a source file C.java that defines the class C like this:
public final class C
{
#Getter
#Setter
private int m_IntValue;
#Getter
#Constructor
private final String m_Text;
}
And now you want to know how to write an annotation processor that jumps in during compilation and modifies the source from C.java that the compiler sees to something like this:
public final class C
{
private int m_IntValue;
public final int getIntValue() { return m_IntValue; }
public final void setIntValue( final int intValue ) { m_IntValue = intValue; }
private final String m_Text;
public final String getText() { return m_Text; }
public C( final String text ) { m_Text = text; }
}
The bad news is, that this is not possible … not with an annotation processor, not for Java 15.
For Java 8 there was a way, using some internal classes with reflection to convince the AP to manipulate the already loaded source code in some way and let the compiler compile it a second time. Unfortunately, it failed more often than it worked …
Currently, an annotation processor can only create a new (in the sense of additional) source file. So one solution could be to extend the class (of course, that would not work for the sample class C above, because the class itself is final and all the attributes are private …
So writing a pre-processor would be another solution; you do not have a file C.java on your hard drive, but one named C.myjava that will be used by that preprocessor to generate C.java, and that in turn is used by the compiler. But that is not done by an annotation processor, but it may be possible to abuse it in that way.
You can also play around with the byte code that was generated by the compiler and add the missing (or additional) functionality there. But that would be really far away from annotation processing …
As a summary: today (as of Java 15), an annotation processor does not allow the manipulation of existing source code (you cannot even exclude some source from being compiled); you can only generate additional source files with an annotation processor.

Understanding the use of 'Annotations'

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.

Play Framework annotation order

When I call fooMethod, I want to process first class annotation (with First.class - in my project this checks if user is logged) and then method annotation (with Second.class - in my project this checks if uses has desired rights to access this specific method. So I need to ensure user is logged first). Is there a way to do that?
#With(First.class)
public class Foo{
#With(Second.class)
public static void fooMethod(){
}
}
Also I wonder why custum action ignores annotation. Code below doesn't process anotation #With(First.class).
public class Foo2 extends Action<CustomAnnotation> {
#Override
#With(First.class)
public Promise<Result> call(Http.Context context) throws Throwable {
return delegate.call(context);
}
}
}
Similar unanswered question: Java + Play Framework 2 with nested action compositions in the same class
In Play 2.4 there appears to be an option for this from the docs here:
Note: If you want the action composition annotation(s) put on a
Controller class to be executed before the one(s) put on action
methods set play.http.actionComposition.controllerAnnotationsFirst =
true in application.conf. However, be aware that if you use a third
party module in your project it may rely on a certain execution order
of its annotations.
The note is only present in the 2.4 docs, so presumably it doesn't work in previous versions.
It looks like at least in Java 8 you have an order in annotation of the same kind: Java Annotations Reflection Ordering.

Create a Java Annotation with IDE contextual behaviour

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.

Categories

Resources