Getting bean from any context using groovy script in hybris
1. Overview
The Scripting console is a powerful feature that allow users to execute scripts on a running environment. It is especially handy when debugging a remote system.
Sometimes when creating our groovy script we may need to access a spring bean to perform some action. In this article we will demonstrate how to access any bean in the hybris application.
We are using hybris 6.3.0, and we will execute the groovy script in the HAC console.
For more information about the groovy syntax: Groovy Documentation
2. Getting our bean
Let’s imagine that we want to access the synchronizationService of the CMSCockpit, we can write:
spring.getBean("synchronizationService")
Or you can directly start using the bean using it’s code only:
synchronizationService
But we will probably face the following error: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'synchronizationService' is defined
It’s normal as the the synchronizationService bean is not visible from the HAC web application context, we should try to retrieve the bean from an application context where the bean is accessible.
Let’s try with CMSCockpit extension using the /CMSCockpit
application context.
import de.hybris.platform.core.PK
import de.hybris.platform.spring.HybrisContextLoaderListener
import org.apache.commons.lang3.reflect.FieldUtils
import org.springframework.web.context.ContextLoader
import org.springframework.web.context.WebApplicationContext
STOREFRONTCONTEXT = "/CMSCockpit"
def f = ContextLoader.getDeclaredField("currentContextPerThread")
f.setAccessible(true)
Map<ClassLoader, WebApplicationContext> contexts = f.get(HybrisContextLoaderListener)
def appContext = contexts.find {STOREFRONTCONTEXT.equals(it.key.getContextName())}
//When the context is found, we are ready to get our beans
if (appContext ==null) println "Impossible to retrieve application context"
else {
defaultSyncService = appContext.value.getBean("synchronizationService")
}
Let’s dive into this code snippets, we have three different steps:
2.1 Getting all hybris contexts
ContextLoader.getDeclaredField("currentContextPerThread")
currentContextPerThread is an attribute of ContextLoader of type Map<ClassLoader, WebApplicationContext>
, containing all the web application contexts.
2.2 Finding the required context
Search for the web application context having the required context name, using:
STOREFRONTCONTEXT.equals(it.key.getContextName())
contexts.find {}
is the groovy method to find the first value of a collection that matches the criteria in the closure.
2.3 we are ready
When the web application context is found, we can retrieve any bean that is visible in the given context, using appContext.getBean()
.
appContext.value
is the groovy style of getting the optional value.
3. Summary
The application context hierarchy is composed of the master hybris application context, and a web application context for every web module extension.
- Beans that are declared in a core module extension are accessible from every web application context. They are registred within the master hybris application context.
- We have a WebApplicationContext for every extension with a web module.
- In a given WebApplicationContext, other beans from other WebApplicationContexts are not visible.
- When the required bean is not accessible from a given WebApplicationContext, for instance the HAC application context, we need to look for it from the web application context of the declaring extension.
Spending many years of building robust softwares and websites in many technologies, a Master’s Degree in Computer Sciences and more than 4 years as a Java and hybris developper for an e-commerce firm, I had the opportunity to collaborate with big compagnies in Europe and North America with love and passion.
My main focus is on software quality, I spend most of my time in Java ecosystem and native apps developpement. I’m also interrested in DevOps and during my free time I love playing with trending technologies in middlewares and cloud computing.
Regardless of use cases where your tip gonna help, it’s a nice post.
To put aside for rainy day, Thank you Lahcen.
Thank you Mehdi for sharing, is it possible to change a bean implementation using groovy:
example:
customBeanImpl1 = spring.getBean(“customBeanImpl1”)
customBeanImpl1.setProperty1(val);
//how to do the following ?
spring.setBean(“customBeanImpl1”, customBeanImpl1);
Thanks in advance !
Hello Ayoub, thanks for your support, it’s possible to change a bean’s implementation, I’m going to publish a new post about this, however you could try something like this:
AutowireCapableBeanFactory factory = Registry.getApplicationContext().getAutowireCapableBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory;
GenericBeanDefinition gbd = new GenericBeanDefinition();
gbd.setBeanClass(CustomBeanImpl1.class);
MutablePropertyValues mpv = new MutablePropertyValues();
mpv.add("property1", val);
gbd.setPropertyValues(mpv);
registry.registerBeanDefinition(beanId, gbd);
Thank You
Thank you Mehdi
Hi Mahdi,
This post is really helpful. I am trying to run the same script to print all the web contexts. For some reason, storefront webcontext is not getting printed. I have tried in 2 different projects but no luck. Do you have idea what could be wrong?
Thanks
Mark
Nice Post !
was very useful for me
Thanks El Mahdi
Many thanks Mr Boufnichel, nice to see you around :).
Anyone struggling with this, just remove the “/” before the web application name and it works. Thanks for the page, had been struggling to find how to do this for hours.
Hi,
First of all nice POST. I really loved it.
I have tried this solution to print the application context names: But couldn’t find the storefront and cmscockpit.
I am using Hybris 1905 version patch 15
authorizationserver
samlsinglesignon
interfaces
backoffice
hac
odata2webservices
datahubadapter
ROOT
Any suggestions?
here we go again, just use it
thanks Mahdi