Java annotation putting parameter constraint on a method in netbeans - java

As you all know, with reflection you are able to check if an annotated method has the required parameters. Is it possible to set something up so that, in my IDE (Netbeans) it validates wether said annotated method has the required parameters and would highlight it as an error or warning should the method not meet the requirements of the annotation?
Example:
#Manifest (decoder = GameDecoder.class, opcode = 12, size = 0)
public class PingRequest {
#Incoming
public void receive(ChannelHandlerContext ctx, ByteBuf buf) {
}
#Outgoing
public void prepare(ByteBuf bb) {
}
}
Those two methods NEED to have the specified parameters, however you can type the methods without those parameters and Netbeans will as expected not say anything because it's not wrong however during runtime they wouldn't get used because they don't have the required parameters.
I did it like this so that my networking is completely POJO but if Netbeans cannot tell me the required parameters in such annotated methods then I might use an interface or something to specify a "contract" that states those methods NEED to have those parameters.

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.

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.

Map a collection with parameter with mapstruct

To map a certain object with mapstruct I need some custom post processing which needs an additional parameter to do it's work:
#Mapper
public abstract class AlertConfigActionMapper {
#Mappings({ #Mapping(target = "label", ignore = true)})
public abstract AlertConfigActionTO map (AlertConfigAction action, Locale userLanguage);
#AfterMapping
public void setLabel (AlertConfigAction action, #MappingTarget AlertConfigActionTO to, Locale userLanguage) {
for (AlertConfigActionLabel label : action.getAlertConfigActionLabels()) {
if (label.getLanguage().equals(userLanguage)) {
to.setLabel(label.getLabel());
break;
} else if (label.getLanguage().equals(Locale.ENGLISH)) {
to.setLabel(label.getLabel());
}
}
}
}
This works just fine.
The problem starts when I add following method to this mapper:
public abstract ArrayList<AlertConfigActionTO> mapList (List<AlertConfigAction> actions, Locale userLanguage);
I need to pass this parameter (userLanguage) as well but mapstruct seems to 'break down' in this case: I generates following code for this part (which naturally gives a compilation error):
#Override
public List<AlertConfigActionTO> mapList(List<AlertConfigAction> actions, Locale userLanguage) {
if ( actions == null && userLanguage == null ) {
return null;
}
List<AlertConfigActionTO> list = new List<AlertConfigActionTO>();
return list;
}
I'm sure it is related to the parameter since if I remove it (from all mapping methods) then the mapList method is generated correctly.
What is needed to be done to allow custom parameters in this case?
What you describe is not possible (yet). Could you open a feature request in our issue tracker? We should provide means of denoting parameters as some sort of "context" which is passed down the call stack.
As a work-around for the time being, you might take a look at using a ThreadLocal which you set before invoking the mapping routine and which you access in your after-mapping customization. It's not elegant - and you need to make sure to clean up the thread local to avoid memory leaks - but it should do the trick.
I know that this question is quiet old, but I run into this issue, and starting at version 1.2 of mapstruct you can resolve it using #Context
So declaring the mapping for the list need to be like this :
public abstract ArrayList<AlertConfigActionTO> mapList (List<AlertConfigAction> actions, #Context Locale userLanguage);
Now, you juste need to add another non abstract mapping like this :
public AlertConfigActionTO mapConcrete (AlertConfigAction action, #Context Locale userLanguage){
return map (action, userLanguage);
}
I don't think it is possible. At least not that way. Problem is that you prepare interface/abstract class - and rest is done by the engine. And that engine expects methods with one parameter... There are decorators, but they go the same way. I would try to inject language. Create bean, mark it as session scoped, and find out. With Spring, you would use ScopedProxyMode for that... Not sure how that goes with CDI.
Other option is more workaround, then solution - maybe that AlertConfigAction can pass that information?

How to use Custom type for #PathParam?

I want to use non spring bean class object as parameter for jersey web service class method. But it is giving missing dependency error at build time.
My code is:
#Component
#Path("/abcd")
public class ActorServiceEndpoint {
#POST
#Path("/test/{nonspringBean}")
#Produces(MediaType.APPLICATION_XML)
public void addActor(#PathParam("nonspringBean") MyNonSpringBeanClass nonspringBean){
}
}
The thing is path parameters come in String form. As per the specification, if we want the have a custom type be injected as a #PathParam, the custom class, should have one of three things:
A public static valueOf(String param) that returns the type
A public static fromString(String param) that returns the type
Or a public constructor that accepts a String
Another option implement a ParamConverter. You can see an example here.
If you don't own the class (it's a third-party class that you can't change) then your only option is to use the ParamConverter/ParamConverterProvider pair.
In either of these cases you'll want to construct the instance accordingly by parsing the String either in the constructor or in one of the above mentioned methods. After doing this, the custom type can be made a method parameter with the annotation.
The same holds true for other params, such as #FormParam, #HeaderParam, #QueryParam, etc.
It would help if you gave a bit more details of the error you're getting, but I see two problems with your code snippet:
The correct Spring annotation is #PathVariable, #PathParam is probably from another package. This doesn't apply as I guess you're using JAX-RS, not Spring annotations.
I'm not sure what converters are applied to path variables, but in any case it would need to have one for MyNonSpringBeanClass. I would take a String parameter and then instantiate MyNonSpringBeanClass myself in the function body.

Creating Custom Java Compiler Errors Without Using Annotations

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.

Categories

Resources