Enum value matching using AspectJ
September 25, 2008 2 Comments
I wrote an Aspect to advise a particular constant-specific method.
What is a constant-specific method ?
The J2SE 5 documentation explains it.
“You can declare the method abstract in the enum type and override it with a concrete method in each constant. Such methods are known as constant-specific methods.”
There is an example here.
The enum is
package com.test.generics; import java.util.Collection; import java.util.List; import java.util.Set; public enum TestEnum { Value1{ public <T> List<T> getValue(){ return null; } public <T> List<T> getSameValue(){ return null; } }, Value2{ public <T> Set <T>getValue(){ return null; } public <T> List<T> getSameValue(){ return null; } }; abstract <T> Collection<T> getValue(); abstract <T> Collection<T> getSameValue(); public static void main(String[] args) { System.out.println( Value1.getSameValue() ); System.out.println( Value2.getSameValue() ); } }
package com.test; import java.util.List; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import com.test.generics.TestEnum; @Aspect() public class EnumAspect { /* Matches a particular method of all enum values */ @Pointcut( "execution(List<T> getValue())" ) public void testPointcut(){}; @Before("testPointcut()") public void test() { System.out.println( "Generics aspect" ); } /* Matches a method of a particular enum values */ @Pointcut( "execution(List<T> getSameValue()) && target(testEnum) && if()") public static boolean testPointcut1( TestEnum testEnum ){ return testEnum == TestEnum.Value2; } @Before("testPointcut1(testEnum)") public void test1( TestEnum testEnum ) { System.out.println( "Generics aspect [" + testEnum.ordinal() + "]" ); } }
The if() pointcut expression with an empty body is used and the testPointcut1 method tests for the value of the enum. There does not seem to be a JoinPoint matching pattern to pick out certain enum values automatically. It looks like a pattern would be useful.
Update : Raised an enhancement request.
Update : 26 Oct 2020
One of the contributors who has commented here pointed out that this aspect works. I am not sure if this would have worked 12 years back when I raised the request. At that time I thought it was a missing feature.
@Aspect public class EnumAspect { @Pointcut("execution(java.util.Collection+ getValue()) && target(testEnum) && if()") public static boolean testPointcut1(TestEnum testEnum) { return testEnum == TestEnum.Value1; } @Before("testPointcut1(testEnum)") public void test1(JoinPoint joinPoint, TestEnum testEnum) { System.out.println(joinPoint + " -> " + testEnum); } @Pointcut("execution(java.util.Collection+ getValue()) && target(testEnum) && if()") public static boolean testPointcut2(TestEnum testEnum) { return testEnum == TestEnum.Value2; } @Before("testPointcut2(testEnum)") public void test2(JoinPoint joinPoint, TestEnum testEnum) { System.out.println(joinPoint + " -> " + testEnum); } }
What is the point of using generics here? It makes no sense to me at all. Like you said, both Value1 and Value2 are constants. How would you assign or use a specific class for during runtime? Your code does not show that at all and the methods return null. Please explain.
No purpose then. Years back when J2SE 5 was introduced I started testing code in eclipse and eclipse had bugs. Since I was interested in AspectJ I tried this code. Looked like I missed the syntax but at that time AspectJ may or may not have handled it. Not sure now. So it is test code that I used to find bugs in eclipse IDE.
But now when we use Enums in JPA( Hibernate ORM ) I need a pattern that switches the state of an entity. As a side effect of that I have to publish an event to AWS SQS. Now the same pattern is useful here. But in this case I don’t want constant-specific methods. I want to use an enum with an entire class so that the class can react when the state is switched.
That is the purpose now.