Does Groovy "as" operator create a subclass at run time for User defined classes? - groovy

In Groovy When I write the below code in a groovy script.
class Emp {
public String getId() {
return "12345";
}
}
def coercedInstance = [
getId: {
"99999"
}
] as Emp
println new Emp().getId()
println coercedInstance .getId()
Using the as Operator here, am I creating a sub class of the actual Emp class at runtime and providing the method body at run time?
I have seen other stack overflow articles and i have learnt that Groovy uses DefaultGroovyMethods.java & DefaultTypeTransformation.java to do the coercion. But could not figure out if it was subclassing or not.

Yes, an as operator creates an object which type is a subclass of the target class. Using DefaultGroovyMethods.asType(Map map, Class clazz) generates (in a memory) a proxy class that extends given base class.
class Emp {
public String getId() {
return "12345";
}
}
def coercedInstance = [
getId: {
"99999"
}
] as Emp
assert (coercedInstance instanceof Emp)
assert (coercedInstance.class != Emp)
assert (Emp.isAssignableFrom(coercedInstance.class))
println coercedInstance.dump() // <Emp1_groovyProxy#229c6181 $closures$delegate$map=[getId:coercion$_run_closure1#7bd4937b]>
What happens in your case specifically is the following:
The asType method goes to line 11816 to execute ProxyGenerator.INSTANCE.instantiateAggregateFromBaseClass(map, clazz);
In the next step, ProxyGeneratorAdapter object gets created.
In the last step, adapter.proxy(map,constructorArgs) gets called to return a newly generated class that is a proxy of the base class.

Related

Implicit assert statement in Groovy

Given I have JUnit tests written in Groovy:
class AssertTests {
#Test
void "explicit assert statement"() {
def value = 42
assert value == 100
}
#Test
void "no assert statement"() {
def value = 42
value == 100
}
}
When I execute them,
explicit assert statement test fails as expected thanks to assert statement.
no assert statement test passes and I would expect it to fail in a similar way how it's done when I use http://spockframework.org
How can I achieve implicit assert behavior for tests written in plain Groovy?
The answer is simple - you can't. Spock uses AST transformations to grab the code written in the then: part and transform it into the code that makes an equivalent of assertion (not the exact assert.)
To illustrate this, here is your test written in Spock:
import spock.lang.Specification
class TestSpec extends Specification {
def "should fail"() {
when:
def value = 42
then:
assert value == 100
}
}
And here is what its bytecode decompiled back to Java looks like:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.GroovyObject;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;
import org.spockframework.runtime.ErrorCollector;
import org.spockframework.runtime.SpockRuntime;
import org.spockframework.runtime.ValueRecorder;
import org.spockframework.runtime.model.BlockKind;
import org.spockframework.runtime.model.BlockMetadata;
import org.spockframework.runtime.model.FeatureMetadata;
import org.spockframework.runtime.model.SpecMetadata;
import spock.lang.Specification;
#SpecMetadata(
filename = "TestSpec.groovy",
line = 5
)
public class TestSpec extends Specification implements GroovyObject {
public TestSpec() {
CallSite[] var1 = $getCallSiteArray();
super();
}
#FeatureMetadata(
line = 7,
name = "should fail",
ordinal = 0,
blocks = {#BlockMetadata(
kind = BlockKind.WHEN,
texts = {}
), #BlockMetadata(
kind = BlockKind.THEN,
texts = {}
)},
parameterNames = {}
)
public void $spock_feature_0_0() {
CallSite[] var1 = $getCallSiteArray();
ErrorCollector $spock_errorCollector = (ErrorCollector)ScriptBytecodeAdapter.castToType(var1[0].callConstructor(ErrorCollector.class, false), ErrorCollector.class);
ValueRecorder $spock_valueRecorder = (ValueRecorder)ScriptBytecodeAdapter.castToType(var1[1].callConstructor(ValueRecorder.class), ValueRecorder.class);
Object var10000;
try {
Object value = 42;
try {
SpockRuntime.verifyCondition($spock_errorCollector, $spock_valueRecorder.reset(), "value == 100", Integer.valueOf(12), Integer.valueOf(16), (Object)null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(Integer.valueOf(2)), ScriptBytecodeAdapter.compareEqual($spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(Integer.valueOf(0)), value), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(Integer.valueOf(1)), 100))));
var10000 = null;
} catch (Throwable var14) {
SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, "value == 100", Integer.valueOf(12), Integer.valueOf(16), (Object)null, var14);
var10000 = null;
} finally {
;
}
var1[2].call(var1[3].call(this.getSpecificationContext()));
} finally {
$spock_errorCollector.validateCollectedErrors();
var10000 = null;
}
}
}
If you look at the SpockRuntime class, you will find that verifyCondition method checks if the condition found in the then: or and: block evaluates to true:
public static void verifyCondition(#Nullable ErrorCollector errorCollector, #Nullable ValueRecorder recorder,
#Nullable String text, int line, int column, #Nullable Object message, #Nullable Object condition) {
if (!GroovyRuntimeUtil.isTruthy(condition)) {
final ConditionNotSatisfiedError conditionNotSatisfiedError = new ConditionNotSatisfiedError(
new Condition(getValues(recorder), text, TextPosition.create(line, column), messageToString(message), null, null));
errorCollector.collectOrThrow(conditionNotSatisfiedError);
}
}
You can't avoid explicit assert in JUnit tests. You can hide them in some helper method, but you still need to call them. Keep in mind, that JUnit runner requires that the test method returns void, so you can't capture the result of a test method. (Replace void with def, and you will see that JUnit does not run your test.)
If you want to explore the world of compile-time metaprogramming in Groovy, you could experiment with writing your own AST transformations. Maybe there is a way to find boolean expression(s) and inject assert in front of it, but I can't guarantee you that it will work. If you look for an out-of-the-box solution for implicit asserts in Groovy JUnit tests, there is no such one.

