Is there some way to get access to Spring bean from Spock extension? - spring

There is an example what I want to do.
The service client is a Spring bean, which is retrieving from external configuration class and should be called from Spock extension.
class ServiceCleintExtension implements IGlobalExtension {
#Autowired
ServiceCLient client
#Override
void start() {
client.execute()
}
...
}
UPD:
I've found a solution by using Spring TestExecutionListener and custom static "container" for SpecInfo/FeatureInfo.

No that is not possible, IGlobalExtension are initialized and manged by Spock. Furthermore, they are singletons which doesn't mesh well with multiple possible Spring contexts.
If you just want to call a method on an injected bean during setup, then I'd suggest to use an annotation based extension. Look at the builtin AutoCleanup extension for reference.

Related

Spock with Spring Boot and Camel: Zero interactions with detached mock

I am having some issues with testing my camel context with spring boot.
I am using spring boot 1.5.6, spock 1.1-groovy-2.4, camel 2.19.2, and camel-spring-boot-starter 2.19.2.
I am using a spock mock, and I'm using the DetachedMockFactory in a #TestConfiguration class. All of my beans use constructor injection. I am injecting a mocked #Repository into one of the processor #Components, and I am also injecting it into my test class to define interactions.
I have my test annotated with #SpringBootTest with the classes list including all Processor implementations, and all RouteBuilder extensions. I also have an '#Import' with my TestConfiguration class. I am even using constructor injection for this repository bean in my test!
But it seems that the mock that is injected into the test class is not the one that is in use. Does anyone have an idea what could be wrong? I have tried #DirtiesContext to reload the context both before and after each test, but that did not help.
Problems with DetachedMocks not behaving correctly, e.g., appearing to be the same instance, are usually caused by some framework wrapping them in proxies. For example this can be caused by #Transactional annotation in Spring, which creates a proxy to facilitate jdbc-session management. See also issue #758
For spring you can use the methods of AopUtils (jdoc). The simple way is to use AopUtils.isAopProxy to check if it is proxied by spring an then unwrap it.
public static <T> T getTargetObject(Object proxy) throws Exception {
if (AopUtils.isAopProxy(proxy)) {
return (T) ((Advised) proxy).getTargetSource().getTarget();
} else {
return (T) proxy;
}
}
And in a Test
def "sample service test"() {
given:
def sampleRepositryMock = getTargetObject(sampleRepositry)
when:
sampleService.doSomething() // simply invoke sampleRepositry.doSomething() in it
then:
1 * sampleRepositryMock.doSomething()
0 * _
}
Edit: Since Spock 1.2 there is an extension to automatically unwrap injected beans #UnwrapAopProxy.
#Inject
#UnwrapAopProxy
SampleRepositry sampleRepositryMock
If someone comes up with the same problem.
Spock added additional #UnwrapAopProxy that will do the job for you instead of the util method mentioned above. You can also drop the DetachedMockFactory
#SpringSpy
#UnwrapAopProxy
Service service

Spring MVC #Configuration class constructor

As part of the Spring MVC initialization, I need to run an action (just calling a method on a 3rd party library) once as a setup operation. I'm working in Spring MVC environment where I don't really have control over the web.xml or anything, so I can't add a servlet context listener or anything. I tried making an implementation of a WebApplicationInitializer but it never seems to get called (no idea why though, or how to try and debug that any further).
If I annotate a class with #Configuration it does get created, so I'm wondering if I can use the class's constructor to perform that setup operation (calling a 3rd party setup method). Is this appropriate/safe to do? Are there any other alternatives for this kind of thing? I'm new to Spring, so I might just be missing something that's meant for this kind of thing.
Thanks
Configuration class would be an appropriate place to contain some initialization logic. You can place it in a constructor, method annotated with #PostConstruct or afterPropertiesSet() method if you implement the InitializingBean interface for example. The difference is that the constructor code will be called before the beans in your configuration class are instantiated, so if your initialization code depends on some Spring beans, go with the #PostConstruct / InitializingBean approach.
Example:
#Configuration
public class Config {
#PostConstruct
public void initialize() {
// Run some action
}
}

Invoking custom annotation using Spring AOP

I searched the web for a clear example on how to invoke my custom method annotation using Spring AOP but couldn't find a clear example.
I am building a framework to inject a user profile in the context when certain methods on any POJO is called.
The framework API should be invoked via a custom method annotation, say #RunAsAdmin. I can build the annotation part and parser, my question is what is the best way to invoke my parser when the annotated method is called.
We are using Spring 3.0 and would like to know what is the best practice to configure Spring framework to understand those methods annotated with specific annotation and invoke my annotation handler (parser).
Any example or guidance will be highly appreciated.
Intercepting a call on any annotated Spring bean method is straightforward, see the example below.
Intercepting a call on a POJO is not possible by definition - you have to return a proxy instead.
That is, you should implement a factory for these POJOs that will return proxies instead of real POJOs. You might use ProxyFactoryBean http://docs.spring.io/autorepo/docs/spring-framework/3.2.0.BUILD-SNAPSHOT/api/org/springframework/aop/framework/ProxyFactoryBean.html for this.
//intercepting a call to any method annotated with #com.yours.RunAsAdmin of any Spring-managed bean
#Component #Aspect class RunAsAdminAspect {
#Autowired
private YourRunAsAdminHandler handler;
#Before("#annotation(com.yours.RunAsAdmin)")
public void doRunAsAdmin() {
handler.grantAdminRightsToCurrentUser(); //your real stuff
}
}

