7

I have the concept of a SlowLoading thing:

public interface SlowLoading {
  boolean hasLoaded();
}

I also have a component MyComponent:

public interface myComponent{
  void doSomething();
}

My implementation covers both:

public class MyComponentImpl implements SlowLoading, MyComponent {
   // omitted for brevity
}

I have a container (interface omitted for brevity) which returns MyComponent:

public class MyContainerImpl implements MyContainer{
  @Inject private MyComponent component;

  @Override    
  public MyComponent doSomething(){
    // magic happens
    return myComponent;
  }
}

I also have an AOP component that intercepts the return of slow loading things and implicitly waits for them to load before returning:

@Pointcut("execution(SlowLoading+ *(..) )")
  public void returnsSlowLoadingThing() {
}

However, at present the MyContainer method is not proxied, since the return value does not implement SlowLoading.

What is the best way to encapsulate this behaviour?

Options I've considered:

  • Make MyComponent extend SlowLoading. This feels like a code smell and breaking of encapsulation - bleeding implementation into the interface. A client does not care if it is slow loading or not.
  • Inject MyComponentImpl directly into my container and return it explicitly (co-variant returns). Again, this feels like it is breaking encapsulation and the point of programming to interfaces, but feels better than the above, since it is done at a lower level and hidden behind the interface (implementation detail). However it is breaking the encapsulation of the AOP functionality which should be orthogonal and transparent.
  • Perform the AOP wait before invoking a method on a SlowLoading thing. This seems the most appropriate, but I've not been able to get this working so far.

migrated from codereview.stackexchange.com May 15 '14 at 3:51

This question came from our site for peer programmer code reviews.

1

How about intercepting every Method of Container subclasses that return Objects?

The advantage of this approach is that your core interfaces don't need to now anything about the "SlowLoading" concept. One disadvantage on the other hand is that you may intercept more calls than necessary - which may or may not a problem for your use-case.

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TransparentLoading {

    @Pointcut("execution(public Object+ Container.*(..))")
    public void executionOfObjectReturningContainerMethod(){}

    @Around("executionOfObjectReturningContainerMethod()")
    public Object performLazyLoadingIfNecessary(ProceedingJoinPoint joinPoint) throws Throwable{

        Object result = joinPoint.proceed();

        if(result instanceof SlowLoading){
            result = ensureLoaded((SlowLoading)result);
        }

        return result;
    }

    public static Object ensureLoaded(SlowLoading result) {

        if(!result.isLoaded()){
            result.load();
        }

        return result;
    }
}
  • This seems a good approach, which still helps to maintain the encapsulation with the obvious tradeoff in performance. The additional overhead should not be an issue for my case at this time. – Tim Jul 25 '14 at 1:12
0

i think this is not the best example for AOP.

It seems it would have to break encapsulation, possible workarounds may be:

A. Use 2 more interfaces that cover the 2 cases of SlowLoading (either wait or not-wait) and use one of these interfaces in the AOP cut

B. Not use AOP at all for this functionality and use 2 interfaces (as above) that handle different cases of SlowLoading (wait and block or not-wait and proxy). This would also make use of some factory pattern to get the correct SlowLoading instance (either wait or non-block)

  • I don't think this is suitable because the MyComponent interface is not related to SlowLoading (purely an implementation detail). In addition, this approach would not scale as the number of components increase (I have lots of different component interfaces that are also slow loading). Or have I mis-understood your answer? – Tim Jul 25 '14 at 1:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.