#PostConstruct and #PreDestroy annotations do not work - java

I have TennisCoach class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
#Component
public class TennisCoach implements Coach {
#Autowired
#Qualifier("randomFortuneService")
private FortuneService fortuneService;
public TennisCoach() {
System.out.println("Inside default constructor");
}
#PostConstruct
public void doMyStartupStuff() {
System.out.println("Inside postconstructor");
}
#PreDestroy
public void doMyFinalStuff() {
System.out.println("Inside predestroyer");
}
#Override
public String getDailyFortune() {
return fortuneService.getFortune();
}
#Override
public String getDailyWorkout() {
return "Practice your backhand volley";
}
}
And such main class:
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationBeanScopeDemoApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Coach theCoach = context.getBean("tennisCoach", Coach.class);
System.out.println(theCoach.getDailyFortune());
System.out.println(theCoach.getDailyWorkout());
context.close();
}
}
Expected output is:
Inside default constructor
Inside postconstructor
DailyFortune
Practice your backhand volley
Inside predestroyer
But I get this:
Inside default constructor
DailyFortune
Practice your backhand volley
It seems like #PostContruct and #PreDestroy annotations do not work correctly. I cannot find the reason of my problem.

Spring might not handle JSR-250 lifecycle annotations by default. Check your applicationContext.xml that it has element:
<beans ...
<context:annotation-config/>
....
</beans>
that configures Spring to be aware of #PostConstruct & #PrePersist.
Fo more info see this article.

From the Spring Core documentation, paragraph 1.9.8 - Using #PostConstruct and #PreDestroy
Provided that the CommonAnnotationBeanPostProcessor is registered
within the Spring ApplicationContext, a method carrying one of these
annotations is invoked at the same point in the lifecycle as the
corresponding Spring lifecycle interface method or explicitly declared
callback method.
Declaring
<context:annotation-config/>
inside you applicationContext.xml file, implicitly register a CommonAnnotationBeanPostProcessor.
Otherwise, you need to manually register it, using (docs)
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />

If you use java 9+ then add dependency javax.annotation:javax.annotation-api (or use java 8).
Or use spring-boot 2 if you using spring-boot 1.

Your Spring don't know about annotation's #PostContruct and #PreDestroy.
Add this code in your applicationContext.xml
<bean class = "org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
Or implements InitializingBean,DisposableBean interfaces in your TenisCoach class.

Eclipse is unable to import #PostConstruct or #PreDestroy
This happens because of Java 9 and higher.
When using Java 9 and higher, javax.annotation has been removed from its default classpath.
Solution
Download the javax.annotation-api-1.3.2.jar from
maven.org
Copy the JAR file to the lib folder of your project
Use the following steps to add it to your Java Build Path.
Right-click your project, select Properties
On left-hand side, click Java Build Path
In top-center of dialog, click Libraries
Click Classpath and then Click Add JARs ...
Navigate to the JAR file /lib/javax.annotation-api-1.3.2.jar
Click OK then click Apply and Close
Eclipse will perform a rebuild of your project and it will resolve the related build errors.

Related

How to rewrite spring configuration from XML to Java

I have Spring XML configuration file like this:
<bean id="A" class="a.b.c.d.ConfigurationA" />
<bean class="a.b.c.d.ConfigurationB" />
<bean id="C" class="a.b.c.d.e.ConfigurationC" depends-on="objectFromConfigurationB" />
Each configuration file import other config classes. Example:
#Configuration
#Import({ConfigA.class, ConfigB.class})
class ConfigurationA {
#Bean
public ABC abc() {
return new ABC();
}
...
...
..
}
I would like to rewrite this XML config into Java keeping all relations (depends-on). How can I do it?
I tried with:
ComponentScan
Import
always the same: beans from inner configuration files are not loaded into spring context. I caught No bean 'A' available error during startup.
How to create depends-on relation during import configuration bundle?
With component scanning you should not need to do anything.
#Component
class A {
}
#Component {
class B {
}
#Componet {
class C {
private final B b;
#Autowired
C(B b) {
this.b = b;
}
}
Using constructor injection in component C gets you exactly what you want, there is no need to do the depends on. If you are newer versions of spring you don't even need the #Autowired on the constructor.
I converted a project with about 10 XML spring files into Java Configuration. I found that writing #Bean definitions each one in an #Configuration class was not necessary, I thought it would cause bootup times to be faster but made no difference. Using component scanning is lot less code and makes things much simpler. If you are on spring boot you need to make sure that the packages that have code in them are being scanned, for example if you have library in com.example.lib and the #SpringBootApplication class is in com.example.app then the beans in com.example.lib won't be picked up because by default it will scan only the child packages of com.example.app you will need to add more packages to scan to the config or move the main spring boot app class to com.example
You are looking for #DependsOn in your ConfigurationC as follows: #DependsOn("name-of-bean-B").

