#SpringBean support for bean in child ApplicationContext - java

I'm working with the developer of PF4J(Plugin Framework for Java) to provide better plugin functionality for Wicket. There is already a pf4j-spring and a pf4j-wicket project to provide some basic integration. In order to allow the #SpringBean or #Inject annotations to have access to plugin beans in a child context we need to be able to lookup the ApplicationContext associated with a specific class.
So for example, say I have a MyService bean in a child(plugin) ApplicationContext and that plugin also provides a panel that needs that via a #SpringBean annotation. Spring doesn't allow the parent ApplicationContext to see beans in a child context and for good reason. So we would get an exception saying that bean could not be found since #SpringBean only looks up beans in the parent context. We have code that we have developed that look up the child context like so:
SpringPlugin plugin = (SpringPlugin)PluginManager.whichPlugin(MyService.class);
ApplicationContext pluginContext = plugin.getApplicationContext();
How could I modify or provide this functionality in a custom version of SpringComponentInjector? It uses a ISpringContextLocator but that context locator does not specify the class for which it needs the ApplicationContext.
Any ideas on how this could be achieved?
Thanks for your help!

I'm afraid current SpringComponentInjector is not prepared for such usage. You will have to create your own version.
The problem that I see is that you will have to have either as many IComponentInstantiationListeners as plugins there are. Or create a composite ICIL that delegates to SpringBeanLocators for each plugin. I think the composite would be better. Then you'll have to make sure that a Panel in pluginA cannot use a bean located by SpringBeanLocatorB.
If you manage to do it and you find something in wicket-spring that could be made more generic to help make your version simpler then please let us know and we will consider your suggestion(s)!

Take a look at sbp. It is built on top of pf4j to support Spring Boot, and also provides mechanism of sharing beans between main application and plugins. It looks like:
#Override
protected SpringBootstrap createSpringBootstrap() {
return new SharedDataSourceSpringBootstrap(this, MdSimplePluginStarter.class)
.addSharedBeanName("objectMapper")
.addSharedBeanName("cacheService");
}

Related

Java EE : With CDI in place, do we ever need to use 'new' for our own POJO's

