How to inject a service Bean in a groovy script? - java

I have a spring boot application and a separate groovy script that runs within the app and I need to inject a CustomService into the groovy script.
How do i achieve that? i tried reading the documentation but it's not so clear
i tried adding the #Autowired annotatino but it gives me an error and I dont think that's how it should be done.

How to inject dependency into IOC container of spring boot project with Groovy
Let imagine here is you CustomService
public class CustomService {
private final String smtPerhaps;
...
}
Then inject the bean as
beans {
yourDesiredBeanNameInContainer(CustomService) {
smtPerhaps = 'stackOverFlow'
}
}
Its quit the same as the Java base dependency injection
#Configuration
public class JavaBeanConfig {
#Bean
public CustomService yourDesiredBeanNameInContainer() {
return new CustomService("stackOverFlow");
}
}
Find out more in here.

Related

Spring Boot Integration test mock external dependency

I'm trying to create integration tests for my Spring Boot app. The idea is to launch an embedded postgres db and run http calls with TestRestTemplate to my controllers.
The problem is my project has a dependency we use for redis queues.
<dependency>
<groupId>com.github.sonus21</groupId>
<artifactId>rqueue-spring-boot-starter</artifactId>
<version>2.9.0-RELEASE</version>
</dependency>
I've tried to mock out the dependencies and most of them work, but with this one it complains I guess because it is a #Configuration not a #Component:
Dependency config class:
#Configuration
#AutoConfigureAfter({RedisAutoConfiguration.class})
#ComponentScan({"com.github.sonus21.rqueue.web", "com.github.sonus21.rqueue.dao"})
public class RqueueListenerAutoConfig extends RqueueListenerBaseConfig {
public RqueueListenerAutoConfig() {
}
...
}
My test config class
#TestConfiguration
public class TestRestTemplateConfig {
#Bean
#Primary
#Order(Ordered.HIGHEST_PRECEDENCE)
public RqueueListenerAutoConfig rqueueListenerAutoConfig() {
return Mockito.mock(RqueueListenerAutoConfig.class);
}
....
}
I've tried with #AutoConfigureOrder(1) at my config class but the original RqueueListenerAutoConfig launches before anything and my mocked beans haven't been declared yet.
To be honest mocking every service on that dependency is a pain, but I haven't figured out a way to mock the whole dependency with a single configuration. I tried not loading the dependency when I'm on the test profile but since it runs spring context my code needs it.
My test class has the following config:
#SpringBootTest
#Import(TestRestTemplateConfig.class)
#ActiveProfiles("test")
public class TestClass {
...
}
Any clues?
Thanks.
Try
#EnableAutoConfiguration(exclude=RqueueListenerAutoConfig.class)

Spring Boot: The bean 'auditLogDao' could not be injected as a 'AuditLogDao' because it is a JDK dynamic proxy

I am getting the following error in a Spring Boot project on which I work:
The bean 'auditLogDao' could not be injected as a '{redactedpathwithcorporatename}.AuditLogDao' because it is a JDK dynamic proxy that implements:
org.springframework.data.jpa.repository.JpaRepository
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
I have tried a variety of solutions on StackOverflow without success, specifically:
Checking that I am indeed calling the interface, not the implementation.
Adding #Component to the top of SwitchUserFilter
Changing #Resource to #Autowired.
AuditLogDao.java
public interface AuditLogDao extends JpaRepository<AuditLog, String> {}
AuditLogService.java
public interface AuditLogService {
AuditLog save(final AuditLog auditLog);
}
AuditLogServiceImplementation.java
public class AuditLogServiceImplementation implements AuditLogService{
#Resource private AuditLogDao auditLogDao;
#Override
public AuditLog save(AuditLog auditLog) {
return auditLogDao.save(auditLog);
}
}
The file where I actually want to use the service to save information
SwitchuserFilter.java
public class SwitchUserFilter
extends org.springframework.security.web.authentication.switchuser.SwitchUserFilter {
#Resource AuditLogService logService;
'''
logService.save(auditLog);
'''
}
I am relatively new to Spring Boot, so an explanation of why it fixes the problem would be appreciated.
I believe the following code will solve your problem. Add it to the AuditLogServiceImplementation and remove the #Resource annotation from the auditLogDao.
#Autowired
private ListableBeanFactory beanFactory;
#EventListener({ContextRefreshedEvent.class})
void contextRefreshedEvent() {
auditLogDao = beanFactory.getBean(AuditLogDao.class);
}
You can do a similar trick in the filter too, whatever more comfortable for you.
I don't know what is the exact problem, but it's some kind of circular-dependency-like issue.
So by manually importing any bean which is affected in this loop, you can resolve the loop. You will set this one particular dependency AFTER Spring had created all of the other beans.

