Runtime Annotation Processing - java

My question is as follows; please assist.
I have an annotation applicable to methods only that i want to be processed at runtime, say
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnno {
String name();}
And here is my processor:
public class MyAnnoProcessor(Class cls){
Method[] m = cls.getClass().getMethods();
...// read the value passed to name and create an instance of an object depending on the value of 'name'
Yes. MyAnnoProcessor code is as follows:
public class MyAnnoProcessor(Class cls){
Method[] methods = cls.getMethods();
for(Method m: methods){
MyAnno an = (MyAnno) m.getAnnotation(MyAnno.class);
if(an!=null)
sysout(an.name());
....//call another method to create a class based on the value passed to 'name'
Now, i have a class where i want to write many methods annotated with #MyAnno but each method passes a different value to "name". Am just unable to figure out a way to handle the annotation processing in an ideal way? How should 'MyAnnoProcessor' know what (object) needs to be returned to which method?
Say, i do this in a method A:
#MyAnno(name="testA")
public void A(){
MyAnnoProcessor(this);
...}
And again i do this in method B:
#MyAnno(name="testB")
public void B(){
MyAnnoProcessor(this);
...}
The 'MyAnnoProcessor' seems to read the value of 'name' as "testA" and not "testB" in the subsequent call to it from method B. Where am i mistaken? Please advise.

If you want to find annotations for a single method, you could first get the method using reflection and the do a getDeclaredAnnotations(). Something like
Class clazz = ...//obtain class object
Method method = clazz.getMethod("A", null);
Alternatively, with your current code, you can still loop through all methods and do a matching for the method name by doing m.getName() inside your for loop to find out which method you're looking at right now.
P.S: I'm not entirely sure your code would compile (MyAnnoProcessor, i don't see any methods) and please try to follow naming conventions for methods)

Related

haven't provide instance field declaration so I tried to construct the instance.However the constructor or the initialization block threw an exception

class Example extends Parent{
public Example() {
super(Example.class)
}
whenever I am trying the
public class Test{
#InjectMock Example example
#BeforeMethod
#BeforeTest
public void setUp(){
MockitoAnnotations.initMocks(this)
}
}
It is giving the above error mentioned.
Any help is appreciated.
there are a pair of things in your code which not used correctly. I think there is a bit of confusion and is not clear enough what you what to do. I'll try to explain e give you something to read.
#Injectmocks annotation in Test class
The #Injectmocks annotation is used to create a real instance of a class in which you want to inject #Mock objects.
Take a look here for some examples:
https://howtodoinjava.com/mockito/mockito-mock-injectmocks/ ,
https://www.baeldung.com/mockito-annotations
The annotation is an instance field annotation. This means that you cannot use that as you are doing on a method declaration, but you need to use that instead on a field into the test class.
Let's suppose you want to test a method in a class, then you will use this annotation to create an instance of that class which contains the method to be tested. Roughly speaking with analogies, injectmock is like the Spring #Autowire annotation, although not the same.
I've noticed now that probably this is what you where trying to do (the puplished code of the test class has not been highlighetd correctly). You should put new line after #InjectMock Example example. In any case, I think there is a mistake in how you use the super keyword.
Call to super constructor in Example constructor.
I don't know what is the constructor in Parent class and how is done, but the rule is you pass arguments of the Parent construtor in super keyword. So for exampe, if this is your parent constructor:
public Parent(String name){
this.name = name}
then you need to do this in Example:
public Example(String name, String code) {
this.code = code;
super(name);
}
You are passing a .class in super(), not a field.
I would like to give you more help. I suggest you to post your code more clearly and with complete classes.

Java - how can I loop methods with same name but different parameters

I have class named: ComplexValidator that extends absract class Validator which have two methods:
Validate(Part part);
getAnswer():
I also have validators, lets name them A, B, C and D.
So
AValidator extends Validator
BValidator extends Validator
CValidator extends Validator
DValidator extends Validator
I am not in front of my code right not so I will use pseudo-code.
CValidator takes different parameter than rest of it, A B and D uses part to get filename etc, but CValidator uses numberOfFiles (which are increased in loop (for part p: multipart) so after every time loop is repeated numberoffiles is increased so I can compare it with maxNumberOfFiles field).
Sadly I didnt know how to make abstract class that will take any parameter to method so all methods must take Part part. Cvalidator doesnt use it and I had to make field numberOfFiles static so I can get access to it.
Is there any way to make those validators takes no parameters but no using static?
Is there any way to make abstract class the way that child classes will be able to change arguments it take?
And if it takes other arguments HOW can I loop it all when I have:
List <Validator> validators = new ArrayList<>();
in my ComplexValidator.
and then I add all child validators to it and loop over them like that:
for (Validator v: validators){
validate(part);
}
The types of the parameters of an overriden method must be the same as the original method.
To face your problem I would create a custom class that wraps all the different parameters that you might want to pass to the validate function.
Something like that
class Wrapper{
Part param1;
File param2;
File param3;
}
class Validator{
void validate (Wrapper wrapper);
}
class ValidatorA extends Validate{
void validate (Wrapper wrapper){
//use wrapper.part...
}
}
class ValidatorC extends Validate{
void validate (Wrapper wrapper){
//use wrapper.file...
}
}
You may want to use java reflection. With a Class you can either getMethods and loop throught the methods and getParameterTypes of each method or if you know in advance the types of the method you wish you can getMethod (without s) and provide an array of type.
In your case I would go to the first method and depending on the presence of the second parameter (number of files), invoke the method the good way (with all the parameters needed).

Passing Class<?> cls as a method parameter?

I'm having trouble completing this method.
I am trying to write a method that will let my main pass two parameters: a Talker object instance and cls a Class object representing the type which the Listener should extend from in order to receive the message. I'm very new to Java and could use some help with this.
Here's the code for the method:
public void sMessage(Talker talker, Class<?> cls) {
for ( Listener l : mParticipants)
{
if (cls.isAssignableFrom(cls.getSuperclass())) {
l.onMessageReceived(talker.getMessage());
}
}
}
Not sure how I should complete this, or how to make a call from main:
singletonDemo.sMessage(demoTalker, Class?);
Not really following the examples I've seen so far. Any suggestions?
#BornToCode is correct about calling the method, but what you want to achieve with the method is still slightly wrong.
cls.isAssignableFrom(cls.getSuperclass())
will always return false. This is because you cannot take a parent class and assign it to the child class. I believe what you are looking for is a way to check if the listener extends the class specified. You can do this by getting the class of the listener.
cls.isAssignableFrom(l.getClass())
or more simply
cls.isInstance(l)
I do not understand what cls should represent. However, you should get something like:
singletonDemo.sMessage(demoTalker, SomeClass.class);
or:
singletonDemo.sMessage(demoTalker, someClassInstance.getClass());
For your information, cls.isAssignableFrom(cls.getSuperclass()) will always return false. The documentation of isAssignableFrom says:
Determines if the class or interface represented by this Class object is either the same
as, or is a superclass or superinterface of, the class or interface represented by the
specified Class parameter.

Can java get method with methodname through reflections

I know Java can get Method Object using the Reflection.getMethod(...) method,but the method needs method parameter types。 but I don't know the exact parameter type。e.g.
byte a = 20;
System.out.println(a);
the println method hasn't the overload method println(Byte),but has println(Int)。
How to get the println method through the byte type?
the other example
class MyClass
{
}
class MyClass1 extends MyClass
{
}
class TestClass
{
public static void method1(MyClass c)
{
... ...
}
}
TestClass.method1(new MyClass1()) is correct.but can i get the method1 through parameter type MyClass1 ?
Class.getMethods will get all method in Class, too much。 can i get all overload method same name?
java.lang.Class (see JavaDoc) provides two ways of finding methods:
Method getMethod(String name, Class<?>... parameterTypes)
and
Method[] getMethods()
(and corresponding getDeclaredMethod() variants).
So there's no API in the standard Java library for directly getting what you need - you'll need to get all methods, filter the ones with the right name, then inspect the parameter types.
Or you may be able to find a 3rd-party library that will do this for you. For example, the reflections library has a getMethodsMatchParams(Class<?>... types) method.
The jOOR library also provides various methods for finding methods with "similar" signatures.

Detecting the present annotations within the given object passed into a constructor

My question in short: how do I detect if a java annotation is present (and in the right place) for a given user class/object.
Details of the "problem"
Lets say I have two java classes:
public class Line {
private List<Cell> cells;
public Line(Object... annotatedObjects) {
// check if annotations #Line and #Cell are present in annotatedObjects.
}
// getter/setter for cells.
}
public class Cell {
// some members
// some methods
}
A Line object holds Cells.
I also have two annotations, like:
public #interface Line {
// some stuff here
}
public #interface Cell {
// some stuff here
}
I also have a bunch of user classes (two will do for this example) that contain the #Line and #Cell annotations I specified, like:
#Line(name="pqr", schema="three")
public class AUserClass {
#Cell
private String aString;
}
#Line(name="xyz", schema="four")
public class AnotherUserClass {
#Cell(name="birthday")
private Date aDate;
}
The problem: When I instantiate a new Line object, I want to be able to pass the user classes/objects into the Line constructor. The Line constructor then finds out if the passed user classes/objects are valid classes that can be processed. Only user classes that have a #Line annotation for the class, and at least one #Cell annotation for its members are valid objects that can be passed into the constructor of the Line object.
All other passed objects are invalid. The moment a valid user object is passed, all the available members that are tagged as #Cell in that object are transformed to Cell objects and added to the cells list.
My questions:
is this possible to detect the annotations in this object/class at runtime, and only for THIS passed object (I don't want to scan for annotations on the classpath!)?
is it possible to detect the datatype of the #Cell tagged members? This is needed because the Cell class doesn't accept all datatypes.
is it possible to retrieve the actual member name (specified in the java file) so that the user doesn't have to specify the members Cell name. I want the user to be able to write #Cell (without a name) and #Cell(name="aName"), and when only #Cell is specified, the name of the member is used instead. I have no idea if this information is still available at runtime using reflection.
How to detect if the annotations are in the right place?If code is tagged like this, then the object should be ignored (or maybe an exception is thrown)?
#Cell // oh oh, that's no good :(
public class WrongClass {
// some members
}
Could you provide some startup code, so I know a little to get going with this problem. I am really new to annotations and reflection. BTW: I am using the latest jvm 1.6+
Thank you for your kind help!
First you need to have retention policy on your annotations so you can read them with reflection
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public static #interface Line {
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public static #interface Cell {
}
Second you need to test if the class has the Line annotation with isAnnotationPresent(annotationClass). This method is accessible from java.lang.Class and a java.lang.reflect.Field.
NOTE: that you need to retrieve the fields that are private with class.getDeclaredField(fieldName).
3. I don't think you can make an annotation have a default value based on a propertyName but you can make name optional by providing a default String name() default DEFAULT and check for that value when iterating through the fields and either use the value stored in name() or the propertyName
Q.1 :is this possible to detect the annotations in this object/class at runtime, and only for THIS passed object (I don't want to scan for annotations on the classpath!)?
Yes it is very well possible using isAnnotationPresent
#Deprecated
public class AnnotationDetection {
public static void main(String[] args) {
AnnotationDetection annotationDetection = new AnnotationDetection();
System.out.println(annotationDetection.getClass().isAnnotationPresent(Deprecated.class));
}
}
Note that annotation which are scoped to retain at Runtime will be available only,

Categories

Resources