Adding new dependency to my Spring Boot project breaks existing #Autowired setup

I am encountering a baffling #Autowired issue, which only occurred after I added a dependency to one of my own projects.
Here is the situation:
I am extending a service, which has autowired repositories. Here's the simplified version:
package com.opt.custom.domain;
import com.opt.repo.RepositoryOne;
import com.opt.repo.RepositoryTwo;
#Primary
#Service("CustomDomainServiceImpl")
public class CustomDomainServiceImpl extends DomainServiceImpl {
private RepositoryOne repo1;
private RepositorTwo repo2;
#Autowired
public CustomDomainServiceImpl(RepositoryOne repo1
, RepositorTwo repo2) {
super(repo1, repo2);
}
....
}
This has been working fine - the #Autowired tags grab the repositories fine, whether or not I include them as attributes, as I don't use them except to feed into the parent service.
However, I have created another service (with its own service, repositories, etc.). When I add this new service as a dependency of the above project (in the POM file), the #Autowired annotations in the above code stop working, even if I don't reference any of the services, repos, etc. in this class. Specifically, the error is:
Parameter 0 of constructor in com.opt.custom.domain.CustomDomainServiceImpl required a bean of type 'com.opt.repo.RepositoryOne' that could not be found.
Action:
Consider defining a bean of type 'com.opt.repo.RepositoryOne' in your configuration.
I don't know how simply adding a dependency (while not using anything from it) can cause this issue.
I have tried adding a #ComponentScan to the above class:
#ComponentScan(basePackages = {"com.opt.repo"})
But this has not helped.
If it helps, this is the top-level class in the Maven project that I am adding as a dependency:
package com.opt.new.service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
#SpringBootApplication
#EntityScan(basePackages = { "com.someotherpackage.persistence.*" })
public class PersistenceClasses {
public static void main(String[] args) {
SpringApplication.run(PersistenceClasses .class, args);
}
}
Thank you for any insights you can provide.
#ComponentScan annotation should be added to the spring boot application class. In your case, its PersistenceClasses. Also, make sure to have a #Repository annotation on your RepositoryOne class
#Repository is a spring stereotype, identifying spring components in an application. More information on it can be found here

Consider defining a bean of type 'package' in your configuration [Spring-Boot]

