get/setProperty for POJOs

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

get/setProperty for POJOs

Basurita
Hi, I've been away from the Groovy world for some years.
As of recently, I've been trying to add some behavior to Groovy scripts embedded in a large Java codebase.
A few things that I "half-remembered" striked me as odd.
In this mail I want to ask about why Groovy does not honor certain methods for POJOs

My questions:
  * Why does Groovy NOT honor get/setProperty for pojos?
  * Why does it honor propertyMissing?

I'm sure there must be good/historical reasons for this incongruency, but I haven't been able to google a good answer.
And I don't think the answer will be "oh! we've never thought of that!" :-)
If it were up to me, I would honor both or none...

And I'm not looking for "solutions" that add those methods through a metaClass blah blah
I just would like a good rationale behind the way Groovy "naturally" handles properties for POJOs

thanks, bye!


For reference, I created a POJO and added the following:

// === a regular Java class: MyPojo.java
public class MyPojo {
  private int myProp= 88;
  private int myOtherProp= 44;

  public int getMyProp() {
    return myProp;
  }

  public Object getProperty(String name) {
    return 555;  // whatever
  }

  public Object propertyMissing(String name) {
    System.out.println("propertyMissing read "+name);
    return "hello";
  }
  public void propertyMissing(String name, Object value) {
    System.out.println("propertyMissing write "+name+"   val: "+value);
  }
}

// === and now from a groovy script

def p= new MyPojo()
assert p.myProp == 88       // called getMyProp()
assert p.myOtherProp == 44  // read directly

assert p.xxx == "hello"     // propertMissing(String) honored!
p.yyy = 2222                // prints  "propertyMissing write yyy   val: 222"

Reply | Threaded
Open this post in threaded view
|

Re: get/setProperty for POJOs

Jochen Theodorou
On 11.10.2017 19:11, Basurita wrote:

> Hi, I've been away from the Groovy world for some years.
> As of recently, I've been trying to add some behavior to Groovy scripts embedded in a large Java codebase.
> A few things that I "half-remembered" striked me as odd.
> In this mail I want to ask about why Groovy does not honor certain methods for POJOs
>
> My questions:
>    * Why does Groovy NOT honor get/setProperty for pojos?
>    * Why does it honor propertyMissing?
>
> I'm sure there must be good/historical reasons for this incongruency, but I haven't been able to google a good answer.
> And I don't think the answer will be "oh! we've never thought of that!" :-)
> If it were up to me, I would honor both or none...
>
> And I'm not looking for "solutions" that add those methods through a metaClass blah blah
> I just would like a good rationale behind the way Groovy "naturally" handles properties for POJOs

if we talk about foo.bar in Groovy then the semantics are the following
(simplified):

* Iff foo is a GroovyObject, call foo.getProperty("bar"). The default
implementation for this will use a property accessor to access the
property. This accessor is normally the getter method.
* Iff foo is no GroovyObject we go directly to the meta class.

In the meta class the process is roughly the following:

step 1: Iff there is a getter getBar use getBar unless the property has
been overwritten by meta programming
step 2: ... do some other things
step 3: Iff  step 1 and 2 do not apply and foo defines a
propertyMissing(String) method, use that to get the property

The effect is the following:

> class Foo {
>   def bar = 1
>   def getProperty(String name) {2}
> }
> assert new Foo().bar == 2

Even though we have a getBar method,we are not using it, we are using
the getProperty method. getProperty is called in the beginning of the
dispatch.

> class Foo {
>   def bar = 1
>   def propertyMissing(String name) {2}
> }
> assert new Foo().bar == 1

See how we here call the getBar method, even though you defined a
propertyMissing?

> class Foo {
>   def propertyMissing(String name) {2}
> }
> assert new Foo().bar == 2

> class Foo {
>   def getProperty(String name) {2}
> }
> assert new Foo().bar == 2

Only if the getter is missing the two seem to have the same semantics.
But even then it is not the case. propertyMissing can be added by meta
programming. For getProperty it must be a static method, which is then
called in Java fashion.

Can you see the difference now?

If you want a historic view on this... getProperty was there first and I
think back then the call to getProperty was actually hardcoded and
directly written into the file. This changed early on with
ScriptBytecodeAdapter, which catched more cases (foo is null for
example), but the call is still a java call. And the original idea was I
think if getProperty is there (it must be if it implements
GroovyObjects, which all Groovy classes do) you can have the same
semantics if you make the call from Java or from Groovy. propertyMissing
was added with the advent of Grails, that did need a fallback method.
This is not part of an interface, there is no Java based contract for
this and for Java to call directly, thus we made this much more
flexible. And I think in the future GroovyObject will (together with
set/getProperty and get/setMetaclass) go away... at least the methods in
there will.

[...]
> For reference, I created a POJO and added the following:

you added the POJO and marked how you want it to behave ;) That is
important, because it is, the program will fail to pass the asserts. Why
should be clear now I hope.
[...]

bye Jochen