I have a script with a global variable in my Groovy script
I have a problem using it inside a function. May I know the reason or the right way?
I'm gonna be using it for a logger. Other primitive data types can be accessed but this, I can't.
#Field def log = Logger.getLogger("NameOfLogger")
log.info("TEST")
testFunction()
private void testFunction() {
//cannot use the log variable here
}
I know now the cause. It's because I was declaring it as def
But I still don't know the real reason why def can't be used.
The following code works for me (I haven't tried with log but used online groovy console):
import groovy.transform.Field
import groovy.transform.Canonical
#Canonical
class Person {
String name
int age
}
#Field person = new Person("John", 30)
println "Global $person"
testFunction()
private void testFunction() {
println "Inside method: $person"
}
Output:
Global Person(John, 30)
Inside method: Person(John, 30)
So make sure you have proper imports first of all
Now, it worth mentioning that groovy creates an implicit class and Field annotation alters the scope of the global variable and moves it to be a field of that implicit class so that both person and testFunction will both belong to this class and there won't be a problem to access the field from within the method.
Related
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.
Does ReflectionTestUtils works only on fields of a class, not on variables defined inside a method of that class?
I tried to test the fields of a class, it works perfectly fine using ReflectionTestUtils, if I try it on variables of a method, I get an IllegalArgumentException.
Example Code:
public class Check {
String city;
public void method() {
city = "Bangalore";
String Street = "MGRoad";
}
}
If I want to have a JUnit tests for the above class using ReflectionTestUtils.
Check c = new Check();
assert ReflectionTestUtils.getField(c, "city").equals("Bangalore")
-> works fine.
assert ReflectionTestUtils.getField(c, "Street").equals("MGRoad")
-> gives illegalArgumentException.
Please have a look and suggest me if I can test the attributes of a method.
You cannot access local variables using reflection and String Street = "MGRoad"; is local variable to that method
If what you mean is variables local to methods/constructors, you can not access them with reflection. ... There is no way to obtain this information via reflection. Reflection works on method level, while local variables are on code block level.
C# 6.0 introduced the nameof() operator, that returns a string representing the name of any class / function / method / local-variable / property identifier put inside it.
If I have a class like this:
class MyClass
{
public SomeOtherClass MyProperty { get; set; }
public void MyMethod()
{
var aLocalVariable = 12;
}
}
I can use the operator like this:
// with class name:
var s = nameof(MyClass); // s == "MyClass"
// with properties:
var s = nameof(MyClass.OneProperty); // s == "OneProperty"
// with methods:
var s = nameof(MyClass.MyMethod); // s == "MyMethod"
// with local variables:
var s = nameof(aLocalVariable); // s == "aLocalVariable".
This is useful since the correct string is checked at compile time. If I misspell the name of some property/method/variable, the compiler returns an error. Also, if I refactor, all the strings are automatically updated. See for example this documentation for real use cases.
Is there any equivalent of that operator in Java? Otherwise, how can I achieve the same result (or similar)?
It can be done using runtime byte code instrumentation, for instance using Byte Buddy library.
See this library: https://github.com/strangeway-org/nameof
The approach is described here: http://in.relation.to/2016/04/14/emulating-property-literals-with-java-8-method-references/
Usage example:
public class NameOfTest {
#Test
public void direct() {
assertEquals("name", $$(Person.class, Person::getName));
}
#Test
public void properties() {
assertEquals("summary", Person.$(Person::getSummary));
}
}
Sadly, there is nothing like this. I had been looking for this functionality a while back and the answer seemed to be that generally speaking, this stuff does not exist.
See Get name of a field
You could, of course, annotate your field with a "Named" annotation to essentially accomplish this goal for your own classes. There's a large variety of frameworks that depend upon similar concepts, actually. Even so, this isn't automatic.
You can't.
You can get a Method or Field using reflection, but you'd have to hardcode the method name as a String, which eliminates the whole purpose.
The concept of properties is not built into java like it is in C#. Getters and setters are just regular methods. You cannot even reference a method as easily as you do in your question. You could try around with reflection to get a handle to a getter method and then cut off the get to get the name of the "property" it resembles, but that's ugly and not the same.
As for local variables, it's not possible at all.
You can't.
If you compile with debug symbols then the .class file will contain a table of variable names (which is how debuggers map variables back to your source code), but there's no guarantee this will be there and it's not exposed in the runtime.
I was also annoyed that there is nothing comparable in Java, so I implemented it myself: https://github.com/mobiuscode-de/nameof
You can simply use it like this:
Name.of(MyClass.class, MyClass::getProperty)
which would just return the String
"property"
It's also on , so you can add it to your project like this:
<dependency>
<groupId>de.mobiuscode.nameof</groupId>
<artifactId>nameof</artifactId>
<version>1.0</version>
</dependency>
or for Gradle:
implementation 'de.mobiuscode.nameof:nameof:1.0'
I realize that it is quite similar to the library from strangeway, but I thought it might be better not to introduce the strange $/$$ notation and enhanced byte code engineering. My library just uses a proxy class on which the getter is called on to determine the name of the passed method. This allows to simply extract the property name.
I also created a blog post about the library with more details.
Lombok has an experimental feature #FieldNameConstants
After adding annotation you get inner type Fields with field names.
#FieldNameConstants
class MyClass {
String myProperty;
}
...
String s = MyClass.Fields.myProperty; // s == "myProperty"
I am writing a Junit for a method with multiple parameters and having private access specifier. I am using Java reflection to achieve this. However, one of the parameter for this private method is private class. I am doing below:
ClassHavingPrivateMethod object = new ClassHavingPrivateMethod();
object.getClass().getDeclaredMethod(PRIVATE_METHOD_NAME, Param1.class, <This parameter is a private class Inside ClassHavingPrivateMethod>)
How can I proceed?
EDIT
I agree on the point that I should not write a test case for a private method with reflection and it should always be accessed through a wrapper public method. However, is there any way to achieve the above objective through reflection. Even though, I am not going to write my test case through reflection but I am eager to know about it.
Any help is really appreciated.
One of the way you can try by changing the access from private to default. By changing the access level to default the method can be accessed only from the same package (still restricted access) on the other hand since your test class and class under test will be under same package , the test class can call that method directly, without doing any trick.
Example :
package com.test;
class SomeClass {
String defaultMethod(){
...
}
}
package com.test;
class SomeClassTest {
public void testDefaultMethod(){
SomeClass testObject = new SomeClass();
testObject.defaultMethod();
}
}
Hope it will help.
In a Groovy 2.1.6 Script I'm defining a field:
import groovy.transform.Field
#Field String test = "abc";
println "Script: ${test}";
def run = new Runnable() {
void run() {
println "Runnable0: ${test}";
new Runnable() {
void run() {
println "Runnable1: ${test}";
}
}.run();
}
}.run();
When accessing it from an anonymous Classes in the Script like here, Groovy seems to try to cast this Field to a Reference and throws the following Exception as soon as the Runnable is defined:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'abc' with class 'java.lang.String' to class 'groovy.lang.Reference'
at bug1.run(bug1:5)
Additionally, if i put the anonymous Runnables in a function like here, Groovy has no problems with casting, but doesn't find the Field in the inner Runnable:
groovy.lang.MissingFieldException: No such field: test for class: bug2$1
at bug2$1.this$dist$get$1(bug2.groovy)
at bug2$1$2.propertyMissing(bug2.groovy)
at bug2$1$2.run(bug2.groovy:14)
at java_lang_Runnable$run.call(Unknown Source)
at bug2$1.run(bug2.groovy:12)
at java_lang_Runnable$run.call(Unknown Source)
at bug2.fun(bug2.groovy:9)
at bug2.run(bug2.groovy:5)
This can be fixed by redefining the field like here
, but this fix only works inside a function
Is this a bug in Groovy or am I just violating some rules and Groovy only lacks proper Exceptions?
You do not need #Field transformation in case where you call anonymous class and refer the field variable.
Reason:
When a strictly typed variable in a script is defined as #Field then that variable (at compile time [AST transformed]) is treated as private inside that script. Hence property missing.
In order to realize the difference, just visualize the script in AST browser from Groovy console and go through the "Semantic Analysis" phase under both cases (without and with #Field), you would notice the variable is local to run() for the main script as compared to defined globally otherwise respectively.
Corollary:
On the other hand, #Field transformation is useful when strictly typed variables are to be used in a method inside the same script because without #Field the field will be declared as a local variable in the run() method of the script, hence not visible to other methods.
Excerpts from AST browser for details.
As Groovy closures are Runnables already, you could do:
import groovy.transform.Field
#Field String test = "abc";
println "Script: ${test}";
{ ->
println "Runnable0: ${test}";
{ ->
println "Runnable1: ${test}"
}.run()
}.run()
Which works