I am getting the following error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method setApplicant in webService.controller.RequestController required a bean of type 'com.service.applicant.Applicant' that could not be found.
Action:
Consider defining a bean of type 'com.service.applicant.Applicant' in your configuration.
I have never seen this error before but it's odd that the #Autowire is not working. Here is the project structure:
Applicant Interface
public interface Applicant {
TApplicant findBySSN(String ssn) throws ServletException;
void deleteByssn(String ssn) throws ServletException;
void createApplicant(TApplicant tApplicant) throws ServletException;
void updateApplicant(TApplicant tApplicant) throws ServletException;
List<TApplicant> getAllApplicants() throws ServletException;
}
ApplicantImpl
#Service
#Transactional
public class ApplicantImpl implements Applicant {
private static Log log = LogFactory.getLog(ApplicantImpl.class);
private TApplicantRepository applicantRepo;
#Override
public List<TApplicant> getAllApplicants() throws ServletException {
List<TApplicant> applicantList = applicantRepo.findAll();
return applicantList;
}
}
Now I should be able to just Autowire Applicant and be able to access, however in this case it is not working when I call it in my #RestController:
#RestController
public class RequestController extends LoggingAware {
private Applicant applicant;
#Autowired
public void setApplicant(Applicant applicant){
this.applicant = applicant;
}
#RequestMapping(value="/", method = RequestMethod.GET)
public String helloWorld() {
try {
List<TApplicant> applicantList = applicant.getAllApplicants();
for (TApplicant tApplicant : applicantList){
System.out.println("Name: "+tApplicant.getIndivName()+" SSN "+tApplicant.getIndSsn());
}
return "home";
}
catch (ServletException e) {
e.printStackTrace();
}
return "error";
}
}
------------------------UPDATE 1-----------------------
I added
#SpringBootApplication
#ComponentScan("module-service")
public class WebServiceApplication extends SpringBootServletInitializer {
#Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(WebServiceApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(WebServiceApplication.class, args);
}
}
and the error went away but nothing happened. However when I commented out everything dealing with Applicant in the RestController prior to adding #ComponentScan() I was able to return a string the UI, thus meaning my RestController was working, now it is being skipped. I ugly Whitelabel Error Page now.
---------------------UPDATE 2------------------------------
I added the base package of the bean it was complaining about. Error reads:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method setApplicantRepo in com.service.applicant.ApplicantImpl required a bean of type 'com.delivery.service.request.repository.TApplicantRepository' that could not be found.
Action:
Consider defining a bean of type 'com.delivery.request.request.repository.TApplicantRepository' in your configuration.
I added #ComponentScan
#SpringBootApplication
#ComponentScan({"com.delivery.service","com.delivery.request"})
public class WebServiceApplication extends SpringBootServletInitializer {
#Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(WebServiceApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(WebServiceApplication.class, args);
}
}
----------------------------Update 3----------------------
adding:
#SpringBootApplication
#ComponentScan("com")
public class WebServiceApplication extends SpringBootServletInitializer {
still is complaining about my ApplicantImpl class which #Autowires my repo TApplicantRepository into it.
It might be because the project has been broken down into different modules.
#SpringBootApplication
#ComponentScan({"com.delivery.request"})
#EntityScan("com.delivery.domain")
#EnableJpaRepositories("com.delivery.repository")
public class WebServiceApplication extends SpringBootServletInitializer {
There is a chance...
You might be missing #Service, #Repository or #Component annotation on your respective implementation classes.
Your Applicant class is not scanned it seems. By default all packages starting with the root as the class where you have put #SpringBootApplication will be scanned.
suppose your main class "WebServiceApplication" is in "com.service.something", then all components that fall under "com.service.something" is scanned, and "com.service.applicant" will not be scanned.
You can either restructure your packages such that "WebServiceApplication" falls under a root package and all other components becomes part of that root package. Or you can include #SpringBootApplication(scanBasePackages={"com.service.something","com.service.application"}) etc such that "ALL" components are scanned and initialized in the spring container.
Update based on comment
If you have multiple modules that are being managed by maven/gradle, all spring needs is the package to scan. You tell spring to scan "com.module1" and you have another module which has its root package name as "com.module2", those components wont be scanned. You can even tell spring to scan "com" which will then scan all components in "com.module1." and "com.module2."
Basically this happens when you have your Class Application in "another package". For example:
com.server
- Applicacion.class (<--this class have #ComponentScan)
com.server.config
- MongoConfig.class
com.server.repository
- UserRepository
I solve the problem with this in the Application.class
#SpringBootApplication
#ComponentScan ({"com.server", "com.server.config"})
#EnableMongoRepositories ("com.server.repository") // this fix the problem
Another less elegant way is to: put all the configuration classes in the same package.
In my case I had a terrible mistake. I put #Service up to the service interface.
To fix it, I put #Service on the implementation of service file and it worked for me.
If a bean is in the same package in which it is #Autowired, then it will never cause such an issue. However, beans are not accessible from different packages by default.
To fix this issue follow these steps :
Import following in your main class:
import org.springframework.context.annotation.ComponentScan;
add annotation over your main class :
#ComponentScan(basePackages = {"your.company.domain.package"})
public class SpringExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringExampleApplication.class, args);
}
}
Important:
For anybody who was brought here by googling the generic bean error message, but who is actually trying to add a feign client to their Spring Boot application via the #FeignClient annotation on your client interface, none of the above solutions will work for you.
To fix the problem, you need to add the #EnableFeignClients annotation to your Application class, like so:
#SpringBootApplication
// ... (other pre-existing annotations) ...
#EnableFeignClients // <------- THE IMPORTANT ONE
public class Application {
Side note: adding a #ComponentScan(...) beneath #SpringBootApplication is redundant, and your IDE should flag it as such (IntelliJ IDEA does, at least).
This can also happen if you are using Lombok and you add the #RequiredArgsConstructor and #NonNull for fields but some of your fields are not to be injected in the constructor. This is only one of the possibilities to get the the same error.
parameter 0 required a bean of type MissingBeanName that could not be found
In my case the error told me what Controller the problem was in, after removing #NonNull the application started fine
In my case these two options worked.
in //#ComponentScan ({"myapp", "myapp.resources","myapp.services"})
include also the package which holds the Application.class in the list, or
Simply add #EnableAutoConfiguration; it automatically recognizes all the spring beans.
I faced with familiar problem in my Maven multi-module project with Spring Boot 2. The problem was related to naming of my packages in sub Maven modules.
#SpringBootApplication incapsulate a lots of component like - #ComponentScan, #EnableAutoConfiguration, jpa-repositories, json-serialization and so on. And he places #ComponentScan in com.*******.space package. This part of packages com.*******.space must be common for all modules.
For fixing it:
You should rename all module packages. Other words you had to have in all packages in all Maven modules - the same parent part. For example - com.*******.space
Also you have to move your entry point to this package - com.*******.space
I think you can make it simplified by annotating your repository with #Repository, then it will be enabled automatically by Spring Framework.
It worked for me after adding below annotation in application:
#ComponentScan({"com.seic.deliveryautomation.mapper"})
I was getting the below error:
"parameter 1 of constructor in required a bean of type mapper that could not be found:
Moving the Springbootapplication(application.java) file to another package resolved the issue for me. Keep it separate from the controllers and repositories.
In my case this error appear because my import was wrong, for example, using spring, the import automatically appear:
import org.jvnet.hk2.annotations.Service;
but i needed:
import org.springframework.stereotype.Service;
I faced the same issue. Mongo DB repository was identified by Spring boot, but it was not creating Bean for a repository interface that extended the mongo repository.
The issue in my case was incorrect version specification in maven pom for "spring + mango". I have changed the artifact's group id and it all worked like magic. no annotations needed as spring boot took care of everything.
During my problem resolution, I was all over web searching for solutions and realized that this problem is actually project configuration related, anyone facing this issue should first check their project setup and enable debug from spring to get more details on failure and pay close attention to where exactly in the process, the creation has failed.
I sought online for an answer but it seems there is no one proper solution to my case:
At the very beginning, everything works well as follows:
#Slf4j
#Service
#AllArgsConstructor(onConstructor = #__(#Autowired))
public class GroupService {
private Repository repository;
private Service service;
}
Then I am trying to add a map to cache something and it becomes this:
#Slf4j
#Service
#AllArgsConstructor(onConstructor = #__(#Autowired))
public class GroupService {
private Repository repository;
private Service service;
Map<String, String> testMap;
}
Boom!
Description:
Parameter 4 of constructor in *.GroupService required a bean of type 'java.lang.String' that could not be found.
Action:
Consider defining a bean of type 'java.lang.String' in your configuration.
I removed the #AllArgsConstructor(onConstructor = #__(#Autowired)) and add #Autowired for each repository and service except the Map<String, String>. It just works as before.
#Slf4j
#Service
public class SecurityGroupService {
#Autowired
private Repository repository;
#Autowired
private Service service;
Map<String, String> testMap;
}
Hope this might be helpful.
This can happen if the #Service class is marked abstract.
#Configuration annotation will just solve the error
You'll also get this error if you accidentally define the same bean in two different classes. That happened to me. The error message was misleading. When I removed the extra bean, the issue was resolved.
My error was that I had included:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
instead of:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
It might help somebody. I had the same problem, same error message, same everything. I tried solutions from other answers, didn't help until I realised that the bean I am using has the same name as the one that is actually been autowired. It happened in the midst of refactor, thus I had to rename the class, which resulted positively. Cheers
Try configuring the project structure as given below:
Put all the repo, service, packages in the child package of the main package:
package com.leisure.moviemax; //Parent package
#SpringBootApplication
#PropertySource(value={"classpath:conf.properties"})
public class MoviemaxApplication implements CommandLineRunner {
package com.leisure.moviemax.repo; //child package
#Repository
public interface UsrRepository extends JpaRepository<UserEntity,String> {
This error message also pops up when you fail to annotate the Entity classes associated with your bean with the #Entity Annotation.
My ComponentScan worked fine but this popped up for the #repository interface:
#Repository
public interface ExpenseReportAuditRepository extends
PagingAndSortingRepository<ExpenseReportAudit, Integer> {
because I failed to add the #Entity annotation to ExpenseReportAudit
#Entity // <--- Adding this fixed the issue.
public class ExpenseReportAudit {
.....
#SpringBootApplication
#MapperScan("com.developer.project.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I had a case where i need to inject RestTemplate into a service class. However, the RestTemplate cannot be picked up by the service class. What I did is to create a wrapper class under the same package as main application and mark the wrapper as Component and autowire this component in the service class. Problem solved. hope it also works for you
If your class dependency is managing by Spring then this issue may occur if we forgot to add default/empty arg constructor inside our POJO class.
There is a chance that you are trying to #autowired an interface before implement the interface.
example solution:
**HomeController.java**
class HomeController{
#Autowired
UserService userService;
.....
}
----------------------------------------------------------------------
**UserService.java**
public interface UserService {
User findByUsername(String username);
.....
}
-----------------------------------------------------------------------
**UserServiceImpl.java**
#Service
public class UserServiceImpl implements UserService{
public User findByUsername(String username) {
return userDao.findByUsername(username);
}
....
}
<i>This is not italic</i>, and [this is not a link](https://example.com)
In my case, our project has a Configuration class, so I just added mine like this
#Configuration
public class DependencyConfiguration {
#Bean
public ActivityService activityService(
#Value("${send.money.ms.activity.url}") final String activityHistoryUrl,
final HttpRestService httpRestService
) {
return new ActivityServiceImpl(activityHistoryUrl, httpRestService);
}
.......................
Then the microservice started alright.
PS: I encountered this issue even though the library I need is imported properly and could be seen on External Libraries imported.
Had the same error, transpired it was an issue with the application properties with incorrect username, password and driver and completely unrelated to Bean.
I also received a similar error:
Consider defining a bean of type 'A_REPOSITORY_INTERFACE' in your configuration.
Then, according to Akashe's solution, I added #EnableJpaRepositories to my main class. After that, I received the following error instead:
Consider defining a bean of type 'entityManagerFactory' in your configuration.
Next, I went through all the responses here, googled a lot and read a lot of other resources, which didn't worked out.
Finally, I was lucky to have found the solution on a blog/website (javatute.com). I just followed its examples.
Like suggested by many here, I added #ComponentScan("YOUR_BASE_PACKAGE.*") and #EntityScan("YOUR_BASE_PACKAGE.*") to my main app class, followed by adding a config package and creating a JpaConfig class like:
package YOUR_BASE_PACKAGE.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#Configuration
#EnableJpaRepositories(basePackages = "YOUR_BASE_PACKAGE")
public class JpaConfig {
}
The blog I followed:
Consider defining a bean of type in your configuration
which lead me to:
Error creating bean with name entityManagerFactory defined in class path resource : Invocation of init method failed
and finally to:
Many To Many Mapping In Hibernate/JPA Using Spring Boot And Oracle

spring boot: run different init code for prod and tests

I am converting an existing Java application to Spring Boot.
I'm a Spring Boot newbie. I know Spring Boot has support for application.properties, which is great for new apps. But this is a legacy app and I need an interim solution for now - without completely redesigning it. This app needs to call some initializer with a property file on startup. There is prod.properties and another one for tests - test.properties.
the prod file needs to be loaded from a specific location on disk (/mydir/prod.properties), while test.properties comes from tests' classpath.
also, may legacy classes require this "property class" to be initialized on their creation (they reference it in their static initializers, oh geez...) - so this init needs to happen before Spring Components are loaded.
what would be the easiest solution?
I came up with this overly-verbose-boiler-plate solution. it works, but maybe there is an easier way?
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.inject.Inject;
#SpringBootApplication
public class DemoApplication implements CommandLineRunner {
#Inject
private Initializer initializer;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
initializer.init();
}
}
public interface Initializer {
void init();
}
#Component
public class ProdInitializer implements Initializer {
#Override
public void init() {
System.out.println("PROD init - will load properties file from /myfolder/ and call some init class with it");
}
}
// and this is from TESTS section:
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
#Primary
#Component
public class TestInitializer implements Initializer {
#Override
public void init() {
System.out.println("TEST init - will load properties file from classpath and call some init class with it");
}
}
I tried having just one initializer with an additional test/resources/application.properties file with just 1 value in it (legacy property file location) hoping that Spring Boot would load application.properties from PROD code, then load the only value present in test/resources/application.properties and override the corresponding value in main/resources/application.properties, but no luck - apparently, Spring Boot ignores main/resources/application.properties for tests if test/resources/application.properties is present. so I would have to duplicate all settings from main/resources/application.properties in test/resources/application.properties with just one property being different.

How do I unit-test Maven multi-module Spring app?

I'm having problems trying to unit test a maven multi-module project with Spring.
I've 4 modules:
application-core
application-data
application-service
application-web
This is my test, its in the application-core module:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:/config/application-context.xml")
public class TicketTest {
#Mock
ITicketDAO ticketDAO;
#Autowired
#InjectMocks
ITicketCore ticketCore;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testRegisterTicket_Ticket_NotUsed_isValid() {
Long ticketNumber = 0L;
when(ticketDAO.getTicket(anyLong())).thenReturn(null);
final boolean isValidTicket = ticketCore.validateTicket(ticketNumber);
assertTrue(isValidTicket);
}
}
And here is the implementation:
#Component
#Scope("prototype")
public class TicketCore implements ITicketCore{
private ITicketDAO ticketDao;
#Autowired
public TicketCore(ITicketDAO ticketDao) {
this.ticketDao = ticketDao;
}
#Override
public boolean validateTicket(Long ticketNumber) {
ITicket ticket = ticketDao.getTicket(ticketNumber);
return ticket != null;
}
}
Interface:
public interface ITicketDAO {
ITicket getTicket(Long ticketNumber);
}
Implementation of ITicketDAO its on the application-data module:
#Service
public class TicketDAO implements ITicketDAO {
#Override
public ITicket getTicket(Long ticketNumber) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
}
I'm having problems testing this code because the context doesn't find the implementation of ITicketDAO. It's seems obvious, because when the test are running, JUnit doesn't care about putting in the classpath the "others modules".
Spring throws BeanCreationException for obvious reasons.
Am I right?
So I would like to test my project without Spring getting in the tests' way.
What could I do to get my tests run w/o any problem???
I've created dummy classes in the test folder/packages, and it works, but...
I would eventually have ALL the external implementations in my application-core module's test folder.
There is a better way?
Thanks in advance.
UPDATE:
application-data
application-service
application-web
all of them depends on application-core. Spring successfully inject TicketCore(application-core). What I want is to give Spring "something" (a dummy class) to inject in ITicketDAO just to run the test.
<beans>
<context:component-scan base-package="ve.gov.imat.transimat" />
<context:annotation-config />
<aop:config proxy-target-class="true" />
</beans>
Pretend that each Maven module is a completely separate project. Put tests specifically of each module's code inside it, and add integration tests in the module where all of the dependencies necessary to run them have been included.
You haven't provided any information on the dependencies between your modules, but it appears that the problem you're running into is that you need some implementation of an interface for testing purposes, but your production bean is defined in another module. This is what mocking frameworks like EasyMock and Mockito are for; they allow you to write simple placeholder implementations so that you can test TicketCore specifically, and it's a good idea to use them even when the real implementation is available so that you can be sure you're just testing one component at a time.
In TicketTest, you're correctly defining your Mockito mock for ITicketDAO, but your TicketCore is still trying to autoacquire the bean from Spring, even though you haven't registered it. Either manually register your bean into the test context, or place the definition for the mock in an #Configuration in src/test.
If I've understood you well your problem is your context file references a class you don't have available in your test classpath.
In principle tests shouldn't need the implementation of any collaborator to work, only the one of the sut.
One solution is to create an application-test-context.xml file under your test/resources folder to be used in your test instead of the production one. Within this file you can create the mocks of your collaborators
<!-- Mock service for splitting jobs -->
<bean factory-bean="mockControl" factory-method="createMock"
primary="true">
<constructor-arg value="net.compart.docpilot.model.service.JobSplitService" />
</bean>

Categories