How to acces JavaFX fields via Annotation? - java

What I'm trying to do:
I have a Java program in which I use JavaFX. I created a fxml file in which I created JavaFx controllers, which I then declared in the AddEmployeeOrderController class. I would like to transfer these created controller fields to a POJO. Since I think it is very time-consuming and leads to a lot of careless mistakes, I wanted to automate this process more. My idea was to make an annotation for each declared JavaFX controller field so that, for example, all annotated fields are gonna be retrieved automatically at for example a push of a button in another method. So you can understand it that way instead of writing everything by hand yourself, e.g.:
EmployeeDto employeeDto = new EmployeeDto(textfield.getText(), textfield2.getText()..);
I first formed the AddEmployeeOrderController and declared some JavaFX field and added an annotation. Again in the AddEmployeeOrderController class I tried to access the annotated field.
Then, logically, I would have to cast to cast the java.lang.reflect.Field to a JavaFX TextField, but that is obviously not possible. It throws only IllegalArgumentException errors, and of course because you can't cast a java.lang.reflect.Field to a JavaFX TextField.
Is there a way in which my idea can be achieved with the help of annotation, or am I forced to write everything by hand and generate so-called boilerplate code.
public class AddEmployeeOrderController implements Initializale {
#FXML
#MyAnno
public TextField orderDateFromTextField;
public void atPushButton() {
for (Field field : AddEmployeeOrderController.class.getDeclaredFields()) {
if (field.isAnnotationPresent(MyAnno.class)) {
if (((Field) object).getType().getCanonicalName()
.contains("TextField")) {
TextField textField = (TextField) field.get(this);
textField.getText();
}
}
}
}
}
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnno {
}

You have not provided sufficient (relevant) code to understand what you are actually doing. However, we can deduce the following:
The Field class you are using is java.lang.reflect.Field.
According to the javadoc, the Field.get(Object) should be called with a reference to an instance ... or null. If an instance is provided, then it needs to be an instance the class that declares the field, or a subclass of that class.
If Field.get is called with a parameter that is NOT of the required class, IllegalArgumentException is thrown.
So ... if what you have told us and shown us is correct ... this is not the correct object to be passing to Field.get on that Field object.
You are saying that the field reflection code you are showing us is in the AddEmployeeController class. That means that this would be a AddEmployeeController instance. But the Field instances you are iterating are for the fields declared by the class AddEmployeeOrderController. So, you should be calling get with a (non-null) value that refers to an AddEmployeeOrderController instance. (Or maybe you should be iterating the declared fields of AddEmployeeController. Without more context it is difficult to say what the correct fix is.)
If we strip away all of the dynamic / reflective stuff, what your code is doing is analogous to this non-reflective code:
public class AddEmployeeOrderController {
public TextField someField;
}
public class AddEmployeeController {
public void someMethod() {
TextField t = (TextField)(this.someField);
}
}
It won't compile because AddEmployeeController doesn't have a field called someField.
What you actually need to do is the analog of this:
public class AddEmployeeController {
public void someMethod(AddEmployeeOrderController aeoc) {
TextField t = (TextField)(aeoc.someField);
}
}
Just to clarify, the problem is not coming from the typecast in
(TextField) field.get(this);
If the typecast was failing, then the exception would be a ClassCastException. The exception you are seeing comes from the get call!
And the problem is not due to annotations.
FOLLOW-UP
I have taken your (attempted) MRE, factored out the JavaFX stuff, and turned it into working code. My version shows how to extract a field value reflectively by matching the field's type and an annotation.
package test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnno {
}
// End of MyAnno
package test;
import java.lang.reflect.Field;
public class MyTest {
#MyAnno
public String someField = "Hi Mom";
public void doIt() throws Exception {
for (Field field : this.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(MyAnno.class)) {
if (field.getType().getCanonicalName().equals("java.lang.String")) {
String value = (String) field.get(this);
System.out.println(value);
}
}
}
}
public static void main(String[] args) throws Exception {
new MyTest().doIt();
}
}
Note that this is REAL code. It compiles, runs and ... works. Try it. If you change String to (say) TextField, you can adapt it to your problem. (The actual type of the field is almost entirely irrelevant to the core problem. As you can see.)
(One thing that could be improved and simplified is that the type test should use Class.equals rather than testing the name of the class. It is cleaner and more reliable.)
One of your concerns was (I think) that you would need a lot of boilerplate code to make this work for your problem. I don't think that is the case:
If I declare an abstract superclass for MyTest and put the implementation of doIt() there ... it should just work. Notice that doIt() uses this.getClass() to get the current object's class.
It would also work if doIt() was in an unrelated class, provided that the method had an argument for passing the target Object.
It would even be possible to parameterize this on the type of the field. Or look for fields that are subtypes of a given type. And so on. (Hint: you would need to pass the type as a Class object.)
I said "(attempted) MRE" for a reason. In fact, your code doesn't compile. Indeed, you have a variable (object) which is not declared, and whose intended type and purpose is hard to fathom. I have assumed that it was a mistake, and guessed that your intention was to use field there. But I should not have to guess!
A real MRE needs to be complete and compilable (unless your problem is how to get it to compile). Ideally it should also be runnable, and running the MRE should reproduce the problem you are asking about.
The point is that we (people trying to help you) need to be sure that we understand what your problem is. That is the purpose of the MRE.

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: make static methods of one class mirror instance methods of another class