Access Spring Boot Actuator build.version property with #Value

THis should be easy, but doesn't work.
I have spring-boot-actuator activated in my Spring Boot (2.0.1-RELEASE) application.
The Actuator-Endpoint /actuator/info works as expected and also shows the correct version info. The file build-info.properties is present.
When trying to access the version property with (e.g. in my Spring-Controller-Class):
#Value("${build.version}) private String version;
The action fails with the error Could not resolve placeholder 'build.version' in value "${build.version}".
ANy suggestions?
With spring expression language it is pretty simple and clean.
#Value("#{buildProperties.get('version')}") // not 'build.version'
private String myAppBuildVersion;
Or better, Autowire the buildProperties bean directly to your components so you can play with it as you want.
#Autowired
private BuildProperties buildProperties;
NOTE: The autoconfiguration strips off the build. prefix. So your
SpEL expressions should use version as key. Not build.version.
I needed to add the file build-info.properties as #PropertSource
#SpringBootApplication()
#PropertySource("classpath:META-INF/build-info.properties")
public class MyApp implements WebMvcConfigurer {
[...]
}
Then you can use the build-info in annotations
#SomeAnnotation(value = "${build.version}")
public class someClass { ... }
In your #Service, put the #Value in the constructor, as a parameter of the constructor. Don't use a standalone value and try to reference it.
like this:
#Service
public class myService {
public myService(#Value("${my.param}") String myParam) {
client.withParam(myParam).build();
}
}
Where your application.properties has a value like:
my.param=http://google.com
I have tried other implementations and they do not work. for example,
#Service
public class myService {
#Value("${my.param}")
String myParam;
public myService() {
client.withParam(myParam).build();
}
}
Does not work.
In this case, the service will be initialized, but the string will be null. I can't explain it. Something to do with param construction and bean initialization timing, I guess.

Spring integration test & set field to controller

I am trying to create my first integration test, inspiring myself from the jhipster project.
In my setup, i use that kind of code:
CampaignController campaignController = new CampaignController();
ReflectionTestUtils.setField(campaignController, "securityService", securityService);
ReflectionTestUtils.setField(campaignController, "campaignService", campaignService);
ReflectionTestUtils.setField(campaignController, "messageService", messageService);
MockMvc restMvcCampaignController = MockMvcBuilders.standaloneSetup(campaignController).setMessageConverters(TestUtil.getCustomJsonMessageConverter()).build();
RestAssuredMockMvc.mockMvc(restMvcCampaignController);
Services are autowired classes.
I would like to know if "ReflectionTestUtils.setField" is a good practice or if there is anything else better I could use ?
Thank you
It's not a good practice. Instead of making it impossible to set the dependencies (other then by reflection), inject the dependencies via a constructor. For example
#Controller
public class Controller {
private CampaignService campaignService;
#Autowired
public Controller(CampaignService campaignService, MessageService messageService) {
//bind fields
}
}
Now you can instantiate the controller easily from the test.

How to inject dependencies into a self-instantiated object in Spring?

