Programmatically adding Beans to Spring application Context - java

I am trying to add a simple String to my Spring Application Context, and then autowire this to a different existing bean (A) within the application context. I know this is not the usual way to go, yet I need to add many beans programmatically, which would otherwise make my xml configuration huge.
public class MyPostProcessor implements BeanFactoryPostProcessor, Ordered {
#Override
public int getOrder() {
return 0;
}
#Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerSingleton("myString", "this is the String");
A a = beanFactory.getBean(A.class);
beanFactory.autowireBean(a);
}
}
public class A {
#Autowired
public transient String message;
}
When running this, the property message of the instance of A is null. What am I missing?
EDIT: this is my application context:
#Configuration
class TestConfig {
#Bean
public A a() {
return new A();
}
#Bean
public MyPostProcessor postProcessor() {
return new MyPostProcessor();
}
}
And this is my test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestConfig.class)
public class MyTest {
#Autowired
private transient A a;
#Test
public void test() throws Exception {
System.err.println("Running");
System.err.println("This is the autowired String: " + a.message);
Thread.sleep(1000);
}
}
Thanks

You should not instantiate beans from BeanFactoryPostprocessors.
From BeanFactoryPostProcessor JavaDoc:
A BeanFactoryPostProcessor may interact with and modify bean
definitions, but never bean instances. Doing so may cause premature
bean instantiation, violating the container and causing unintended
side-effects.
In your case, the A bean is instantiated before BeanPostProcessors and therefore not autowired.
Remove the lines:
A a = beanFactory.getBean(A.class);
beanFactory.autowireBean(a);
And will work.

Try using the #Qualifier to specific which bean you want to Auto wire.
public class A {
#Autowired
#Qualifier("myString")
public transient String message;
}

Related

How to enforce 1 Bean instance and avoid NoUniqueBeanDefinitionException?