I have a POJO like this:
public class Foo {
private String bar1;
private String bar2;
//...
public String getBar1() { return bar1; }
public void setBar1(String bar1) { this.bar1 = bar1; }
public String getBar2() { return bar2; }
public void setBar2(String bar2) { this.bar2 = bar2; }
//...
}
As an alternative to Java reflection (which is quite slow in general), I would like to define a class with static methods like this:
public class FooStatic {
public static String getBar1(Foo foo) { return foo.getBar1(); }
public static void setBar1(Foo foo, String bar1) { foo.setBar1(bar1); }
public static String getBar2(Foo foo) { return foo.getBar2(); }
public static void setBar2(Foo foo, String bar2) { foo.setBar2(bar2); }
//...
}
which enforces the creation/deprecation of a static method every time the Foo class is updated. For example, if the field bar2 is deleted in FooStatic, then the static methods getBar2() and setBar2() in FooStatic should be identified by the compiler to be removed. If a new variable bar3 is added to Foo with getters and setters, the compiler should enforce the creation of new static methods getBar3() and setBar3() in FooStatic. Moreover, I have multiple POJOs, and would like a solution which scales. Is this possible?
Yes... sort of. It's very complicated.
Annotation Processors are compiler plugins that run at certain times during the compilation process. It gets complex fast - IDEs and build tools are 'incremental' (they don't want to recompile your entire code base everytime you change a single character, of course), for example.
Annotation processors can do a few things:
They can run as part of the compilation processes. This can be done automatically - they just need to be on the classpath, is all
They can be triggered due to the presence of an annotation.
They can read the signatures of existing files (the names of fields and methods, the parameter names, parameter types, return type, and throws clause, and the type of fields, and the extends and implements clauses, and the param names and types of the constructors). They can't read the body content (initializing expressions, method and constructor bodies). But I think you just need the signatures here.
They can make new files. They can even make new java files which will then automatically get compiled along with the rest.
Thus, you have a route here: Make an annotation, then make an annotation processor. For example, you could set it up so that you manually write:
#com.foo.Hossmeister.Singletonify
class Example {
void foo1() {}
String foo2(String arg) throws IOException {}
}
and have an Annotation Processor (which also has that com.foo.Hossmeister.Singletonify annotation), which, if it is on the classpath, automatically generates and ensures that all other code can automatically see this file:
// Generated
class ExampleSingleton {
private ExampleSingleton() {}
private static final Example INSTANCE = new Example();
public void foo1() {
INSTANCE.foo1();
}
public static String foo2(String arg) throws IOException {
return INSTANCE.foo2(arg);
}
}
But, annotation processors are tricky beasts to write, and they can be quite a drag on the compilation process. Still, that's the only way to get what you want. Now you have something to search the web for / read up on :)
You start by making a separate project that defines the annotation, has the annotation processor (a class that extends AbstractProcessor), pack that into a jar, and make sure the manifest includes an SPI file that tells java that your class that extends AbstractProcessor is an annotation processor, and then it'll be picked up automatically. I'll give you the annotation definition:
In a file named Singletonify.java:
#Retention(RetentionPolicy.CLASS)
#Target(ElementType.TYPE)
public #interface Singletonify {}
But... wait!
The concept of singletons is often problematic. Singletons should be 'stateless' - and if they are stateless, why isn't your Foo class just filled with entirely static methods, obviating the need for your "static mirror class"? If it is stateful, you now have global state which is a virtually universally decried anti-pattern. You don't want global state, it makes reasoning about control flow impossible.
A second problem is testability - because static stuff doesn't 'do' inheritance, you can't (easily) make test implementations of static methods. With non-static stuff this is much easier.
This problem is more generally solved by so-called Dependency Injection frameworks such as Dagger, Guice, or Spring. They let you write code that just 'gets' an instance of your Foo class, without callers having to actually figure out where to get this instance from: The Dependency Injection framework takes care of it. It lets you do things like "Have a singleton of this object... per web session". Which is pretty powerful stuff.
I think what you probably want is a DI system. You may want to investigate a bit before spending the 2 weeks writing that annotation processor.

Determine whether field is annotated with a given annotations

I don't know if you managed to figure out what i am trying to do just from the title so I'll try to explain with example
Lets suppose I have created my own annotation #VerifySomething
And I have created test class for that annotation to make sure it works.
Now lets suppose that I have class SomeClass with field something anoted with annotation #VerifySomething
class SomeClass {
#VerifySomething
String something;
}
So far so good, but now I want to create test class for my SomeClass however I don't see any point in verifying all the test cases of something as I have already checked that #VerifySomething works as it should in class which tests that annotation, however I need to make sure that field something actually has #VerifySomething annotation without copy pasting all these test cases.
So my question is, is there a way to check if some field has one or more required annotation without writing test cases I have already written in annotation test class to make sure it works as it should.
You can use getAnnotation to determine if there is a specific Annotation on the field, which takes the annotation class as a parameter:
field.getAnnotation( SomeAnnotation.class );
Here is a method you can use to verify that a class has a field annotated by given annotation:
import java.lang.reflect.Field;
import javax.validation.constraints.NotNull;
import org.junit.Test;
import org.springframework.util.Assert;
public class TestHasAnnotatedField {
#Test
public void testHasFieldsWithAnnotation() throws SecurityException, NoSuchFieldException {
Class<?>[] classesToVerify = new Class[] {MyClass1.class, MyClass2.class};
for (Class<?> clazz : classesToVerify) {
Field field = clazz.getDeclaredField("something");
Assert.notNull(field.getAnnotation(NotNull.class));
}
}
static class MyClass1 { #NotNull String something; }
static class MyClass2 { #NotNull String something; }
}
I am not sure I am following, but in case you want to verify whether a class and or its properties have a given Bean Validation constraint, you can use the meta data api. The entry point is Validator#getConstraintsForClass(SomeClass.class). You get a BeanDescriptor. From there you can do _beanDescriptor#getConstraintsForProperty("something") which gives you a PropertyDescriptor. Via propertyDescriptor#getConstraintDescriptors() you get then a set of ConstraintDescriptors which you can iterate to verify that a given constraint annotation was used.
Note, this is a Bean Validation specific solution compared to generic reflection as in the answer above, but it depends what you are really after. To be honest I don't quite understand your use case yet.

final static String defined in an interface not evaluated at compile time - Android

I have two classes and an interface (for example DatabaseModel, LocalStore, and InternalModelInterface). They're defined as follows;
public class DatabaseModel {
// ...
public static final String KEY_PARAM1 = "param1";
}
public class LocalStore implements InternalModelInterface {
// ...
public void function () {
String temp = InternalModelInterface.COLUMN_PARAM1;
}
}
public interface InternalModelInterface {
public static final String COLUMN_PARAM1 = DatabaseModel.KEY_PARAM1;
// ...
}
The issue I'm experiencing is that at runtime, when I call localStore.function(), temp is being assigned null, as InternalModelInterface.COLUMN_PARAM1 is null. Does this make sense? Shouldn't InternalModelInterface.COLUMN_PARAM1 be evaluated at compile time and inlined?
This is for an Android application. Thanks in advance.
I'll further explain to clarify any confusion.
Objects of the DatabaseModel class are instantiated as a JSON response is parsed. The constants defined in the DatabaseModel class represent the keys to look for in the JSON response.
The InternalModelInterface defines the column names used in the local (cache) database on the device. For several reasons (including they keys being illegal column names in SQLite), I'm not reusing the keys as column names.
The reason I'm using an interface and not just a plain class is that the interface also specifies required methods that need to be implemented by the third class, LocalStore.
JLS3 §8.3.2.1, §9.3.1 http://java.sun.com/docs/books/jls/third_edition/html/classes.html#38010
at run time, static variables that are
final and that are initialized with
compile-time constant values are
initialized first. This also applies
to such fields in interfaces (§9.3.1).
These variables are "constants" that
will never be observed to have their
default initial values (§4.12.5), even
by devious programs.
So null should never be observed in your example. It's an Android bug then.
I'm not and android expert but I think that if you don't create an instance of the class, it's optimised out at compile time. If you create a constructor for DatabaseModel and instantiate it somewhere it seems to solve this for me.

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