Looping through class members and update member value in groovy - groovy

I have a question regarding loop through class members and update member value of the object in groovy:
class Test {
String a
String b
Test(String a, String b) {
this.a = a
this.b = b
}
String toString() {
return "a is " + a + " b is " + b
}
}
And I want to loop through the object member and update the value of the member:
class Testing {
static void main(String[] args) {
Test test = new Test("hello", "world")
test.properties.findAll {
it.value.toString.equals('hello')
}.each {
it.setValue("new value")
}
}
}
I try to change the value of "hello" to "new value", looks like it can find the member contains the "hello", but the value the same after it.setvalue(), how to change the value of the member in the object in correct way?

Changing properties does not affect field value change. If you want to find a field that stores specific value, like hello, and change it to something else, then you can try doing it with setProperty method invoked on test object.
Consider the following example:
class Testing {
static void main(String[] args) {
Test test = new Test("hello", "world")
test.properties.findAll {
it.value == 'hello'
}.each { field, _ ->
test.setProperty(field as String, "new value")
}
println test
}
}
Output:
a is new value b is world

Related

Problem using FormatStringConverter in ComboBox.setConverter in javafx

I have to use a combobox to associate a list of values (key, Value). Key is the value to be stored in the database, Value is the description to be displayed in the combobox.
For example:
Key / value
C1 Code one
C2 Choice two
C3 Choice three
...
Retrieving, for example, the selected value 'Choice two' I would like to receive the code C2.
For storing the elements in items I defined the ComboVal class.
Defining my combobox, I am stuck on the definition of the setConverter function.
The compiler gives me the following error:
Error: (1093, 49) java: constructor FormatStringConverter in class javafx.util.converter.FormatStringConverter cannot be applied to given types; required: java.text.Format; found: no arguments
reason: actual and formal argument lists differ in length
Code:
class ComboVal {
String[] dato = {null, null};
ComboVal (String Key, String Value)
{
setValue(Key, Value);
}
ComboVal ()
{
setValue(null, null);
}
String getValue ()
{
return dato[1];
}
String getKey ()
{
return dato[0];
}
void setValue (String Key, String Value)
{
dato[0] = Key;
dato[1] = Value;
}
}
classe myclass {
....
/*
Parameter ctrl is a List containing information for dynamic creation of combobox
*/
void mothod (List ctrl)
{
VBox box = new VBox();
box.getChildren().add(new Label(ctrl. label));
ObservableList items = FXCollections.observableArrayList();
ComboBox<ComboVal> cb = new ComboBox<>();
cb.setId(ctrl.name);
cb.setItems(items);
//----->>> compiler report error in the next row <<<<<<<<
cb.setConverter(new FormatStringConverter<ComboVal>() {
#Override
public String toString (ComboVal object)
{
return (object.getValue());
}
#Override
public ComboVal fromString (String string)
{
return null;
}
});
ctrl.options.forEach((k, v) -> {items.add(new ComboVal(k, v));});
cb.setCellFactory(new Callback<ListView<ComboVal>, ListCell<ComboVal>>() {
#Override
public ListCell<ComboVal> call (ListView<ComboVal> p)
{
return new ListCell<ComboVal>() {
#Override
protected void updateItem (ComboVal item, boolean empty)
{
super.updateItem(item, empty);
if (item == null || empty)
{
setGraphic(null);
}
else
{
setGraphic(new Text(item.getValue()));
}
}
};
}});
box.getChildren().add(cb);
}
The FormatStringConverter class needs to be constructed with a Format parameter. You however constructed it with no parameters.
Supply a Format, like this for example:
Format format = new MessageFormat("Bla bla");
cb.setConverter(new FormatStringConverter<ComboVal>(format);
The FormatStringConverter defines its own toString and fromString methods already, and will use the given format to parse and display the values. I doubt this is what you want as this is pretty limited.
So I think you'd be better of just using a regular StringConverter and provide the custom implementations for toString and fromString.

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!

How can I use a "String" to compare an "if" and "if else" statement?

The below code works just fine. But how can I get the user to input a string instead of and int to bring up either the "shop" or "inn" method?
ie. When "int a = navigate.nextInt();" is changed to "String a = navigate.nextString();" and the "if" and "if else" conditions are changed to "a == "shop" or "inn". The next line to run the correct method does nothing.
(I hope that made sense, see below)
import java.util.*;
public class ShopTest {
public static Scanner navigate = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("Where to?\n Shop (1)\n Inn (2)");
int a = navigate.nextInt();
if (a == 1)
Shop();
else if (a == 2)
Inn();
}
public static void Shop() {
System.out.println("Welcome to my shop\nWould you like to see my wares?");
}
public static void Inn() {
System.out.println("**You enter the inn and approach the barkeep**\nHow can I help you?");
}
}
Try this
System.out.println("Where to?\n Shop \n Inn ");
String a = navigate.nextLine();
if (a.equals("Shop"))
Shop();
else if (a.equals("Inn"))
Inn();
}
Use .equal
== tests for reference equality (whether they are the same object).
.equal tests for value equality (whether they are logically
"equal").
More: How do I compare strings in Java?