What is the static version of propertyMissing method in Groovy?

ok - tried looking /reading and not sure i have an answer to this.
I have a Utility class which wraps a static ConcurrentLinkedQueue internally.
The utility class itself adds some static methods - i dont expect to call new to create an instance of the Utility.
I want to intercept the getProperty calls the utility class - and implement these internally in the class definition
I can achieve this by adding the following to the utility classes metaclass, before i use it
UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure.'Each'
however what i want to do is declare the interception in the class definition itself. i tried this in the class definition - but it never seems to get called
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
i also tried
static def getProperty (String prop) { println "accessed $prop"}
but this isnt called either.
So other than adding to metaClass in my code/script before i use, how can declare the in the utility class that want to capture property accesses
the actual class i have looks like this at present
class UnitOfMeasure {
static ConcurrentLinkedQueue UoMList = new ConcurrentLinkedQueue(["Each", "Per Month", "Days", "Months", "Years", "Hours", "Minutes", "Seconds" ])
String uom
UnitOfMeasure () {
if (!UoMList.contains(this) )
UoMList << this
}
static list () {
UoMList.toArray()
}
static getAt (index) {
def value = null
if (index in 0..(UoMList.size() -1))
value = UoMList[index]
else if (index instanceof String) {
Closure matchClosure = {it.toUpperCase().contains(index.toUpperCase())}
def position = UoMList.findIndexOf (matchClosure)
if (position != -1)
value = UoMList[position]
}
value
}
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
//expects either a String or your own closure, with String will do case insensitive find
static find (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def inlist = UoMList.find (matchClosure)
}
static findWithIndex (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
else if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def position = UoMList.findIndexOf (matchClosure)
position != -1 ? [UoMList[position], position] : ["Not In List", -1]
}
}
i'd appreciate the secret of doing this for a static utility class rather than instance level property interception, and doing it in class declaration - not by adding to metaClass before i make the calls.
just so you can see the actual class, and script that calls - i've attached these below
my script thats calling the class looks like this
println UnitOfMeasure.list()
def (uom, position) = UnitOfMeasure.findWithIndex ("Day")
println "$uom at postition $position"
// works UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure[4]
println UnitOfMeasure.'Per'
which errors like this
[Each, Per Month, Days, Months, Years, Hours, Minutes, Seconds]
Days at postition 2
Years
Caught: groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
at com.softwood.scripts.UoMTest.run(UoMTest.groovy:12)
Static version of propertyMissing method is called $static_propertyMissing:
static def $static_propertyMissing(String name) {
// do something
}
This method gets invoked by MetaClassImpl at line 1002:
protected static final String STATIC_METHOD_MISSING = "$static_methodMissing";
protected static final String STATIC_PROPERTY_MISSING = "$static_propertyMissing";
// ...
protected Object invokeStaticMissingProperty(Object instance, String propertyName, Object optionalValue, boolean isGetter) {
MetaClass mc = instance instanceof Class ? registry.getMetaClass((Class) instance) : this;
if (isGetter) {
MetaMethod propertyMissing = mc.getMetaMethod(STATIC_PROPERTY_MISSING, GETTER_MISSING_ARGS);
if (propertyMissing != null) {
return propertyMissing.invoke(instance, new Object[]{propertyName});
}
} else {
// .....
}
// ....
}
Example:
class Hello {
static def $static_propertyMissing(String name) {
println "Hello, $name!"
}
}
Hello.World
Output:
Hello, World!

