Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Anyway to use AJ to _prevent_ field assignment at initialization of an object?

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<T> {
public abstract void doSomething();
}

package de.scrum_master.app;

public class CacheLookupUtil extends AbstractCacheLookupUtil<InvocationContext> {
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<InvocationContext> {
@Inject
private BeanManagerUtil beanManagerUtil;

private CacheKeyGenerator defaultCacheKeyGenerator = new DefaultCacheKeyGenerator();
private CacheResolverFactory defaultCacheResolverFactory = new DefaultCacheResolverFactory();

...
  ...
}

My problem is the assignment of the defaultCacheResolverFactory, or to be even more specific the construction of the DefaultCacheResolverFactory() without arguments when initializing the object.  The default constructor used throws an exception which is extremely difficult to catch given that the DI framework is instantiating the object.
 
Is there anyway I can use AspectJ to modify that assignment?  Ideally, I would like to prevent the construction of the DefaultCacheResolverFactory with no args, and replace it with a call to new DefaultCacheResolverFactory(CacheManager) instead.
 
So my issue is not just being able to assign the field (which I would be able to do in a CacheLookupUtil constructor advice, but also prevent the construction of the DefaultCacheResolverFactory().   
 
Can you think of any kind of pointcut(s) that I could use to catch that condition?  I figure I need an Around advice against a pointcut which picks up the constructor of the DefaultCacheResolverFactory (so I can return my own object instead), but from what I understand I cannot use around with the initialization pointcut.
 
Any suggestions what I can try?

Thanks,

Eric
 

Back to the top