Groovy call field

I'm trying to put into the field an object that supports a call operation, and then to call him. I can do it without intermediate reading fields in a variable?
My attempt looks like this:
class CallableObjectDynamic {
def call() {
return "5"
}
}
class MyClassDynamic {
CallableObjectDynamic field = new CallableObjectDynamic()
}
class GroovyRunnerDynamic {
static String make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
return x.field()
}
}
​
But I receive groovy.lang.MissingMethodException.
What can you do? Or can anyone give a proof where it's written that we can't call the field?
Membership (.) has lower order of precedence than function/method/call invocation (()). Thus this line:
return x.field()
is interpreted as "invoke the 'field' method on the 'x' object".
To get Groovy to parse the code as you desire, the minimal change would be to regroup using parentheses, as follows:
return (x.field)()
which is (ultimately) interpreted as "invoke the 'call' method on the 'field' object member of the 'x' object", as desired.
It is trivial issue. Not required to have parenthesis for field.
Change from:
return x.field()
To:
return x.field
If you want to execute call method further, then use below code snippet.
Note that static method return type is changed.
class CallableObjectDynamic {
def call() {
return "5"
}
}
class MyClassDynamic {
CallableObjectDynamic field = new CallableObjectDynamic()
}
class GroovyRunnerDynamic {
static def make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
return x.field
}
}
​GroovyRunnerDynamic.make(1)​.call()​
Output would be : 5
Not sure why argument to make method is done here, seems to be not used in the above code.
Alternatively, you can change
class GroovyRunnerDynamic {
static def make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
return x.field.call()
}
}
​GroovyRunnerDynamic.make(1)
EDIT: Based on OP's implicit call.
Not really sure how it is working, but the below does implicit call. Just assign x.field to a variable and just add parenthesis for that as shown below.
class GroovyRunnerDynamic {
static String make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
def fun = x.field
fun()
}
}
GroovyRunnerDynamic.make(1)

How to use closure to capture the invocation by specific type and ignore others?

I have a mock with a method that can accept all children of an abstract type.In a test,this method may be invoked by different children multiple times,and I want to check that it is invoked by specific type once like this:
1*mockObject.method(_) {SpecificType ct->
//check the ct's field value
}
the problem is that the closure always capture the first invocation due to:
mockObjectt.method(_)
can't distinguish different children types,so it match all invocations,then I tried another way like this:
1*mockObject.method({it instanceof SpecificType}) {SpecificType ct->
//check the ct's field value
}
but the problem of this way is that:
{SpecificType ct->
//Here,any check will return true,
//I think the checkings in here are ignored
}
is ignored always(I think I misused the groovy's closure here)
So question is:
Is there elegant way to capture the invocation by specific child type with specific values and ignore others?
What about: 1*mockObject.method({it instanceof SpecificType && it.field == fieldValue }) ?
Take a look at this sample code:
import spock.lang.Specification
class SimpleTestSpec extends Specification {
private static class A { }
private static class B extends A { }
private static class C extends B { }
private static class D extends A { }
private static class TestClass {
String foo(A value) {
return "A: ${value}"
}
String foo(B value) {
return "B: ${value}"
}
String foo(C value) {
return "C: ${value}"
}
String foo(D value) {
return "D: ${value}"
}
}
private static class ComponentClass {
private final TestClass testClass
ComponentClass(TestClass testClass) {
this.testClass = testClass
}
String foo(A value) {
return testClass.foo(value)
}
}
TestClass testClassMock = Mock(TestClass)
ComponentClass componentClass = new ComponentClass(testClassMock)
def setup() {
testClassMock.foo(_ as D) >> "DDD"
testClassMock.foo(_ as C) >> "CCC"
testClassMock.foo(_ as B) >> "BBB"
testClassMock.foo(_ as A) >> "AAA"
}
def "should use mocked DDD result"() {
when:
String result = testClassMock.foo(new D())
then:
result == "DDD"
}
def "should use mocked CCC result"() {
when:
String result = testClassMock.foo(new C())
then:
result == "CCC"
}
def "should use mocked BBB result"() {
when:
String result = testClassMock.foo(new B())
then:
result == "BBB"
}
def "should use mocked AAA result"() {
when:
String result = testClassMock.foo(new A())
then:
result == "AAA"
}
def "should record invocation based on dynamic type"() {
when:
componentClass.foo(new C())
then:
1 * testClassMock.foo(_ as C)
}
def "should return result associated with mocked invocation in runtime"() {
when:
String result = componentClass.foo(new D())
then:
result == "DDD"
}
}
Gist file: https://gist.github.com/wololock/c59151b67d4c9b0c0c8e
You can specify expected type of an argument using as casting operator. But there is one tricky part - you need to stub class behavior in particular order: from most specific to most general. Try to mix the order in setup() and then you will see that tests will start failing.
You can also make use of Groovy's dynamic method invocation - notice how ComponentClass behaves with injectest TestClass instance which was previously stubbed with expected behavior. You can also count the number of invocations associated with specific type even if external call was made through the most general type method.
I hope it will help you resolve your problem. Best!

Resources