Error Caught: groovy.lang.GroovyRuntimeException: This script or class could not be run

Recently encountered with this problem- when i had two class in one groovy class if main method class is not on the top i encountered this problem.
class Book {
private String name
void setName(String bookName) {
name=bookName
print "Book Name => "+bookName+"\n";
}
String getName(){
return name;
}
}
class TestClass {
static main(args) {
Book t = new Book();
t.setName("First Book");
print "book title=>"+t.getName()+"\n"
}
}
But if change the order of these two class than there is no error, does it mean main method class should be on top in Groovy ?
Yes, order of classes matter in a groovy script. If you parse a groovy script and check its class name, it would the top level class and not the one with main method or one that have same name as the name of the file. It could be a concrete class, an abstract class, an enum, an interface or trait.
Lets see your case. We are going to put your code inside a GString and then will try to parse it using our own GroovyClassLoader.
String script = """
class Book {
private String name
void setName(String bookName) {
name=bookName
print "Book Name => "+bookName+"\\n";
}
String getName(){
return name;
}
}
class TestClass {
static main(args) {
Book t = new Book();
t.setName("First Book");
print "book title=>"+t.getName()+"\\n"
}
}
"""
GroovyClassLoader loader = new GroovyClassLoader()
GroovyCodeSource codeSource = new GroovyCodeSource(script, "MyClass", GroovyShell.DEFAULT_CODE_BASE)
println loader.parseClass(codeSource)
When you will execute this code it will print class Book. Because this is the first available class in your script.
The exception you are getting is because that your top level class doesn't have a main method and neither your script have something to execute after you have loaded your classes. One solution is to move TestClass at top or just add another line at the end of the file TestClass.main() and it will execute without any issues.

groovy immutable object with parent class

I have two immutable groovy classes that have a few shared values that I'm trying to abstract to a parent class. However when I create the following, the second test case always fails. Although everything compiles correctly and no error is thrown at runtime, when I assign the parent property int he constructor, it is never set, resulting in a null value. I havent found any documentation that forbids this, but I'm wondering is this even possible? I've tried a number of configuration of Annotations and class-types (e.g. removing abstract from the parent) but nothing seems to work short of just removing the #Immutable tag altogether.
abstract class TestParent {
String parentProperty1
}
#ToString(includeNames = true)
#Immutable
class TestChild extends TestParent {
String childProperty1
String childProperty2
}
class TestCase {
#Test
void TestOne() {
TestChild testChild = new TestChild(
childProperty1: "childOne",
childProperty2: "childTwo",
parentProperty1: "parentOne"
)
assert testChild
assert testChild.parentProperty1
}
}
Based on the code for the ImmutableASTTransformation, the Map-arg constructor added by the createConstructorMapCommon method does not include a call to super(args) in the method body.
which means that immutable classes are self contained by default
Now if you want to do it you need to use composition instead of inheritance and this is an example of how you can do it :
import groovy.transform.*
#TupleConstructor
class A {
String a
}
#Immutable(knownImmutableClasses=[A])
class B {
#Delegate A base
String b
}
def b = new B(base: new A("a"), b: "b")
assert b.a
i hope this will help :)

Call groovy script

Hi i have written groovy script like:
class Test{
public Object testComposedRules() {
String ruleACode = {age, product -> def discount = 0; if(age<10 && product=="Toys") discount=10; println "hi $discount"; return discount};
Closure ruleA = (Closure) Eval.me(ruleACode);
Object object = ruleA.call(9, "Toys");
return object;
}
}
when i tried to access this class from another main class; i cant get the test class
public static void main() {
Test a = new Test();
a.testComposedRules();
}
i m getting error it does not exists; is there any way to access groovy functions from java class;
I assume the case difference of A in definition and call is a typo in the question?
If not, try A.testComposedRules();

Resources