I have the following scenario:
Spring 3.2
EHCache
A superclass that can not be modified (inside a jar), with a structure similar to this:
public abstract class SuperClass<E extends Object> implements SuperIface<E> {
public void insert(E entity) {
}
}
A subclass, (can be modified), with this structure and a little more complex condition in #CacheEvict
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
#Service
#CacheEvict(value = "entityCache", allEntries = true, condition = "'insert'.equals(#root.methodName)")
public class SubClass extends SuperClass<Entity> implements ISubIface {
public void anotherMethod() {
}
}
Is there any option to say Spring to make effective #CacheEvict annotation when insert method of SuperClass is invoked? In other words, Can I remove cache entries when insert method is invoked from a SubClass instance?
Note that I'm looking for the way to do it via configuration. I know that I can override superclass' methods in subclass, but for some circumstances (another logic in superclass) I prefer not to do that.
You can create cache advices on any class you want using xml configuration if you can't change the source.
Having said that, your example does not make much sense to me: the class is abstract so you actually need an implementation to invoke that method. Are you saying that you have multiple implementations and you want all these implementations to have a CacheEvict behaviour? If you only have one, I don't see the problem of having an override that merely call super + the annotation.
Related
As we all know, the self-invokation of bean's method is not working in Spring without AspectJ.
See this question for example.
I think this is because the Spring-created proxy calls the target object's methods using delagate pattern. Like this:
class MyClass {
#Autowired
private MyClass self; // actually a MyProxy instance
#Transactional // or any other proxy magic
public void myMethod() {}
public void myOtherMethod() {
this.myMethod(); // or self.myMethod() to avoid self-invokation problem
}
}
class MyProxy extends MyClass { // or implements MyInterface if proxyMode is not TARGET_CLASS and MyClass also implements MyInterface
private final MyClass delegate;
#Override
public void myMethod() {
// some proxy magic: caching, transaction management etc
delegate.myMethod();
// some proxy magic: caching, transaction management etc
}
#Override
public void myOtherMethod() {
delegate.myOtherMethod();
}
}
Am I right?
With this code:
public void myOtherMethod() {
this.myMethod();
}
this.myMethod() will bypass the proxy (so all #Transactional or #Cacheable magic) because it is just internal delegate's call... So we should inject a MyClass bean (which is actually is MyProxy instance) inside MyClass and call self.myMethod() instead. It is understandable.
But why the proxy is implemented this way?
Why it is not just extends the target class, overriding all public methods and calling super instead of delegate?
Like this:
class MyProxy extends MyClass {
// private final MyClass delegate; // no delegate
#Override
public void myMethod() {
// some proxy magic: caching, transaction management etc
super.myMethod();
// some proxy magic: caching, transaction management etc
}
#Override
public void myOtherMethod() {
super.myOtherMethod();
}
}
It should solve the self-invokation problem, where this.myMethod() bypasses the proxy, because in this case this.myMethod(), invoked from MyClass.myOtherMethod() (we remember that MyClass bean actually is MyProxy instance), will invoke overriden child's method (MyProxy.myMethod()).
So, my main question is why it is not implemented this way?
Your assumption that Spring AOP uses delegation for its proxies is correct. This is also documented.
Using CGLIB, you can theoretically use proxy.invokeSuper() in order to achieve the effect you want, i.e. that self-invocation is registered by the aspect implemented by the proxy's method interceptor (I am using Spring's embedded version of CGLIB here, thus the package names):
package spring.aop;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
class SampleClass {
public void x() {
System.out.println("x");
y();
}
public void y() {
System.out.println("y");
}
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor() {
#Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
if(method.getDeclaringClass() == Object.class)
return proxy.invokeSuper(obj, args);
System.out.println("Before proxy.invokeSuper " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After proxy.invokeSuper " + method.getName());
return result;
}
});
SampleClass proxy = (SampleClass) enhancer.create();
proxy.x();
}
}
Console log:
Before proxy.invokeSuper x
x
Before proxy.invokeSuper y
y
After proxy.invokeSuper y
After proxy.invokeSuper x
This is exactly what you want. The problem starts, however, when you have several aspects: transactions, logging, whatever else. How do you make sure that they all work together?
Option 1: Each aspect gets its own proxy. This obviously will not work unless you nest the proxies into each other according to aspect precedence. But nesting them into each other means inheritance, i.e. one proxy would have to inherit from the other outside-in. Try proxying a CGLIB proxy, it does not work, you get exceptions. Furthermore, CGLIB proxies are quite expensive and use perm-gen memory, see descriptions in this CGLIB primer.
Option 2: Use composition instead of inheritance. Composition is more flexible. Having one proxy to which you can register aspects as needed solves the inheritance problem, but also means delegation: The proxy registers the aspects and calls their methods during runtime in the right order before/after the actual real object's code is executed (or not, if an #Around advice never calls proceed()). See this example from the Spring manual about manually registering aspects to a proxy:
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// add an aspect, the class must be an #AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existing aspect instances, the type of the object supplied must be an #AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();
As to why the Spring developers chose this approach and whether it might have been possible to use the one-proxy approach but still make sure that self-invocation works like in my little CGLIB sample "logging aspect" above, I can only speculate. You can maybe ask them on the developers mailing list or look into the source code. Maybe the reason was that CGLIB proxies should behave similarly to the default Java dynamic proxies so as to make switching between the two for interface types seamless. Maybe the reason is another one.
I did not mean to be rude in my comments, only straightforward, because your question is really not suited to StackOverflow because it is not a technical problem to which someone can find a solution. It is a historical design question and rather philosophic in nature because with AspectJ a solution to your technical problem (self-invocation) beneath the actual question already exists. But maybe you still want to dive into the Spring source code, change the Spring AOP implementation from delegation to proxy.invokeSuper() and file a pull request. I am not sure such a breaking change would be accepted, though.
In addition, you will not able to use Inheritance + super in the following cases:
What about if the RealSubject is final, so the proxy will can NOT extends it
What about if the Proxy needs to extend something other than the RealSubject
What about if you need to hide some functionality (methods) inside the RealSubject
Prefer Composition over Inheritance (recommended by many developers)
I'm using 2 common packages, Immutables and
Guice. The very first thing that happens at runtime is I load setting from environment and other sources into settings into a singleton, non-Immutable config class, let's call it MyConfig, that for example, exposes a public getSettingX() method.
MyConfig myConfig = MyConfig.intialize().create();
String settingX = myConfig.getSettingX();
I have one abstract Immutable class, call it AbstractImmutable. that at instantiation needs to set a field based on the myConfig.getSettingX().
#Value.Immutable
abstract class AbstractImmutable {
abstract String getSettingX(); // Ideally set
}
Now, typically I inject MyConfig into classes using Guice, and would liket to figure a way to do this for implementations of the AbstractImmutable class (to avoid manually having to inject the MyConfig class every time I build an object--whole reason using juice to begin with, to manage my DI). However, since the concrete Immutables classes are generated at compile, it doesn't to work with the usual Guice injection annotations.
There's indication on the Immutables site of using the builder package to annotate a static factory method, but I can't seem to figure how to add this to the abstract immutable class.
Anyone have any suggestions?
To my knowledge, there is no way to do this on the generated Immutables class itself (though there may be some funny stuff you could do with #InjectAnnotation), so you may be out of luck there.
Even though you are asking under the guise of Guice, what you are asking for reminds me of the pattern that AutoFactory uses, and should be similarly applicable. In essence, take advantage of the Factory Pattern by injecting into the factory and then the factory will create the Immutable object.
For example, specifically referring to your case,
#Value.Immutable
abstract class ValueObject {
MyConfig getMyConfig();
#Value.Derived
String getSettingX() {
getMyConfig().getSettingX();
}
String getAnotherProperty();
class ValueObjectFactory {
#Inject MyConfig myConfig;
ValueObject create(String anotherProperty) {
return ImmutableValueObject.builder()
.setMyConfig(this.myConfig)
.setAnotherProperty(anotherProperty)
.build();
}
}
}
Then, in the application code, you would inject the ValueObjectFactory directly and call create on it as
class SomeApplicationClass {
#Inject ValueObjectFactory factory;
void someMethod() {
ValueObject = factory.create("myString");
// ... do something with the ValueObject
}
}
Similarly, you could define your factory as a builder, but that will be a decision you will have to make based on the number of parameters you have.
I'm trying to use Spring Cache within abstract classes but it won't work, because, from what I can see, Spring is searching for CacheNames on the abstract class. I'm having a REST API which uses a service layer and a dao layer. The idea is to have a different cache name for every subclass.
My abstract service class looks like this:
#Service
#Transactional
public abstract class AbstractService<E> {
...
#Cacheable
public List<E> findAll() {
return getDao().findAll();
}
}
An extension of the abstract class would look like this:
#Service
#CacheConfig(cacheNames = "textdocuments")
public class TextdocumentsService extends AbstractService<Textdocuments> {
...
}
So when I start the application with this code, Spring gives me the following exception:
Caused by: java.lang.IllegalStateException: No cache names could be detected on 'public java.util.List foo.bar.AbstractService.findAll()'. Make sure to set the value parameter on the annotation or declare a #CacheConfig at the class-level with the default cache name(s) to use.
at org.springframework.cache.annotation.SpringCacheAnnotationParser.validateCacheOperation(SpringCacheAnnotationParser.java:240) ~[spring-context-4.1.6.RELEASE.jar:?]
I think this happens because Spring is searching for the CacheName on the abstract class, despite it is being declared on the subclass.
Trying to use
#Service
#Transactional
#CacheConfig
public abstract class AbstractService<E> {
}
leads to the same exception; using
#Service
#Transactional
#CacheConfig(cacheNames = "abstractservice")
public abstract class AbstractService<E> {
}
gives no exception, but then Spring Cache uses the same cache name for every subclass and ignores the cache name defined on the subclass. Any Ideas to so solve this?
This problem has been addressed in another question and is less about abstract classes and more about the framework's ability to figure out which cache to use.
Long story short (quoting from Spring documentation) you are missing appropriate CacheResolver that will work with your abstract class hierarchy:
Since Spring 4.1, the value attribute of the cache annotations are no longer mandatory, since this particular information can be provided by the CacheResolver regardless of the content of the annotation.
Therefore, your abstract class should define a caching resolver instead of directly stating the cache name.
abstract class Repository<T> {
// .. some methods omitted for brevity
#Cacheable(cacheResolver = CachingConfiguration.CACHE_RESOLVER_NAME)
public List<T> findAll() {
return getDao().findAll();
}
}
The resolver determines the Cache instance(s) to use for an intercepted method invocation. A very naive implementation can take the target repository bean (by name) and use it as the cache name
class RuntimeCacheResolver
extends SimpleCacheResolver {
protected RuntimeCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
#Override
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
return Arrays.asList(context.getTarget().getClass().getSimpleName());
}
}
Such resolver needs an explicit configuration:
#Configuration
#EnableCaching
class CachingConfiguration extends CachingConfigurerSupport {
final static String CACHE_RESOLVER_NAME = "simpleCacheResolver";
#Bean
#Override
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
#Bean(CACHE_RESOLVER_NAME)
public CacheResolver cacheResolver(CacheManager cacheManager) {
return new RuntimeCacheResolver(cacheManager);
}
}
I've create a Gist which describes the whole concept in more details.
Disclaimer
The above snippets are just for demonstration and are intended to give direction than to provide a complete solution. The above cache resolver implementation is very naive and doesn't consider many things (like method parameters etc.). I'd never use it in a production environment.
The way Spring handles caching is through proxies, where the #Cacheable annotation declares the cache, together with naming information processed on runtime. The cache is resolved through runtime information provided to cache resolver (no surprise it resembles some similarities to InvocationContext of classical AOP).
public interface CacheOperationInvocationContext<O extends BasicOperation> {
O getOperation();
Object getTarget();
Method getMethod();
Object[] getArgs();
}
Through the getTarget() method it is possible to figure out which bean is proxied, but in real-life, more information should be taken into account, to provide a reliable cache (like method parameters, etc).
I have an interface like this:
public interface IFoo{
#AnnotationTest(param="test")
String invoke();
}
and I implement this like this:
public class Foo implements IFoo{
#Override
public String invoke(){
Method method = new Object() {
}.getClass().getEnclosingMethod();
AnnotationTest ann = method.getAnnotation(AnnotationTest.class);
if(ann == null){
System.out.printl("Parent method's annotation is unreachable...")
}
}
}
If it is possible to reach parent's annotation, I want to learn the way of it.
Any help or idea will be appreciated.
You can use Spring AnnotationUtils.findAnnotation to read annotations from interfaces.
Example :
Interface I.java
public interface I {
#SomeAnnotation
void theMethod();
}
Implementing class A.java
public class A implements I {
public void theMethod() {
Method method = new Object() {}.getClass().getEnclosingMethod();
SomeAnnotation ann = AnnotationUtils.findAnnotation(method, AnnotationTest.class);
}
}
It obviously requires to include in your project (and import) Spring framework classes.
There is no direct way to get it. If you really need, you have to manually loop over getInterfaces() to find if any implemented interface has the annotation. If you want to search for (eventually abstract) superclasses and the annotation is not #Inherited, you can again iterate the superclass chain until finding Object (*).
But beware, as following post states, there are good reasons for this not to be directly implemented in Java : Why java classes do not inherit annotations from implemented interfaces?
(*) If the annotation is #Inherited it is automatically searched on superclasses, but not on interfaces.
you can't inherit annotations.
But a framework that uses an annotation can check to see if annotation is present on superclass
I'm working on something that might benefit from a pattern like the following:
public abstract class SomeBuisnessThingy()
{
protected int someDatapoint;
}
public class ADatabaseThingy() extends SomeBusinessThingy()
{
#SomeJPAAnnotation
???? someDatapoint;
}
public class AWebServiceThingy() extends SomeBusinessThingy()
{
#SomeSOAPStuff
???? someDatapoint;
}
It smells more like an interface than an abstract class, but the same thing needs to be done. I have a DB implementation of that class and a WS implementation of that class.
Those representations are very similar, but may be different. For example the WS class may expose a field as a String so a 3rd party can easily do an integration, it can also be splot into its own package so we can hand a customer some lightweight WebService or POJO classes without all the baggage of the DB or a JPA framework coming with it. Perhaps it could be used to create the basic classes needed for something then switch between persistence frameworks that use different annotations.
Is it possible to ADD annotations to inherited fields?
No. If you need to annotate inherited members, you need to annotate the methods, not the fields.