How can I instantiate an injected class (using Spring) before logback configuration

I am using spring to inject a class into my PropertyDefiner implementation which will be used to help set up some properties within the logback.xml file (through dynamic property loading).
I'd love to get this class loaded and instantiated before logback is configured. Any thoughts on how to do this?
If you're using annotations in Spring, it's convenient to do this by marking the class (i.e. the dependency) you'll be injecting as #Component and then using #Autowired in your PropertyDefiner implementation. This ensures that the first class will be instantiated first. http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch04s12.html
Any other initialization you require could be achieved using instance initializer blocks http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
I do not know if this can be done elegantly at present time (2012-07). However, support for injection has been requested in LOGBACK-719.
If your bean factory implements AutowireCapableBeanFactory, given the Spring Applicaton context, you could invoke autowireBean(Object existingBean) to autowire the bean. Here is a tentative implementation:
class Your.PropertyDefiner implements PropertyDefiner, LifeCycle {
#Autowired
#Qualifier("myKey")
String myKey;
public void start() {
ApplicationContext appContext = ... somehow get the spring app context
AutowireCapableBeanFactory factory = appContext.getAutowireCapableBeanFactory();
factory.autowireBean(this); // declare victory
}
}
The start() method will be invoked only if your PropertyDefiner implements the LifeCycle interface. Moreover, you need logback version 1.0.7 or later. Earlier versions do not invoke start().
My solution resulted in not implementing a PropertyDefiner. The original question became an issue of not having the application context from spring to set the dynamic properties. I'm not sure why, but code in a later listener (after the Spring listeners) would get called (invoking the LoggerFactory call) before the application context was available. I tried a number of things, until I starting looking at a different approach.
Instead of using dynamic properties I created a listener (called on server startup) which then programmatically sets up my appender with the properties I want (through the createAdminNotifyAppender).
#Override
public void contextInitialized(ServletContextEvent arg0)
{
//Set up the property reader to pull the correct properties
ServletContext context = arg0.getServletContext();
ApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(context);
propReader = (AppConfigPropertiesReader)appContext.getBean("propertySourcesPlaceholder");
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
createAdminNotifyAppender(lc, propReader);
}
The createAdminNotify method simply sets up an appender and adds it to the logging context. (if you're really interested, you can see that method's implementation on this thread).
Now I have a separate and modular listener that I can add to other apps that are using logback, but possibly with different properties. The properties are pulled from a database and can also vary by environment.

How to use spring to resolve dependencies of an object created manually?

I would like to know if it's possible to use Spring to resolve the dependencies of an object created manually in my program. Take a look at the following class:
public class TestClass {
private MyDependency md;
public TestClass() {
}
...
public void methodThaUsesMyDependency() {
...
md.someMethod();
...
}
}
This TestClass is not a spring bean, but needs MyDependency, that is a spring bean. Is there some way I can inject this dependency through Spring, even if I instantiate TestClass with a new operator inside my code?
Thanks
Edit: The method I'm describing in my original answer below is the general way to accomplish DI external of the container. For your specific need - testing - I agree with DJ's answer. It's much more appropriate to use Spring's test support, for example:
#Test
#ContextConfiguration(locations = { "classpath*:**/applicationContext.xml" })
public class MyTest extends AbstractTestNGSpringContextTests {
#Resource
private MyDependency md;
#Test
public void myTest() {
...
While the above example is a TestNG test, there is also Junit support explained in 8.3.7.2. Context management and caching.
General approach: Annotate your class with #Configurable and utilize AspectJ load-time or compile-time weaving. See 6.8.1 in the Spring documentation on AOP for more details.
You can then annotate your instance variables with #Resource or #Autowired. Though they accomplish the same goal of dependency injection, I recommend using #Resource since it's a Java standard rather than Spring-specific.
Lastly, remember to consider using the transient keyword (or #Transient for JPA) if you plan on serializing or persisting the objects in the future. Chances are you don't want to serialize references to your DI'd repository, service, or component beans.
See the autowire() method on the AutowireCapableBeanFactory class. If you use an ClasspathXmlApplicationContext, you can get the factory with getAutowireCapableBeanFactory()
To get the ApplicationContext, you would need to use a static singleton or other central repository, such as JNDI or a Servlet container. See DefaultLocatorFactory on how to get an instance of the ApplicationContext.
If what you need is for testing purposes, Spring has good support for the scenario that you described above.
Check out Spring Reference manual section on Testing

Resources