Thanks for the great example Alexander.
But to make you SSCCE example more inline with what is happening, the
no-arg constructor for DefaultCacheResolverFactory should be throwing a
runtime exception.
Consequently, just using a set() alone will still throw the exception since
the no-arg cstor is still being called.
I can wrap the set() with a cflow() as you suggested and catch the
exception, but in an ideal world, I would rather prevent the call to the
no-arg cstor altogether.
So essentially, I would be looking at doing something like:
Around(cflow(initialization(CacheLookupUtil.new(..)) &&
call(DefaultCacheResolverFactory.new())){
return new DefaultCacheResolverFactory( new CacheManager();
}
I haven't tried that yet, but I believe it should get me where I need to
get.
Thanks,
Eric
On Thu, Aug 8, 2019, 9:48 PM Alexander Kriegisch I replicated your situation with dummy classes:
> --
>
> package de.scrum_master.app;
>
> public class InvocationContext {}
>
> --
>
> package de.scrum_master.app;
>
> public interface CacheResolverFactory {
> CacheManager getCacheManager();
> }
>
> --
>
> package de.scrum_master.app;
>
> public class DefaultCacheResolverFactory implements CacheResolverFactory {
> private CacheManager cacheManager = new CacheManager("default");
> public DefaultCacheResolverFactory() {
> System.out.println("DefaultCacheResolverFactory: no-args constructor");
> }
>
> public DefaultCacheResolverFactory(CacheManager cacheManager) {
> System.out.println("DefaultCacheResolverFactory: constructor with
> CacheManager");
> this.cacheManager = cacheManager;
> }
>
> @Override
> public CacheManager getCacheManager() {
> return cacheManager;
> }
> }
>
> --
>
> package de.scrum_master.app;
>
> public class CacheManager {
> private String name;
>
> public CacheManager(String name) {
> this.name = name;
> }
>
> @Override
> public String toString() {
> return "CacheManager [name=" + name + "]";
> }
> }
>
> --
>
> package de.scrum_master.app;
>
> public abstract class AbstractCacheLookupUtil {
> public abstract void doSomething();
> }
>
> --
>
> package de.scrum_master.app;
>
> public class CacheLookupUtil extends
> AbstractCacheLookupUtil {
> private CacheResolverFactory defaultCacheResolverFactory = new
> DefaultCacheResolverFactory();
>
> @Override
> public void doSomething() {
> System.out.println(defaultCacheResolverFactory.getCacheManager());
> }
>
> public static void main(String[] args) {
> new CacheLookupUtil().doSomething();
> }
> }
>
> --
>
> Now if you run that code, the console log says:
>
> DefaultCacheResolverFactory: no-args constructor
> CacheManager [name=default]
>
> No surprise here.
>
> Now you can use LTW (load-time weaving) and a set() pointcut like this:
> --
>
> package de.scrum_master.aspect;
>
> import de.scrum_master.app.CacheResolverFactory;
> import de.scrum_master.app.DefaultCacheResolverFactory;
> import de.scrum_master.app.CacheLookupUtil;
> import de.scrum_master.app.CacheManager;
>
> public aspect CacheResolverFactoryReplacer {
> void around(CacheResolverFactory cacheResolverFactory) :
> set(CacheResolverFactory CacheLookupUtil.*) &&
> args(cacheResolverFactory)
> {
> proceed(new DefaultCacheResolverFactory(new CacheManager("aspect")));
> }
> }
>
> --
>
> The console log changes to:
>
> DefaultCacheResolverFactory: no-args constructor
> DefaultCacheResolverFactory: constructor with CacheManager
> CacheManager [name=aspect]
>
> Now as you can see, the no-args resolver factory constructor is still
> executed but the resulting object is no longer assigned to the member
> because the advice proceeds with the object you want to be assigned instead.
>
> If you want to be very specific in your aspect and limit setting the
> member during constructor execution or object initialisation, you can
> always add && cflow(execution(CacheLookupUtil.new(..))) or &&
> cflow(initialization(CacheLookupUtil.new(..))) to your pointcut.
> --
> Alexander Kriegisch
> https://scrum-master.de
>
>
>
> Eric B schrieb am 08.08.2019 21:20:
>
> I'm using the JCache API, in which a design decision made by the JSR-107
> team in implementing the Reference Implementation is causing me a
> significant headache. The class in question is:
> org.jsr107.ri.annotations.cdi.CacheLookupUtil from package org.jsr107.ri:
> cache-annotations-ri-cdi:1.1.0.
>
> This is the layout of the class:
>
>
> public class CacheLookupUtil extends
> AbstractCacheLookupUtil {
> @Inject
> private BeanManagerUtil beanManagerUtil;
>
> private CacheKeyGenerator defaultCacheKeyGenerator = new
> DefaultCacheKeyGenerator();
> private CacheResolverFactory defaultCacheResolverFactory