Does anyone know of an annotation in any framework or library (or IntelliJ or IntelliJ plugin) that can enforce in my code that only specific methods described in the annotation can call it?
example
#caller(class="UsefulClass")
public static void myMethodToBeCalledOnlyByUsefulClass() {
}
The Checker Framework allows you to define annotations such as #Caller and then have the compiler statically enforce programming rules. You could use the Checker Framework to define your #Caller annotation and a compiler plugin. Then, every time you compile your code using the plugin, it will issue an error if the code is used improperly.
The Checker Framework ships with a number of annotations already built in, but not #Caller which you would have to define yourself.
Related
My goal is to learn on how to create annotation. So, I use the project lombok's #Getter annotation for practice. However, one thing bothers me is that the IntelliJ IDEA throws warning of Cannot resolve method 'getId' in 'Product'. Please note, compiling is not a problem.
What I did:
Enable annotation processing in the Settings.
My expected result: The IDE knows that getId method will be injected at compile-time.
My actual result: The IDE throws warning.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
public static Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
Product product = new Product();
logger.debug(Integer.toString(product.getId()));
}
}
import lombok.Getter;
public class Product {
#Getter
private int id = 10;
}
PS: I heard it needs Lombok plugin to be installed. Is there a way to do it without plugin? I need it to implement it in my own annotation.
Lombok isn't an annotation processor. Lombok is a unique bit of software, and (as one of the core authors), what lombok does is not trivial in the slightest: You'd have to fork the lombok code base if you want to do lombok-esque things.
Looking at lombok as an example of what annotations can do is in that sense not a good idea: Lombok is its own thing, and merely uses annotations to know where to act, it is not a processor (but, weirdly enough, it registers itself as one in order to become part of the compilation process).
To answer your direct questions:
Yes, you need the lombok plugin installed; recent versions of intellij have it installed by default if memory serves.
No, lombok cannot be made to work without that.
However, an actual normal annotation processor would work just fine.
Basic (non-lombok) annotation processors can only make new files - they cannot change existing files. Only lombok can do that (and it requires a plugin). If you write a basic annotation processor (which therefore can only make new files), what you've done (turn on 'annotation processing') is all that is needed.
Note that basic annotation processors tend to need to go through a full build and have issues with incremental compilation (as in, incrementally compiling tools generally just compile everything, every time, if annotation processors are loaded. Most tools know lombok isn't an annotation processor / works just fine in incremental compilation scenarios and know not to fall back to 'compile all the things all the time'). For medium to large project, 'compile everything' is a gigantic time waster which you want to avoid.
Next steps for you:
Consider if the changes you want to make can be done solely by making new files. If the answer is No, I must change existing files, give up. Or, fork lombok and spend half a year figuring out the inner workings of javac, ecj, and intellij :/
If you CAN do the job by making only new files, know that the experience won't be as smooth and speedy as what lombok does. Forget lombok as an example, it's not a normal annotation processor. Find any tutorial on annotation processing / read up on the APIs / have a look at the source of a project such as AutoValue for an example of how a 'normal' annotation processor works. Know that you can do what you want, and all it takes is what you already did: Enable that 'run processors' checkbox.
As noted in the #rzwitserloot answer,
do not use Lombok as a means to learn annotations.
Instead,
read an annotation tutorial.
Here are some links:
Oracle's Annotation Tutorial
Wikipedia's Annotation Page
Baeldung's Custom Annotation Article
I was browsing the source code of the Lombok project, as I'm learning about Annotations and AOP in general and I thought that would be a good example to draw inspiration from.
However, I don't understand, the AllArgsConstructor only defines the annotation - that part I get from what I grasped so far - but where is the code that actually adds the constructor ? And all other annotations.
Let me first note that if you want to learn about annotation processing, Lombok is not a good example to start with. Lombok is not a regular annotation processor (which only adds new source files to the compilation). Instead, it modifies existing Java sources. That is not what annotation processors typically do, and it's not something the annotation processing in javac was designed for. Lombok uses the API of javac to modify and enrich an abstract syntax tree. That makes it complex and difficult to understand.
To answer your question, the logic that generates the code for Lombok annotations is located in so-called handlers. In your case, it's the HandleConstructor classes (there are two of them: one for javac, one for the Eclipse compiler).
Is there a way to perform (more or less) "automatic" JSR-303 java bean validation without runtime modification of a class?
Usually I see people using AspectJ to accomplish this, but we have had so many complications when using runtime code weaving (like with cofoja) that I'd like to avoid it. It makes a lot of our build tools fail because the runtime class files were different than the class files on disk.
I've looked at dynamic proxies via reflection which can only proxy interfaces (public methods) AND if you call anything annotated inside "this", you don't go through the proxy anymore so you lose that validation.
I'v also looked at ByteBuddy for a way to possibly intercept method calls by wrapping/redefining a class. There might be something here but I can't figure out how to intercept private methods or accomplish the above without getting back into modifying the original class.
Any ideas?
In theory, you can enforce bean validation by reflection only. But I assume that by automatic, you mean without an explicit call to a validation method.
In this case, instrumentation is probably your only option. With Byte Buddy, you can instrument existing methods, by using redefinition or rebasing. The easiest way to do so is a Java agent using an agent builder or using the Gradle or Maven plugins for build time instrumentation. The documentation provides an example of how to implement an agent and the build instrumentations have a lot of javadoc (documentation in progress).
I am currently a bit annoyed with my IDE, which is complaining about unused methods. These methods are used predominantly by Camel or Spring and not all covered by Unit Tests. I would like to annotate those methods to let my IDE know that they are unused for a reason.
Which annotation is most suitable for this purpose?
Have you tried #SuppressWarnings("unused") ?
Is it possible to create a preprocessor like functionality that is available in C and provided by Antenna. Can we use the APT tool to achieve this functionality? Are there any articles or links on similar topics?
Annotations are not meant as a tool to transform code; they just add metadata to code. You can't use annotations for conditional compilation, for example.
As Sun's tutorial on annotations says:
Annotations provide data about a program that is not part of the program itself. They have no direct effect on the operation of the code they annotate.
Wikipedia says:
When Java source code is compiled, annotations can be processed by compiler plug-ins called annotation processors. Processors can produce informational messages or create additional Java source files or resources, which in turn may be compiled and processed, but processors cannot modify the annotated code itself.
So an annotation processor plug-in is not going to be able to give you all of the functionality that the C preprocessor has.
You can perform compile-time tasks using the annotation processing framework. It's not as powerful as a preprocessor, since you can't do things like:
#RunOnlyOn(OS.Mac) public void someMethod() { ... }
Some good use cases for annotation processors are:
creating mapping files from annotated classes, e.g. create a hibernate mapping file;
creating indexes of classes which have certain annotation, e.g. create testng xml files from a source folder of test classes;
enforce compile-time constraints not usually available, e.g. having a no-arg constructor.
Please note that as of Java 6 APT is no longer needed, since all properly declared annotation processors take part in the compilation.