How to get class field identifier as String in Groovy? - groovy

Suppose simple Groovy class (POGO):
class Person { String name; int age }
How to get chosen identifier at runtime? In other words identifier name (like "name" and "age") used in source code by programmer - not value held in variable of this identifier (like "James" and "32").
With result solution (if there is any) it would be possible to write something like this (syntactically wrong pseudo code):
assert new Person().name.identifierAsString == 'name'
assert new Person().age.identifierAsString == 'age'
Please note I'm not trying to get list of field names (like Person.declaredFields), but compile-time safe way to get field identifier as String.

I wrote a lib sometime ago to write type-checked queries. It might be what you are after:
import org.latitude.Latitude
Customer customer = Latitude.forClass Customer
assert customer instanceof Customer
assert customer.name == "name"

I'm not certain what you're trying to accomplish, but you can get all of the declared field names like so:
assert ['name', 'age'] == Person.declaredFields.findAll { !it.synthetic }.collect { it.name }
And otherwise declaredFields is a list of java.lang.reflect.Field that you can use.

Related

Unable to display the age of an object that was passed to a kotlin function

I'm just starting to learn kotlin and ran into a problem:
I have a Person class that has two fields
-age (Int data type)
-name (data type String)
there is also a oldUp function where I pass a Person object and increment the object's age field by 10.
Before the end of the program ** I want to display the age of the object that was passed to oldUp **
However, age is not shown.
my code:
class Person(var name: String, var age: Int){
}
fun growOld(human: Person){
human.age+=10
}
fun main(args: Array<String>) {
var human = Person("Kitty",6)
growOld(human)
println(human)
}
If you want to print the age, you can just write: println(human.age).
In your example it might be cleaner to add the growOld method to your class so you can call it on the object. For example:
class Person(var name: String, var age: Int){
fun growOld() {
this.age += 10
}
}
fun main() {
var human = Person("Kitty", 6)
println(human.age) // prints 6
human.growOld()
println(human.age) // prints 16
println(human.name) // prints Kitty
}
The problem is you're trying to print the human object itself. Under the hood, this calls its toString() method - every class has one of these, because it's defined on the type all classes derive from. If you don't override it and provide a nice way to "pretty print" your object, it'll use the default implementation, which is basically a reference to the object in memory.
A lot of classes you use have a nice toString() implementation, e.g. if you print a List you get ["something", "that", "looks", "like", "this"]. But that behaviour needed to be coded in - and you need to do that for your Person class too!
So you can override the default implementation like this:
override fun toString(): String {
// return a String here
}
override means you're taking an existing function and writing your own version of it to use instead - if this doesn't match an existing function you can override, you'll get an error. You'll also get an error if you don't use the override keyword for a function that looks exactly like an existing one in a supertype - it's just to make sure you don't accidentally do the wrong thing. In IntelliJ you can do Ctrl+O to override existing functions if you like.
So you could do something like this:
// inside your Person class
override fun toString(): String {
return "Name: $name, age: $age"
}
and then when you use it in a print statement, or in a string (like "Details: $person" or val details = "Details: " + person) it will call that toString() method and get the string you produced.
Another way to approach this is to use a data class:
data class Person(var name: String, var age: Int)
A data class is a special kind of class where all your "data" goes in the constructor (as properties, either val or var), and then you get some boilerplate stuff for free which uses those properties (and only those properties). Things like an equals() and hashCode() implementation that uses that data - and the relevant thing here, it gives you a toString() implementation that pretty prints name and age. Try it out!
Data classes can be really handy for simple data objects like you have here - but in normal classes, overriding toString() yourself is the general way of doing things. And you can still override a data class's toString if you want - sometimes you might want a more complex representation, or nice formatting, or you might want to only include some properties and ignore others. You're in control of how it prints itself!
And if you just want to print the age property, or print anything at all using the data in your object, then you just need to do what Robin's answer says. You don't need a toString() implementation at all for that (and since this is how you usually use objects, often you won't need to write a toString for your own classes at all)

Setting member variables by name in Spock

I am writing a Spock integration test for a function that takes a DTO, that has a lot of member variables. The functionality to test is that one user role is allowed to change some member variables, but if that user tries to change one of the other fields, it should fail.
I don't want to manually write a test for every single field, so I figured, I could be using a where: table like so:
where:
fieldname | value | isAccepted
"fieldA" | "val" | true
"fieldB" | "val" | false
...
For that, I'd have to be able to set the fields by the name in a string. In Java I'd have to use reflection for that. In Python I could just use setattr(object, fieldname, value) for that.
Since I writing the test in Groovy, is there something idiomatic for that?
Yes there is an idiomatic way to dynamically access fields an methods in groovy. You just use a GString to reference the field.
class A {
String foo = 200
String bar = 400
}
def a = new A()
def field = "foo"
println a."$field"
field = "bar"
println a."$field"
a."$field" = 600
println a.bar
Outputs
200
400
600
Test it in the Groovy Web Console

Does positive assert message exist in Groovy?

There is a Negative Groovy Assert with Message like:
def name = "John"
assert name == "Peter" : "Name should be John"
Which gives output:
Caught: java.lang.AssertionError: Name should be John. Expression: (name == Peter). Values: name = John
java.lang.AssertionError: Name should be John. Expression: (name == Peter). Values: name = John
But if the statement is true there is no information in the log. So when you (or your coworker) checks the log later (coworker does not know the checks you implemented) you have no idea about assertions which had place.
So I'd like to log positive assertions. Something like (adding positive message ? "Name is " + name):
def name = "Peter"
assert name == "Peter" : "Name should be John" ? "Name is " + name
Does it exists? I know I can log message after the assertion e.g.: log("Assert is correct: Name is " + name) but I'd like to do it in one line assertion.
There is no such thing like positive assertion message, because it does not make much sense in general. Let's consider example you have posted:
assert name == "Peter" : "Name should be John" ? "Name is " + name
When expression name == "Peter" evaluates to false it is straightforward what happens - java.lang.AssertionError is thrown with message Name should be John. Positive branch in this case is not straightforward - where does the message Name is ${name} should be log to? Using simple println or maybe using slf4j's log.info() or log.debug? Where is explicit decision about that? And what if I don't want to have such information in my logs, because it only produces overhead?
Of course you could define your own method like:
void doAssert(boolean expr1, String errorMessage, Closure<Void> onSuccess = null) {
assert expr : errorMessage
onSuccess?.call()
}
and then do:
doAssert name == "Peter", "Name should be John", {
log.info("Name is ${name}")
}
but in long term this might be an overkill - you create a closure object only for some debugging information. You can always modify this method and comment out onSuccess?.call() to limit some overhead created while calling a closure, although closure's object (and related Java anonymous class) gets created anyway.
But I guess you see that above method requires exactly same amount of effort as:
assert name == "Peter" : "Name should be John"
log.info("Name is ${name}")
I would rather suggest to use assertions as they were designed and don't produce much overhead. You can always log important information, but it has to be something that makes sense for maintainers. I don't see much value in getting informed that specific assertion was satisfied - I know that because program continued computations. Hope it helps you making right decision.

How to get count of a generic list in C# and no need to consider items with null or empty values in the count?

I need to get the count of a generic list in C#.No need to consider empty and null items in the count of list.
Below is my code
Public class Student
{
public string Name {get;set;}
public string Age {get;set;}
}
List<student> listStudent = new List<student>();
Student studentOne=new Student();
studentOne.Name="abc";
studentOne.Age="20";
listStudent.Add(studentOne);
Student studentTwo=new Student();
studentOne.Name="def";
studentOne.Age="22";
listStudent.Add(studentTwo);
Student studentThree=new Student();
studentOne.Name=" ";
studentOne.Age=null;
listStudent.Add(studentThree);
I have written below code to get the count
listStudent.count
It returns 3.it is correct as it contains 3 rows in the list.But I need to get the count of elements or items only having values. here in my code values in last item is null or empty.so I need to get count as 2.
Is there any built in method in c# to do the same. is there any way to check without using loops ?
LINQ can help here:
listStudent.Where(
s => !string.IsNullOrWhiteSpace(s.Name) && s.Age != null
).Count();
There is no method in framework that you are looking for. You need to create your own extended method to make this.

c# cast a value obtained from FieldInfo

Grade in an Enum Structure.
var y=1;
var x= (Grade)y;
I'm trying to do the same thing as the above line but with a dynamic CLASSNAME.
FieldInfo field = typeof(Person).GetField("Grade");
var x= Convert.ChangeType(y ,field.FieldType);
I tried that. this works fine but not for enums.
I think the problem is with the way you are accessing the field on the enum. Enum fields are static. By default, the Type.GetField method uses binding flags equivalent to BindingFlags.Public|BindingFlags.Instance. This won't match an enum member.
If this is the problem you are having, then you can use typeof(Person).GetField("Grade",BindingFlags.Public|BindingFlags.Static) to get the FieldInfo for the field named "Grade" on the enum type named "Person". This assumes that your model looks like:
enum Person
{
Grade
}
There's another problem with your code that is compatible with enums as well. It's not totally obvious because your example seems to treat "Grade" as both a field and an type. If my previous suggestion doesn't describe your model, and the following does, then the problem is that you are using Convert.ChangeType which in this case should give you an InvalidCastException.
You need to find a different way to cast the value to your enum. If the class name is not known at compile-time, then I would suggest using linq expressions, e.g.
Type targetEnumType = typeof(Person).GetField("Grade");
ConstantExpression runtimeValue = Expression.Constant(y);
UnaryExpression cast = Expression.Convert(runtimeValue,targetEnumType);
LambdaExpression lambda = Expression.Lambda(cast);
Delegate getTheCastValue = lambda.Compile();
object value = getTheCastValue.DynamicInvoke();
This code assumes that your model looks something like
class Person
{
public Grade Grade;
}
enum Grade
{
First = 1,
Second = 2
}
However, looking at this, it becomes obvious that if Person is a non-generic class, then you would have to know the type of the Grade field at runtime, so you are better off just doing a (Grade)y cast, like in your example.

Resources