Let's say we have a class:
public class MyClass {
#Autowired private AnotherBean anotherBean;
}
Then we created an object of this class (or some other framework have created the instance of this class).
MyClass obj = new MyClass();
Is it possible to still inject the dependencies? Something like:
applicationContext.injectDependencies(obj);
(I think Google Guice has something like this)
You can do this using the autowireBean() method of AutowireCapableBeanFactory. You pass it an arbitrary object, and Spring will treat it like something it created itself, and will apply the various autowiring bits and pieces.
To get hold of the AutowireCapableBeanFactory, just autowire that:
private #Autowired AutowireCapableBeanFactory beanFactory;
public void doStuff() {
MyBean obj = new MyBean();
beanFactory.autowireBean(obj);
// obj will now have its dependencies autowired.
}
You can also mark your MyClass with #Configurable annotation:
#Configurable
public class MyClass {
#Autowired private AnotherClass instance
}
Then at creation time it will automatically inject its dependencies. You also should have <context:spring-configured/> in your application context xml.
Just got the same need and in my case it was already the logic inside non Spring manageable java class which had access to ApplicationContext. Inspired by scaffman.
Solved by:
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(manuallyCreatedInstance);
I used a different approach. I had spring loaded beans that I wanted to call from my extended classes of a third-party library that created its own threads.
I used approach I found here https://confluence.jaytaala.com/display/TKB/Super+simple+approach+to+accessing+Spring+beans+from+non-Spring+managed+classes+and+POJOs
In the non-managed class:
{
[...]
SomeBean bc = (SomeBean) SpringContext.getBean(SomeBean.class);
[...]
bc.someMethod(...)
}
And then as a helper class in the main application:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class SpringContext implements ApplicationContextAware
{
private static ApplicationContext context;
public static <T extends Object> T getBean(Class<T> beanClass)
{
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException
{
SpringContext.context = context;
}
}
I wanted to share my solution that follows the #Configurable approach as briefly mentioned in #glaz666 answer because
The answer by #skaffman is nearly 10 years old, and that does not mean not good enough or does not work
The answer by #glaz666 is brief and didn't really help me solve my problem but, did point me in the right direction
My setup
Spring Boot 2.0.3 with Spring Neo4j & Aop starts (which is irrelevant anyway)
Instantiate a bean when Spring Boot is ready using #Configurable approach (using ApplicationRunner)
Gradle & Eclipse
Steps
I needed to follow the steps below in order to get it working
The #Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false) to be placed on top of your Bean that is to be manually instantiated. In my case the Bean that is to be manually instantiated have #Autowired services hence, the props to above annotation.
Annotate the Spring Boot's main XXXApplicaiton.java (or the file that is annotated with #SpringBootApplication) with the #EnableSpringConfigured and #EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
Add the dependencies in your build file (i.e. build.gradle or pom.xml depending on which one you use) compile('org.springframework.boot:spring-boot-starter-aop') and compile('org.springframework:spring-aspects:5.0.7.RELEASE')
New+up your Bean that is annotated with #Configurable anywhere and its dependencies should be autowired.
*In regards to point #3 above, I am aware that the org.springframework.boot:spring-boot-starter-aop transitively pulls the spring-aop (as shown here mavencentral) but, in my case the Eclipse failed to resolve the #EnableSpringConfigured annotations hence, why I explicitly added the spring-aop dependency in addition to the starter. Should you face the same issue, just declare the dependency or go on adventure of figuring out
Is there a version conflict
Why the org.springframework.context.annotation.aspect.* is not available
Is your IDE setup properly
Etc etc.
This worked for me:
#Configuration
public class AppConfig {
#Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
See more information: https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html
Found the following way useful for my use case. Sharing here for reference, credit goes to the blogger entirely. This creates a static field and populates that from Spring and then provides a public static method which returns the field populated above.
https://sultanov.dev/blog/access-spring-beans-from-unmanaged-objects/

Categories

Resources