views:

391

answers:

10

Is there a way to define a method, which is called everytime I call a get?

I have an Object Contact and don't want to set updateLastUsed(); in about 30 Getters for my Members.

+1  A: 

You can add in a call to every method (boring), or use some form of AOP (e.g. AspectJ, below for an example) to match the type's getters and call the updateLastUsed() method.

Edit: Several people have pointed out 30 getters is a code smell and invoking another method is a side effect. the first statement is a fair indicator, but not a rule. There could be many reasons to have this kind of type, without further information I'd leave it as advice to check if you can separate responsibilities into two or more types.

The other point about side effects may or may not be relevant. There are numerous cross-cutting concerns it makes sens to apply to getter methods. For example logging, authentication, and caching. The example method updateLastUsed() might be part of a caching strategy, so unqualified criticism of the question is undeserved in my opinion.

An example of how to implement the pointcut and advice in AspectJ is as follows:

package test;

public aspect TestAspect {
 /**
  * Match all getters of test.Contact and bind the target.
  */
    protected pointcut contactGetters(Contact contact) : 
     execution(* test.Contact.get*()) && target(contact);

    /**
  * Before execution of each getter, invoke the updateLastUsed() method
  * of the bound target.
  */
    before(Contact contact): contactGetters(contact) {
     contact.updateLastUsed();
    }     
}
Rich Seller
Having 30 getters is already passing the (boring) mark! ANYTHING you do with this class is going to be a nightmare, without business logic, there shouldn't be a class. If you have business logic, you shouldn't need the getters.
Bill K
+2  A: 

I would have suggested AOP but if it's J2ME we're talking about you're most likely better off manually inserting "onGetCalled()" in each of your 30 accessors and then coding whatever you need within that method. You may want to pass in name of the method being called (or property accessed) in case you need it in the future.

ChssPly76
+1  A: 

This looks like a job for Aspect Oriented Programming (AOP).

Defining an aspect to be executed for anything that starts with get*

The "new" AspectJ 5 stuff supports the use of annotations to define aspect pointcuts so you could annotate your getters to have call a pointcut @Before executing the body of the method.

dustmachine
+1  A: 

Something like AOP would be needed to do this. I don't know how well supported that is on J2ME other than this.

jsight
+1  A: 

Besides AOP, you could use a java.lang.reflect.Proxy, or bytecode manipulation...

But not on J2ME

I recommend calling updateLastUsed() 30 times.

ykaganovich
+3  A: 

Instead of accessing the getter for your properties, you could create one general getter that takes the property name as an input. The return type would need to be Object if your properties are of different types.

In this general getter you call the property getter and the updateLastUsed() method. To be safe make all property getters private.

Johannes
+1  A: 

Here's a way. It ain't pretty, but you might prefer it to the repetition:

public class GetterTest extends TestCase {
    private static class Thing {
     public int accessCount;
     private String name;
     private int age;

     private <T> T get(T t) {
      accessCount++;
      return t;
     }

     public String getName() {
      return get(name);
     }

     public int getAge() {
      return get(age);
     }
    }

    public void testGetIncrementsAccessCount() throws Exception {
     Thing t = new Thing();
     assertEquals(0, t.accessCount);
     t.getName();
     assertEquals(1, t.accessCount);
     t.getAge();
     assertEquals(2, t.accessCount);
    }
}

Obviously, my get() is just incrementing accessCount, and you'll want some other behavior, but the idea is there.

Carl Manaster
My Blackberry only supports Java 1.4 so there's not generic support. But like your sample. +1
Henrik P. Hessel
You can do it without generics by replacing T with object and adding a cast in all the getX methods.
Kathy Van Stone
Except for primitives (no autoboxing in 1.4).
Carl Manaster
+1  A: 

Use a regular expression to append the method call to the getter headers.

Find:

\w+ get\w+\s*\(\)\s*\{(\s*)

Replace with:

\0updateLastUsed();\1

These expressions were tested using Eclipse 3.5 (Galileo) using "Replace All" in the "Find/Replace" dialog.

Note that the editor you use must support multiline matching (or you have to enable it). For EmEditor 8.05, I had to modify the search string to be:

\w+ get\w+\s*\(\)\s*\{\s*(\n\s*)

so that the new line is matched explicitly. The replacement string remains as is.

Hosam Aly
+1  A: 

You could do something fancy, but honestly this is why macros were added to editors, so that you can quickly repeat boring code.

I would just make the method to be called by all the getters, and then use a macro to create the call (if it needed to differ by method). This all only has to be done once and then you just forget about it...

Kendall Helmstetter Gelner
A: 

I would say proxify the object to call the desired method.

John Doe