I am interested in getting the class being proxied from spring, rather than the proxy.
ie:
public class FooImpl<KittyKat> {
#Transactional
public void doStuff() {
getBar();
// java.lang.ClassCastException: $Proxy26 cannot be cast to
// com.my.foo.Bar
}
}
public abstract class AbstractFoo<T extends AbstractBar> {
public String barBeanName;
protected T getBar() {
// java.lang.ClassCastException: $Proxy26 cannot be cast to
// com.my.foo.Bar
return (T)appContext.getBean(barBeanName);
}
}
public class KittyCat extends AbstractBar {
...
}
public abstract class AbstractBar {
...
}
Are you trying to get the proxied bean only because of the ClassCastException? If you could cast to Bar, would you happy with that?
When Spring creates a proxy, it checks to see if the bean class implements any interfaces. If it does, then the generated proxy will also implement those interfaces, but it will not extend the target bean's class. It does this using a standard java.lang.reflect.Proxy. This seems to be the case in your example.
If the target bean's class does not implement any interfaces, then Spring will use CGLIB to generate a proxy class which is a subclass of the target bean's class. This is sort of a stop-gap measure for proxying non-interface beans.
You can force Spring to always proxy the target class, but how you do that depends on how you created the Bar proxy to begin with, and you haven't told us that.
The generally preferred solution is to refer to your proxied beans by their interfaces, and everything works nicely. If your Bar class implement interfaces, could your Foo not refer to that interface?
Related
I'm trying to understand how to handle conditionally creating new instances of a class that uses #Inject. In the below example I have a factory that instantiates classes based on a parameter.
AnimalFactory does not have access to the injector the main class of my application has, so I can't use injector.getInstance(Cat.class)
class AnimalFactory {
public IAnimal create(AnimalType type) {
if (type.equals(AnimalType.CAT)) {
return new Cat(); // Cat uses #Inject, so this won't work of course. But ???
} else if (type.equals(AnimalType.DOG)) {
return new Dog();
}
}
}
In the rest of my app, classes are injected into my constructors because I always need them. Guice creates an instance/singleton for each. But in this scenario, I do not want to create and inject instances for each animal because all but one are needed.
You can use a MapBinder as described here:
public class AnimalModule extends AbstractModule {
public void configure() {
MapBinder<AnimalType, IAnimal> animalBinder= MapBinder.newMapBinder(binder(), AnimalType.class, IAnimal.class);
animalBinder.addBinding(AnimalType.DOG).to(Dog.class);
...
}
}
And than use it in your factory:
class AnimalFactory {
#Inject
Map<AnimalType, IAnimal> animals;
public IAnimal create(AnimalType type) {
return animals.get(type);
}
}
Actually I worked on exactly the same issue and I wrote a feature that allows you to create self-populating factory. Meaning that if you work in Spring/Spring-boot environment you can create a factory that can access and provide any interface implementing class that is managed by Spring-boot without injecting in the factory. You can also give the instances custom names. So, it seems like it fits your case exactly. Here is a link to an article that describes the feature in great detail: Non-intrusive access to "Orphaned" Beans in Spring framework. Also, in MgntUtils library Javadoc there is a good description of the feature here enter link description here. The library itself including source code could be found on Github here and in the package com.mgnt.lifecycle.management.example there is a working example. Maven artifacts are here
Is it a bad practice to have a Spring Service break down its functionality by implementing multiple interfaces and then having Spring inject that one Service instance using the interface that declares only the required methods where needed?
Like:
public interface OperationsService1 {
public void operation1();
public void operation2();
}
public interface OperationsService2 {
public void operation3();
public void operation4();
}
#Service
public class OperationsServiceImpl implements OperationsService1, OperationsService2 {
public void operation1() {}
public void operation2() {}
public void operation3() {}
public void operation4() {}
}
and then in the calling class:
#Autowire
private OperationsService1 ops1;
or
#Autowire
private OperationsService2 ops2;
This is more a matter of design than a matter of Spring from my point of view. Generally, a class should be responsible for a single functionality (see SRP on wiki). So one service class should implement one service interface.
and then having Spring inject the Service instance using the interface
that declares only the required methods where needed?
First of all I feel like you are confused. In your example there won't be an instance for each interface. When you call
#Autowire
private OperationsService1 ops1;
#Autowire
private OperationsService2 ops2;
they will both point to the same OperationsServiceImpl class because the bean is singleton by default. What you have here is one instace and two interfaces which point to it. By autowiring the interfaces it means that for the first interface you can call only some of the methods in the bean, with the 2nd interface some other methods of the same bean.
It it a good practice?
I don't think so, usually one would use an interface with multiple object instances with various functionality which is not the case here as explained above. It's gonna get even more messy if other classes start implementing these interfaces and you have to use #Qualifier to distinguish between them. If you want a clean solution separate the OperationsServiceImpl into two separate classes and each of them implement the corresponding interface. It would be less complex and easier to support for new developers.
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 am trying to inject specific Generic bean to Generic subtype, but Spring is unable to resolve dependency. By removing type from the bean, everything works as expected. Here is an example:
public class AbstractFrom{
// ...
}
public class EmployyForm extends AbstractFrom{
// ...
}
public class CompanyForm extends AbstractFrom{
// ...
}
abstract class AbstractBean<T extends AbstractFrom>{
public abstract void calculate(T form);
}
#Component
public CompanyBean extends AbstractBean<CompanyForm>{
public void calculate(CompanyForm form){
// specific impl
}
}
#Component
public EmployeeBean extends AbstractBean<EmployyForm>{
public void calculate(EmployyForm form){
// specific impl
}
}
Here is a target class:
#Service
public BaseService{
#Autowire
public AbstractBean<AbstractFrom> baseBean; // <- NoSuchBeanDefinitionException
// #Autowire
// public AbstractBean baseBean; <- Injection works as is expected
}
Depends of active profile is initialized only CompanyBean or EmployeeBean, never both. I've also tried set the same name given beans and us #Qualifier annotation.
Does exist any way how inject this bean using diamond syntax? Does Spring is able to resolve given dependency? Using Spring 4.2.x.
Edit:
With Spring 4.3 is should be possible. See Juergen Hoeller's talk
I know you are probably not going to like this, but why not separate out the EmployeeForm and the CompanyForm to 2 separate base forms, and then in the BaseService make TWO entires, for the Autowire.
This is not a Spring answer per se, but that is what I would do, as a quick work around to see if it would work.
Separating them is not a terrible design compromise.
Here's a problem I am facing.
I am writing a plugin. There is an interface called SystemObject, and a default getter.
public class MyPlugin extends Plugin {
#override
public SystemObject getSystemObject() {
return super.getSystemObject();
}
}
SystemObject interface has a method called getScreenSize() which I would like to proxy or intercept. When I create a proxy class, or simply implement this SystemObject interface myself, I get a class cast exception.
This is because the caller for getSystemObject (part of the plugin system) has this in their code (found via reverse-engineering):
private void foo() {
SystemObjectImpl impl = (SystemObjectImpl)plugin.getSystemObject();
}
My question is: is there any way I can proxy calls on the SystemObject interface?
I tried implementing the interface and using java reflection proxy invocation to no avail. Unfortunately, I'm not responsible for running the java process, so I can't use an agent.
Cheers!
You could use something like CGLIB to create a proxy class that extends SystemObjectImpl.