class Parent {
final static String newLine = "*"
}
class Child extends Parent{
List body = [3, 4, 5]
String toString() {
def str = new StringBuilder()
body.each { str.append(it + newLine) }
str
}
}
def c = new Child()
println c
The above is one trivial sample to illustrate the problem. It couldn't be compiled using Groovy plugin on Eclipse. Remove either final or static in the field of super class solves the problem. However, I have no idea why it's the case.
http://groovy.codehaus.org/Groovy+Beans
In this link it mentions the rules for property and fields used in Groovy. I suppose the one applied should be the last one, i.e. meta class. Unfortunately, I still couldn't understand the behavior.
The behavior is reproduced consistently in all versions of Groovy. Maybe someone could report one bug to Groovy team. I have never done this before. It would be more efficient if someone experienced could do that.
This is most probably https://issues.apache.org/jira/browse/GROOVY-5776 which is more difficult to fix than it looks like
As blackdrag already pointed out: it's a bug.
But another workaround is to add the protected keyword:
protected final static String newLine = "*"
Related
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)
I have the following JUnit test:
public class JavaTest {
final int value = 2;
#Test
#Repeat(times = value)
public void test() {
fail("Not yet implemented");
}
}
The #Repeat annotation comes from easytest-core, and the exact definition is here.
When I compile this as java source everything builds (and runs) fine. When I compile the exact same thing as groovy source, I get:
Groovy:Attribute 'times' should have type 'java.lang.Integer'; but found type 'java.lang.Object' in #org.easetech.easytest.annotation.Repeat GroovyTest.groovy
After searching the internets, I found a few similar discussions on SO and jira.codehaus, but those deal with String - GString problems, so the solutions do not work for me.
How can I fix this?
Updates:
java.version=1.7.0_76
groovy.version=2.3.7
Think you're bumping into the fact groovyc doesn't treat final variables as inline constants like javac does
I tried changing your int variable like this:
final Integer value = Integer.valueOf(2).intValue()
which prevents the variable from being treated as an inline constant. After that change I get a compile error from the #Repeat annotation:
Expected Integer.valueOf(2).intValue() to be an inline constant
It looks like there's some acknowledgement of the inconsistency here in a Groovy JIRA: https://issues.apache.org/jira/browse/GROOVY-1628
There's also some further discussion here in this SO thread:
Does it make sense to mark variable as final in groovy?
It doesn't look like you're going to be able to get groovy to match the Java behavior for this scenario.
Expanding on this blog post, I am trying to use a category to create a simple DSL for use with the javax.measure (JSR-275) classes (similar to TimeCategory for time intervals)
However, I do not want to add boilerplate code for each of the possible available methods (getMeter, getMilliMeter, getKelvin, getSecond etc.). I thought overriding the getProperty(String) method would work, but alas, it looks like the getProperty method defined in the category is not used when accessing the property directly.
Here is some simplified code to demonstrate:
import javax.measure.quantity.Length;
import javax.measure.unit.Unit;
import javax.measure.Measure;
#Category(Number)
class LengthCategory {
public Measure<BigDecimal, Length> getProperty(String unit){
return Measure.valueOf(this,Unit.valueOf(unit));
}
}
use(LengthCategory){
println 3.getProperty("m") // this works
println 3.m // this reports a non-exisiting property
prinlln 3.'m' // as does this
}
Assuming other methods of dynamically adding properties to a runtime object (e.g. Expando, subclassing GroovyInterceptible, mixins and other metaclass manipulations) is not viable and I would really rather not have to manually code getters for every possible unit and SI prefix combination. There are obviously other ways to go about creating a DSL for measurements, but I would still like to understand why this method would not work.
Could someone explain why the getProperty method of the category does not override .propertyName usage? I am obviously missing something important about the resolution of property names using the metaclass during runtime.
I don't know why getProperty doesn't work on categories. But you can define a get method on them that does basically the same (i think). This works:
#Category(Number)
class LengthCategory {
def get(String unit) {
"$this $unit"
}
}
use (LengthCategory) {
println 3.m // 3 m
println 3.'m' // 3 m
}
As far as I can tell, you can't actually extend Integers with full (i.e., readable and writable) properties using Category -- only with methods.
You can extend an Integer using read-only properties by using the method version of the property. You can even make it writable by including a set method. However, there doesn't seem to be a way to store the value passed in other than in a static variable and that ends up affecting all Integers.
Example:
$ cat catprop
#!/usr/local/bin/groovy
#Category(Integer)
class CatInteger {
private static String str = "default"
public static String setN(Integer i, String _str) { str = _str }
public static String getN(Integer i) { return str }
}
use (CatInteger) {
3.n = "333a"
println "3.n is " + 3.n
3.n = "333b"
println "3.n is " + 3.n
4.n = "444"
println "4.n is " + 4.n
println "3.n is " + 3.n
}
$ catprop
3.n is 333a
3.n is 333b
4.n is 444
3.n is 444
$
Note that in the last line 3.n return "444" because the stored field is static. I suppose that one could use a private HashMap and store a value for every Integer accessed, but that's too ugly to contemplate.
Another possibility would be to use the MetaClass Interface's getProperty() and setProperty(). However, I haven't looked into that so I don't know if it would work or not (just a thought).
Nice answer, but not sure, if you's still want to use JSR-275 now that JSR-363 is final?;-)
I have been reading Groovy for a month or so. Recently i have came across the following code:
class MyBean implements Serializable {
def untyped
String typed
def item1, item2
def assigned = 'default value'
}
And when I do this :
def bean = new MyBean()
assert 'default value' == bean.getAssigned()
However the above code makes GroovyBeans very very impressive, but still my question is this:
Even though we haven't created the getter function(getAssigned()), groovy does for us. So is that groovy produce this for all class's even though we are not intended to work in GRoovyBeans? This means that for all class's it creates the setter and getter, even though we wont want? Is this is not the performance issue? Or else my view is worng?
Adding a method to a class won't cause a performance issue, as it doesn't have to be called.
If you want direct access to the property, you can use the Java field operator:
bean.#assigned
I'd like to re-implement a method of a Java class. For example, for "hi".length() to return 4. (How) Can I do that?
I know using SomeClass.metaClass I can get a reference to an existing method and define new (or overriding) method, but I can't seem to be able to do that for existing Java methods.
Using Groovy, you can replace any method (even those of final classes) with your own implementation. Method replacement in Groovy uses the meta-object protocol, not inheritance.
Here's the example you requested, i.e. how to make String.length() always return 4
// Redefine the method
String.metaClass.invokeMethod = { name, args ->
def metaMethod = delegate.metaClass.getMetaMethod(name, args)
def result = metaMethod.invoke(delegate, args)
name == 'length' ? 4 : result
}
// Test it
assert "i_do_not_have_4_chars".length() == 4
Seems like it could be possible by abusing String metaClass. But the attempt I've done so far in groovy console didn't led to the expected result :
def oldLength = String.metaClass.length
String.metaClass.length = { ->
return oldLength+10;
}
println "hi".length()
outputs the sad 2
I think you could take a look at Proxy MetaClass or Delegating metaClass.
If you did redefine it, it would only work in Groovy code. Groovy can't change the way Java code executes.
In Groovy, "hi".length() is roughly equivalent to this Java:
stringMetaClass.invokeMethod("hi","length");
Because Groovy doesn't actually call length directly, metaClass tricks work in Groovy code. But Java doesn't know about MetaClasses, so there is no way to make this work.
Although this question is very old I like to point out another way (at least for newer Groovy versions) .
The length() method in java.lang.String is implemented from java.lang.CharSequence interface. In order to reimplement the method using the String-metaClass you need to "override" the method in the metaClass of the interface first.
CharSequence.metaClass.length = { -> -1}
String.metaClass.length = { -> 4 }
assert "i_do_not_have_4_chars".length() == 4
The solution using String.metaClass.invokeMethod changes the behaviour of all String-methods and is problematic. For instance, simply invoking "asdf".size() leads to an exception on my setup.