I'm implementing a websocket service where incoming messages are passed to controllers and the controllers can then broadcast response messages to another websocket session(s).
When they broadcast the message back, there is either 1 of 2 issues. Either MySocketHandler is a different instance than the one that handled afterConnectionEstablished (using Autowired annotation on MySocketHandler in MessageRouter seems to create a new instance) or I get NoUniqueBeanDefinitionException (if I use ApplicationContext to specifically get the bean by class type).
An instance of my application should only have 1 MySocketHandler, so I annotated MySocketHandler with #Scope(ConfigurableBeanFactory.SCOPE_SINGLETON).
I suspect this has something to do with asynchronous event publishing and listening. I've refactored this code a few times to try to implement this the "Spring" way but there's some fundamental error each time.
I want to know how I can enforce the Spring container to create and reuse only 1 instance of MySocketHandler.
Here is my a minimalized version of MySocketHandler.java to exemplify the problem:
#Component
#Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class MySocketHandler extends BinaryWebSocketHandler {
#Autowired private ApplicationContext applicationContext
#Autowired private MessageRouter messageRouter;
private final HashMap<String, WebSocketSession> sessions = new HashMap<>();
#EventListener
public void onOutgoingBinaryMessageEvent(OutgoingBinaryMessageEvent event) {
// ERROR: NoUniqueBeanDefinitionException
applicationContext.getBean(MySocketHandler.class).broadcast(event.getBytes(), event.getConnectionIds());
}
#Override
public void afterConnectionEstablished(WebSocketSession session) {
sessions.put(session.getId(), session);
}
#Override
public void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
eventPublisher.publishEvent(new IncomingBinaryMessageEvent(
this,
message.getPayload().array(),
session.getId()));
}
private void broadcast(byte[] bytes, Set<String> playerIds) {
BinaryMessage binaryMessage = new BinaryMessage(bytes);
// this.sessions is null because its a different instance of MySocketHandler than the one that actually managing the connections
for (WebSocketSession session : sessions.values()) {
try {
webSocketSession.sendMessage(binaryMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
And an example of the MessageRouter.java:
#Component
public class MessageRouter {
#Autowired private ApplicationEventPublisher eventPublisher;
public void send(Message message) {
eventPublisher.publishEvent(message);
}
#EventListener
private void routeMessageToController(SomeMessageEvent any, String connectionId) {
.....
// Parse message and route it to a controller class.
.....
}
}
}
Application entry point:
public class MyApplication implements WebSocketConfigurer {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(getSocketHandler(), "/").setAllowedOriginPatterns("*");
}
#Bean
public MySocketHandler getSocketHandler() {
return new MySocketHandler();
}
}
An instance of my application should only have 1 MySocketHandler, so I
annotated MySocketHandler with
#Scope(ConfigurableBeanFactory.SCOPE_SINGLETON).
First of all , singleton is applied in the bean level but not the type level. It can't ensure your application will only has the single bean of a particular type. You can still define multiple singleton bean for the same type.
In most general cases , a bean can be defined by the following ways:
Annotating the class with #Component (or its specialisation version such as #Repository , #Service , #Controller , #Configuration etc.)
Using #Bean method in the #Configuration class
Now you are doing :
#Component
#Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class MySocketHandler extends BinaryWebSocketHandler
}
#SpringBootApplication
public class MyApplication implements WebSocketConfigurer {
#Bean
public MySocketHandler getSocketHandler() {
return new MySocketHandler();
}
}
Note: #SpringBootApplication is a composed annotation which contain #Configuration
which means you are now defining two MySocketHandler beans . One with the name mySocketHandler (defined via #Component) and the other has the name getSocketHandler (defined via #Bean)
So to ensure there is only one MySocketHandler bean , either remove #Component from MySocketHandler or remove this #Bean method.

Initiate object via constructor through #AutoWired during runtime

I was new to Springboot application using the #Autowired to perform the dependency injection. We can use #Autowired directly by initiate that class object for class that has none or default parameterless constructor. But what if a class has some parameter in its constructor, and I would like to initiate it during runtime conditionally and automatically, is it possible to do that?
For example
#Component
public class SomeContext {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Component
public class SomeBuilder {
private final SomeContext ctx;
#Autowired
public SomeBuilder(SomeContext ctx) {
this.ctx = ctx;
}
public void test() {
System.out.println("ctx name: " + ctx.getName());
}
}
#Service
public class SomeService {
#Autowired
SomeBuilder someBuilder;
public void run(SomeContext ctx) {
if (ctx != null) {
// I want someBuilder to be initiated here in someway with my input ctx
// but NOT doing through new with constructor like below
// someBuilder = new SomeBuilder(ctx);
someBuilder.test(); // ctx name: null, I would expect to see "ctx name: someUser", while ctx was injected into someBuilder in any possible way
}
}
}
#RestController
public class HelloWorldController
{
#Autowired
SomeService someService;
#RequestMapping("/")
public String hello() {
SomeContext someContext = new SomeContext();
someContext.setName("someUser");
someService.run(someContext);
return "Hello springboot";
}
}
I'm not sure I've got your question right, but from the code it looks like you really want to create a new instance of SomeBuilder every time you call the run method of SomeService.
If so, I think the first thing to understand is that in general the injection magic happens only if the class is managed by Spring by itself. Read, if spring creates the object of the class - it will inject stuff into it otherwise you're on your own here.
The next thing to understand is that, if you have a object of class SomeBuilder managed by spring and you want to inject SomeContext into it, this SomeContext instance has to be managed by spring as well.
Bottom line, spring can deal only with objects that it manages. These objects are stored in a 'global registry' of all the objects called ApplicationContext in spring.
Now Spring has a concept of prototype scope vs. singleton scope. By Default all the beans are singletons, however you can easily alter this behavior. This has two interesting consequences:
You Can create prototype objects being injected into the singleton upon each invocatino (of method run in your case, so the SomeBuilder can and I believe should be a prototype)
Prototype objects are not stored in the application contexts so the capabilities of injecting stuff in there during the runtime are rather limited
With all this in mind:
If you want to create SomeContext like you do in the controller, its not managed by spring, so you can't use Injection of spring as is into the builder.
The builder is a singleton, so if you inject it with a regular #Autowire into another singleton (SomeService in your case), you'll have to deal with the same instance of the builder object - think about concurrent access to the method run of SomeService and you'll understand that this solution is not really a good one.
So these are the "inaccuracies" in the presented solution.
Now, in terms of solution, you can:
Option 1
Don't manage builders in Spring, not everything should be managed by spring, in this case you'll keep your code as it is now.
Option 2
and this is a the solution, although pretty advanced one:
Use Java Configuration to create prototype beans in runtime with an ability to inject parameters into the bean.
Here is an example:
// Note, I've removed all the annotations, I'll use java configurations for that, read below...
public class SomeBuilder {
private final SomeContext ctx;
public SomeBuilder(SomeContext ctx) {
this.ctx = ctx;
}
public void test() {
System.out.println("ctx name: " + ctx.getName());
}
}
Now the class SomeService will also slightly change:
public class SomeService {
private Function<SomeContext, SomeBuilder> builderFactory;
public void run(SomeContext ctx) {
SomeBuilder someBuilder = builderFactory.apply(ctx);
someBuilder.test();
}
}
And now you should "glue" it to spring in an advanced way with Java Configurations:
#Configuration
public class MyConfiguration {
#Bean
public Function<SomeContext, SomeBuilder> builderFactory() {
return ctx -> someBuilder(ctx);
}
#Bean
#Scope(value = "prototype")
public SomeBuilder someBuilder(SomeContext ctx) {
return new SomeBuilder(ctx);
}
#Bean
public SomeService someService() {
return new SomeService(builderFactory());
}
}
For more details with a really similar example, see this tutorial

Why are #Bean Generics creation methods on a superclass called later than ones on the child-class in Spring Boot?

I have a spring boot base abstract config class that creates a bean. If I then inherit from it, the bean will be created later than my controller (which needs to auto-wire it and thus fails). Note: it does get created, just after the controller. So it can't be auto-wired but has to be found via appContext.getBean( BeanType.class )
If I instead override the bean method in the child class, then it's created before the controller and it can be auto-wired.
How can i fix this and make the super-class bean definition load at the same time as the child class?
#SpringBootApplication
public class ChildConfig extends ParentConfig<PCTestBean>
{
public ChildConfig()
{
super();
}
#Override
public PCTestBean getT()
{
return new PCTestBean();
}
}
public abstract class ParentConfig<T>
{
public ParentConfig() {}
#Bean
public T createTestBean()
{
return getT();
}
public abstract T getT();
}
public class PCTestBean
{
}
#RestController
#RequestMapping( "/client" )
public class MyController
{
#Autowired
private PCTestBean pcTestBean;
#RequestMapping( "/get" )
#ResponseBody
public String getClient(HttpServletRequest request) throws Exception
{
return pcTestBean.toString();
}
}
#RunWith( SpringJUnit4ClassRunner.class )
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
#ContextConfiguration(
classes = {
ChildConfig.class
}
)
public class TestConfigs
{
#LocalServerPort
private String port;
private MockMvc mockMvc;
#Autowired
private WebApplicationContext context;
#Before
public void setUp() throws Exception
{
mockMvc = MockMvcBuilders
.webAppContextSetup( context )
.build();
}
#Test
public void testValidCall() throws Exception
{
MvcResult result = mockMvc.perform(
MockMvcRequestBuilders.get( new URI( "http://localhost:" + port + "/client/get" ) )
)
.andExpect( MockMvcResultMatchers.status().isOk() ).andReturn();
System.out.println( result.getResponse().getContentAsString() );
}
}
When Spring scans your configuration class, ChildConfig, it discovers this inherited method
#Bean
public T createTestBean() {
return getT();
}
and registers a bean definition for it. That bean definition contains metadata about the type of the bean. That type is inferred from the return type of the method. In this case, it's resolved to Object because the type variable T has no bounds in its declaration and because Spring doesn't try to resolve it based on the type argument provided in ChildConfig's extends ParentConfig<PCTestBean> clause.
When Spring then tries to process the
#Autowired
private PCTestBean pcTestBean;
injection target, it looks for a PCTestBean bean, which it doesn't think it has, because the metadata is lacking. IF the bean hasn't been initialized through some other forced order, then Spring has no other information to go on and thinks the bean doesn't exist.
When you change your code to
instead override the bean method in the child class
the return type of the method is PCTestBean which Spring can then match to the #Autowired injection requirement, find (and initialize) the bean, and inject it.
By the time you use ApplicationContext#getBean(Class), the PCTestBean has been initialized. Spring can therefore rely on the actual type of the instance. It'll more or less loop through all beans and check whether beanClass.isInstance(eachBean), returning the one that matches (or failing if more than one does).
Pankaj, in their answer, suggests using #DependsOn (it was wrong when they suggested it, before you edited your question). That can help establish the order I mentioned earlier.
I don't how extensive your configuration class is that you think you need generics to abstract some behavior away, but I would suggest just dropping the generic behavior and be explicit in each class.
Try DependsOn annotation, it guarantees that the child bean should be created after the parent bean
#Configuration
public class ChildConfig extends ParentConfig
{
public ChildConfig()
{
super();
}
#DependsOn("parentConfig")
#Override
public TestBean createTestBean()
{
return super.createTestBean();
}*/
}
public abstract class ParentConfig
{
public ParentConfig() {}
#Bean (name ="parentConfig")
public TestBean createTestBean()
{
return new TestBean();
}
}

CacheManager bean definition in Config.class leads to NoSuchBeanDefinitionException

I have a Spring service which is checking database entries. To minimize my repository calls both find methods are "#Cacheable". But when I try to init my service bean while my configuration class has a CacheManager bean definition I get following NoSuchBeanDefinitionException:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'foo.mediacode.directory.MediaCodeDirectoryService' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:353)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1093)
at foo.mediacode.directory.MediaCodeDirectoryService.implementation(MediaCodeDirectoryService.java:63)
at foo.campaigntree.directory.CampaignTreeDirectoryService.<init>(CampaignTreeDirectoryService.java:18)
... 15 more
If I take out the CacheManager bean definition, I can init my service bean and it runs without any problems and caching!
Here is my code:
Configuration
...
#Configuration
#EnableCaching
#EnableJpaRepositories(...)
#PropertySource({...})
public class MediaCodeDirectoryServiceConfig {
private static Logger configLogger = Logger.getLogger(MediaCodeDirectoryServiceConfig.class.getName());
#Value("${jpa.loggingLevel:FINE}")
private String loggingLevel;
#Value("${mysql.databaseDriver}")
private String dataBaseDriver;
#Value("${mysql.username}")
private String username;
#Value("${mysql.password}")
private String password;
#Value("${mysql.databaseUrl}")
private String databaseUrl;
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
...
}
#Bean
public MediaCodeDirectoryService mediaCodeDirectoryService() {
return new MediaCodeDirectoryService();
}
#Bean
public CacheManager mediaCodeCacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("mediaCodeMappingRegexCache"),
new ConcurrentMapCache("mediaCodeMappingsCache")));
return cacheManager;
}
#Bean
public JpaTransactionManager transactionManager() {
...
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
...
}
public DataSource getDataSource() {
...
}
public JpaDialect getJpaDialect() {
...
}
public Properties getEclipseLinkProperty() {
...
}
public JpaVendorAdapter getJpaVendorAdapter() {
...
}
}
Service
....
public class MediaCodeDirectoryService implements MediaCodeDirectoryServiceApi {
...
#Autowired
private MediaCodeDirectoryRepository repo;
#SuppressWarnings("resource")
public static MediaCodeDirectoryServiceApi implementation() {
if (INSTANCE == null) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MediaCodeDirectoryServiceConfig.class);
INSTANCE = ctx.getBean(MediaCodeDirectoryService.class);
}
return INSTANCE;
}
...
Repository
...
#Repository
public interface MediaCodeDirectoryRepository extends CrudRepository<MediaCodeDao, Integer> {
#Cacheable("mediaCodeMappingRegexes")
#Query("SELECT m FROM #{#entityName} m WHERE (m.fooId = :fooId) AND (m.isRegex = :isRegex) ORDER BY (m.orderId DESC, m.id ASC)")
List<MediaCodeDao> findByfooIdAndIsRegexOrderByOrderIdDescAndIdAsc(#Param("fooId") int fooId, #Param("isRegex") boolean isRegex);
#Cacheable("mediaCodeMappings")
List<MediaCodeDao> findByMediaCode(String MediaCode, Pageable pageable);
}
When I debug into DefaultListableBeanFactory I can find within beanDefinitionMap my mediaCodeDirectoryService and also within beanDefinitionNames mediaCodeDirectoryService appears. But DefaultListableBeanFactory.getBean(...) cannot resolve name and namedBean in line 364 is null.
When I try to get the context via String like:
INSTANCE = (MediaCodeDirectoryService) ctx.getBean("mediaCodeDirecotryService")
I avoid the NoSuchBeanDefinitionException but I run into an other one.
Anybody here has an idea on what might be the cause of this? Did I missed something in my configuration? Thx!
Caching is applied through AOP. For AOP Spring uses a proxy based approach and the default is to create interface based proxies.
public class MediaCodeDirectoryService implements MediaCodeDirectoryServiceApi {... }
With this class definition at runtime you will get a dynamically created class (Proxy$51 or something along those lines) which implements all interfaces but it isn't a MediaCodeDirectoryService. It is however a MediaCodeDirectoryServiceApi.
You have 2 ways of fixing this, either program to interfaces (which you should have been doing anyway because you have defined interfaces) instead of concrete classes or use class based proxies.
The first option involves you changing your code in the places the directly #Autowire or get an instance of MediaCodeDirectoryService to use MediaCodeDirectoryServiceApi instead (which imho you should already do, why else define an interface). Now you will get the proxy injected and everything will work.
The second option involves you setting proxyTargetClass=true on your #EnableCaching annotation. Then instead of an interface based proxy you will get a class based proxy.
#EnableCaching(proxyTargetClass=true)

How to disable Spring autowiring in unit tests for #Configuration/#Bean usage

I want configure a component test using spring-test configuration inner class (#Configuration). Tested components has some services which I'd like to mock for the test. These services are classes (no interface used) and have spring annotations (#Autowired) in them. Mockito can easily mock them, however, I found no way of disabling spring autowiring.
Example how I can easily reproduce:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SomeTest.Beans.class)
public class SomeTest {
// configured in component-config.xml, using ThirdPartyService
#Autowired
private TestedBean entryPoint;
#Test
public void test() {
}
#Configuration
#ImportResource("/spring/component-config.xml")
static class Beans {
#Bean
ThirdPartyService createThirdPartyService() {
return mock(ThirdPartyService.class);
}
}
}
public class ThirdPartyService {
#Autowired
Foo bar;
}
public class TestedBean {
#Autowired
private ThirdPartyService service;
}
In this example "TestBean" represents the service to be mocked. I would NOT like "bar" to be injected by spring! #Bean(autowire = NO) does not help (in fact, that's the default value).
(Please save me from "use interfaces!" comments - the mocked service can be 3rd party which I can't do anything with.)
UPDATE
Springockito partially solves the problem, as long as you don't have to have anything else to configure (so you can't use configuration class with Springockito - it does not support it), but use mocks only.
Still looking for pure spring solution, if there's any...
Here is my solution to your problem:
import static org.mockito.Mockito.mockingDetails;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MockitoSkipAutowireConfiguration {
#Bean MockBeanFactory mockBeanFactory() {
return new MockBeanFactory();
}
private static class MockBeanFactory extends InstantiationAwareBeanPostProcessorAdapter {
#Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return !mockingDetails(bean).isMock();
}
}
}
and then just
#Import(MockitoSkipAutowireConfiguration.class)
in your test #Configuration and you are all set
I solved it by creating FactoryBean for my bean instead of just mocking bean. At this way Spring don't try to autowire fields.
Factory bean helping class:
public class MockitoFactoryBean<T> implements FactoryBean<T> {
private final Class<T> clazz;
public MockitoFactoryBean(Class<T> clazz) {
this.clazz = clazz;
}
#Override public T getObject() throws Exception {
return mock(clazz);
}
#Override public Class<T> getObjectType() {
return clazz;
}
#Override public boolean isSingleton() {
return true;
}
}
Actual test context part:
#Configuration
public class TestContext {
#Bean
public FactoryBean<MockingService> mockingService() {
return new MockitoFactoryBean<>(MockingService.class);
}
}
Check Spring profiles. You don't need to disable auto wiring, you need to inject different beans for different configuration.
You could add the mocked service manually to the spring application context via org.springframework.beans.factory.config.SingletonBeanRegistry#registerSingleton. This way the mock is not post-processed by spring and spring does not attempt to autowire the mock. The mock itself will be injected into your tested bean.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SomeTest.Beans.class)
public class SomeTest {
// configured in component-config.xml, using ThirdPartyService
#Autowired
private TestedBean entryPoint;
#Autowired
private ThirdPartyService thirdPartyServiceMock;
#Test
public void test() {
}
#Configuration
static class Beans {
#Autowired
private GenericApplicationContext ctx;
#Bean
TestedBean testedBean() {
ctx.getBeanFactory().registerSingleton("thirdPartyService", mock(ThirdPartyService.class));
return new TestedBean();
}
}
public static class ThirdPartyService {
#Autowired
Object bar;
}
public static class TestedBean {
#Autowired
private ThirdPartyService service;
}
}
I am in quite the same situation.
What I found that if you do not set the context loader by #ContextConfiguration annotation on your test class, the default context loader will be used, which derived from AbstractGenericContextLoader. I had a look at its source and turned out it registers all the bean post processors which are responsible for reading annotations such #Autowired. In other words, annotation config is enabled by default.
So the main problem is that there are two configurations which are in conflict: in the java config we said that autowiring is not needed, while the autowired annotation tells the opposite. The real question is how to disable the annotation processing in order to eliminate the undesired configuration.
As far as I know there is no such spring implementation of ContextLoader which would not be derived from AbstractGenericContextLoader so I guess the only we can do is to write our own. It would be something like this:
public static class SimpleContextLoader implements ContextLoader {
#Override
public String[] processLocations(Class<?> type, String... locations) {
return strings;
}
#Override
public ApplicationContext loadContext(String... locations) throws Exception {
// in case of xml configuration
return new ClassPathXmlApplicationContext(strings);
// in case of java configuration (but its name is quite misleading)
// return new AnnotationConfigApplicationContext(TestConfig.class);
}
}
Of course it would be worth to spend more time to find out how to implement ContextLoader properly.
Cheers,
Robert
There are so many ways of doing this, I'm pretty sure that this answer will be incomplete, but here are a few options...
As currently seems to be recommended practice, use constructor injection for your services rather than autowiring the fields directly. This makes testing like this so much easier.
public class SomeTest {
#Mock
private ThirdPartyService mockedBean;
#Before
public void init() {
initMocks(this);
}
#Test
public void test() {
BeanUnderTest bean = new BeanUnderTest(mockedBean);
// ...
}
}
public class BeanUnderTest{
private ThirdPartyService service;
#Autowired
public BeanUnderTest(ThirdPartyService ThirdPartyService) {
this.thirdPartyService = thirdPartyService;
}
}
By doing that, you can also mix up autowired and mocked services by autowiring into the test itself and then constructing the beans under test with the most useful mix of autowired and mocked beans.
A reasonable alternative is to use Spring profiles to define stub services. This is particularly useful when wish to use the same stubbed features in multiple tests:
#Service
#Primary
#Profile("test")
public class MyServiceStub implements MyService {
// ...
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SomeTest.Beans.class)
#ActiveProfiles({"test"})
public class SomeTest {
// ...
}
By using the #Primary annotation, it ensures that this stub bean will be used instead of any other bean implementing the MyService interface. I tend to use this approach for things like email services, where by changing profile, I'm able to switch between a real mail server and Wiser.

Categories