Env:
Wildfly 8.2.0 Final
JDK 8
Java EE 7
Please note that by 'POJO' i am referring to the classes that serve the other classes i.e other than value objects, entities.
This question was on back of my head for some time. Just wanted to put it out.
Based on CDI and Managed Beans specs and various other books/articles, its pretty clear that CDI injection starts with a 'managed' bean instance. By 'managed' i mean servlet, EJBs etc. which are managed by a container. From there, it injects POJOs (kind of crawl through layers) till every bean gets its dependencies. This all makes very sense to me and i see very little reason why developers ever need to use "new" to create an instance of their dependent POJO's.
One scenario that comes to my mind is when developer would like to have logic similar to
if(something) {
use-heavy-weight-A-instance
} else {
use-heavy-weight-B-instance
}
But, that also can be achieved via #Produces.
Here is one scenario that i verified to be true in wildfly 8.2.0 Final i.e. CDI is not able to inject bean when the JSP has
<%!
#Inject
BeanIntf bean;
%>
But, the alternative to use a servlet works fine.
That said, would like to know if there is any scenario(s) where a developer has to use 'new'. As i understand, by using 'new', developer owns the responsibility of fulfilling dependencies into that bean and all its dependent beans, and their dependent beans etc..
Thanks in advance,
Rakesh
When using CDI or other container you don't use new, because you expect a bunch of service coming from the container.
For CDI these main services are:
Injection of dependent beans (get existing instance or create a new
instance)
Lifecycle callback management (#PostConstruct and
#PreDestroy)
Lifecycle management of your instance (a #RequestScoped bean will make container produce an instance leaving until the end of request)
Applying interceptors and decorators on your instance
Registering and managing observers methods
Registering and managing producers methods
Now, on some rare occasion, you may want to add a part of these services to a class you instantiate yourself (or that another framework like JPA instantiate for you).
BeanManager bm = CDI.current().getBeanManager();
AnnotatedType<MyClass> type = bm.createAnnotatedType(MyClass.class);
InjectionTarget<MyClass> it = bm.getInjectionTargetFactory(type).createInjectionTarget(null);
CreationalContext<MyClass> ctx = bm.createCreationalContext(null);
MyClass pojo = new MyClass();
injectionTarget.inject(instance, ctx); // will try to satisfied injection points
injectionTarget.postConstruct(instance); // will call #PostConstruct
With this code you can instantiate your own MyClass containing injection points (#Inject) and lifecycle callbacks (#PostConstruct) and having these two services honored by the container.
This feature is used by 3rd party frameworks needing a basic integration with CDI.
The Unmanaged class handle this for you, but still prevent you to do the instantiation ;).

Spring Test: better use XML configuration over annotations?

I'm learning Spring and looking at using Spring Test for my web app (JQuery/CXF/Hibernate). I have been using annotations to wire up my beans and noticed that this sometimes got into the way of polymorphism. For example I have a GenericDAO extended by all DAOs. It is also a concrete class used by simple services, so when I wired it for one of those services, ALL other DAOs became candidates for runtime wiring (because of polymorphism). I could solve that by wiring explicitly by type: #Resource(type= GenericDaoImpl.class), but this goes against the best practice of coding to interfaces ..
Now I want to create unit tests using a MockGenericDaoImpl, and integration tests using GenericDaoImpl. How will I override the annotations? I'm guessing the best approach is to stick to XML-based wiring, so that I can have several versions of beans.xml, one for prod, one for unit tests, one for integration tests, and possibly split them into parallel sub-files, as needed. Isn't this approach more flexible than depending on annotations that either scan to guess the appropriate candidate, or constrain polymorphism?
Can someone give me broad directions on how to organize my test configuration setup? Thank you!
How about using #Configuration class? If you're not familiar with this method - you can declare a class that replaces the XML context file and looks something like this:
#Configuration
#ComponentScan({ "com.project.dao"})
public class TestConfiguration {
#Bean
public GenericDao getGenericDao() {
return new MockGenericDaoImpl();
}
}
In the #ComponentScan annotation just put the relevant packages to scan. This way you're very flexible with the beans you're creating and the way to create them. You can injects mock to the beans whatever way you'd like.
Also you can create several test configurations, each configuration for a different purpose. In order to load the context you need to put this annotation on your test class:
#ContextConfiguration(classes={TestConfiguration .class})
Using XML configuration files prevent you from depending on Spring dependencies. You can replace it with another DI framework(maybe Guice, but this is not realistic for big projects I know). Using XML configuration files enables you to code cleanly.
I hate XML but I hate existence of not-business-logic-specific things in my code more.
I see you know how to overcome the test issues using XML configuration files. I will try to show how to overcome duplication of implementations(one real one mock implementation) problems using annotations.
You can define your beans via annotations. You can select implementation using aliases:
project.dev.properties:
my.project.dao.xDao=xDaoJpaBean
project.test.properties:
my.project.dao.xDao=xDaoMockBean
<alias name="${my.project.dao.xDao}" alias="xDao"/>
#Autowired
#Qualifier("xDao")
protected XDao xDao;
So you can select your implementation just using your properties file. If you want to use Annotations purely you can do this as well:
#Autowired
#Qualifier("${my.project.dao.xDao}")
protected XDao xDao;
Your build environment will specify which properties file to load, in return your bean will be assigned.

Abstract class variable with spring

I am using spring and Hibernate and Dao design pattern for the my project, In my GenericDaoImpl(Abstract class) class has "tenentId", I want to set the "tenentId" when use login to the System. My other DaoImpl classes extends from GenericDaoImpl, so I need to set the tenentId(It's define in GenericDaoImpl) user login time and reset the "tenentId" when user log out.
What is the best way to do this?
In my test cases I tried #Autowired the "GenericDaoImpl" but I couldn't do that, It throws an exception telling, org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type. I know the problem now,
(We can't create instance of abstract classes,if use tenantId as static variable, is it going to be a problem?)
Can any one suggest me any solution?
Thank you,
Udeshika
if you are developing multi-tenancy application and would like to have tenant aware application context then have a look spring-tenancy. This will help you to have beans injected which are tenant aware.
if you want to multi-tenancy at hibernate layer then you can also look at multi-tenancy feature of hibernate.

How to get Spring Context

I have a third party library that starting up my aplication, load spring context and save it in private static filed without any acessors.
I need to get this context to my application. Does spring provides some callbacks like afterContextLoaded methods or any other ways how to get it?
Reflection is not a solution for me!
Thanks.
you have several ways to archive that:
Use ApplicationListerner and ApplicatinEvent
Use ApplicationContextAware
Both of them can be found at http://static.springsource.org/spring/docs/3.0.0.M4/reference/html/ch03s13.html
(sorry for the link is not to the latest version)
Just implement ApplicationContextAware in a Spring bean.
If you want to access the AppContext on startup, then also implement InitializingBean and put your code in afterPropertiesSet() - the ApplicationContext instance will be populated and ready for use at that time.

is there an elegant way to inject a spring managed bean into a java custom/simple tag

I have a bunch of java custom tags that use spring managed beans.. since i cant find a way to inject into a custom tag, i created a helper class that provides static methods to "getTheObjectINeedBean()" for all the spring bean objects i need.. I do not like this approach at all.
i really want to be able to inject a spring managed bean into the custom tag
Is there a way? As far as my research goes, I understand there is no way to do this, because the custom tag is container managed
Thanks,
Billy
You are correct there isn't a simple way to use dependency-injection in jstl tags, because they are not managed by spring, and cannot be. However there are (at least) two workarounds:
#Configurable - aspectJ allows you to plug a weaver at load-time/compile-time, so that even objects that are not instantiated by spring can be spring aware. See here
You can create a base tag class for your project, and call an init(..) method from every doStartTag(..) method. There, you can get the ServletContext from the pageContext, and thus obtain the spring ApplicationContext (via ApplicationContextUtils). Then:
AutowireCapableBeanFactory factory = appCtx.getAutowireCapableBeanFactory();
factory.autowireBean(this);
Neither options are perfect as they require either some additional code, or some "black magic"
To expand on #Bozho's post, I have gotten this to work like so: (in spring 3.0 there is no ApplicationContextUtils that I could find)
public class LocationTag extends RequestContextAwareTag {
#Autowired
PathComponent path;
...
#Override
protected int doStartTagInternal() throws Exception {
if (path == null) {
log.debug("Autowiring the bean");
WebApplicationContext wac = getRequestContext().getWebApplicationContext();
AutowireCapableBeanFactory acbf = wac.getAutowireCapableBeanFactory();
acbf.autowireBean(this);
}
return SKIP_BODY;
}
}
The solution as described above works but some background and additional code snippets are, quite likely, useful.
1) The doStartTagInternal method is invoked from the doStartTag method.
2) I was forced to set the pageContext first before invoking the doStartTag
3) I did a lookup of the bean as opposed to the autowiring. To me this seems more straightforward: (YourBeanProxy) autowireCapableBeanFactory.getBean("yourBeanName")
Hopefully this additional info is useful.

Categories