GroovyScript Field access in anonymous Class - java

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

Related

Using of #Field variable in Groovy script

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.

Does ReflectionTestUtils works only on fields of a class, not on variables defined inside a method of that class?

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.

Calling java class methods in Rhino script

I have one interface method as follows and saved in Order.java file
and rhino script.
In rhino script I am trying to call the interface methods.
rhino:
var x = Packages.com.data.Order.X;
print(x);
java:
package com.data;
public interface Order
{
String X = "Hello, World!";
void invoke();
}
but it is not printing "Hello world".
Instead it is printing
uncaught JavaScript runtime exception: TypeError: Cannot call
property invoke in object [JavaPackage com.data.Order]. It is not a
function, it is "object". "
problem Statement: How to call java interface method from rhino script.
That type of error usually means that the Rhino engine is not seeing the class you are attempting to use.
If you are definitely seeing the jar get into the classpath, next, I'd double check that the jar contains your class exactly as referenced.
You can verify whether the JS step is seeing your class properly by Alerting it like this:
Alert(com.foo.bar.MyClass);
If the Alert indicates it is a JavaClass then it found your class. Otherwise it will say it is a JavaPackage.

nameof equivalent in Java

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"

Java -The method sleep(int) is undefined for the type Thread

I'm getting an error: The method sleep(int) is undefined for the type Thread. I thought the sleep method is in the Thread class in Java.
import java.util.Random;
public class Thread implements Runnable {
String name;
int time;
Random r = new Random();
public Thread(String s){
name = s;
time = r.nextInt(999);
}
public void run() {
try{
System.out.printf("%s is sleeping for %d\n", name, time);
Thread.sleep(time);
System.out.printf("%s is done", name);
} catch(Exception e ) {
}
}
}
You implemented your own class called Thread and try to call sleep on it, which fails, cause sleep is undefined in your class. Your class basically shadows java's Thread class.
Call your class differently (ie. MyThread or even better MyRunnable, as noted by owlstead) or call java.lang.Thread.sleep() directly.
It's not in your Thread class.
Since you named your class Thread, that's where Java will look for Thread.sleep. If you want the function that's built into Java, try java.lang.Thread.sleep(time);.
Your class name "Thread" conflicts with the Thread class in Java standard library. Change the name of your class and it will resolve everything.
The reason you're getting this is that you've implemented your own Thread class. In your class there is no sleep method.
First prize would be to avoid using class names that are part of the standard Java libraries.
If you insists to keep the names, use java.lang.Thread.sleep(...) to specify that you want the Thread class that Java provides.
Fully-qualify Thread since you're trying to use java.lang.Thread, not your own.
The problem is that your class is named Thread, which doesn't have a sleep() method. The sleep method is in java.lana.Thread, which is being hidden by your class.
Answers to this question have already been posted yet one another analogy. It may not be the direct answer but may help you remove your confusion why should avoid reusing the names of platform classes, and never reuse class names from java.lang, because these names are automatically imported everywhere.
Programmers are used to seeing these names in their unqualified form and
naturally assume that these names refer to the familiar classes from java.lang. If
you reuse one of these names, the unqualified name will refer to the new definition
any time it is used inside its own package.
One name can be used to refer to multiple classes in different packages. The following simple code snippet explores what happens when you reuse a platform class name. What do you
think it does? Look at it. It reuses the String class from the java.lang package. Give it a try.
package test;
final class String
{
private final java.lang.String s;
public String(java.lang.String s)
{
this.s = s;
}
#Override
public java.lang.String toString()
{
return s;
}
}
final public class Main
{
public static void main(String[] args)
{
String s = new String("Hello world");
System.out.println(s);
}
}
This program looks simple enough, if a bit repulsive. The class String in the
unnamed package is simply a wrapper for a java.lang.String instance. It seems
the program should print Hello world. If you tried to run the program, though,
you found that you could not. The VM emits an error message something like this:
Exception in thread "main" java.lang.NoSuchMethodError: main
If you're using the NetBeans IDE, the program would simply be prevented from running. You would receive the message No main classes found.
The VM can’t find the main method because it isn’t there. Although
Main has a method named main, it has the wrong signature. A main method
must accept a single argument that is an array of strings. What the
VM is struggling to tell us is that Main.main accepts an array of our String
class, which has nothing whatsoever to do with java.lang.String.
Conclusion : As mentioned above, always avoid reusing platform class names from the java.lang package.

Categories

Resources