OptaPlanner SolverManager Bean not being found in Spring application - java

I am fairly new to working with Spring and I've come across a problem I cannot seem to resolve. I am trying to work with a package called Optaplanner. In this case I'm more or less following along with a simple course scheduler the video is here and the part I am working on happens at 51:00.
My problem is, one step of the process requires a dependency injection and when I build/run the Spring application I get the following error:
Description:
Field solverManager in com.java.optaplex.resource.MainResource required a bean of type 'org.optaplanner.core.api.solver.SolverManager' that could not be found.
The injection point has the following annotations:
- #javax.inject.Inject()
Action:
Consider defining a bean of type 'org.optaplanner.core.api.solver.SolverManager' in your configuration.
Process finished with exit code 1
I have used Gradle to manage my optaplanner package and I can see that the dependency is present (it is an interface called SolverManager). I cannot figure out why it cannot find/generate the bean however. I am assuming Spring would generate the bean on the fly much like a JPA repository's bean is created when using the #Autowired decorator. I have tried copying and pasting the SolverManager code to its own file under my project root and tried a few decorators on it (eg. #Component) in hopes that Spring would detect it, yet it still throws the same error and I am unsure what to do.
I have created a very simple demo app on GitHub here that has the error. The error is in the file src/main/java/com/java/optaplex/resource/MainResource.java
Also, in IntelliJ the SolverManager instance solverManager (see code below) is highlighted and says:
Could not autowire. No beans of 'SolverManager<Test, Long>' type found.
MainResource.java:
package com.java.optaplex.resource;
import com.java.optaplex.pojo.Test;
import org.optaplanner.core.api.solver.SolverManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.inject.Inject;
#RestController
#RequestMapping("/api")
public class MainResource {
// THE OFFENDING LINE IS HERE
#Inject
SolverManager<Test, Long> solverManager;
#GetMapping("/test")
public Test test () {
return new Test("Result message here");
}
}
For clarity, my Test class in the declaration of the Solver manager is:
Test.java
package com.java.optaplex.pojo;
public class Test {
private String message;
public Test(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
I realize my example code doesn't actually make use of the SolverManager, I just want the error on build to stop so I can proceed developing this. I just wanted to provide a very simple case that caused the error.
Lastly, my Gradle dependencies look like this:
build.gradle:
plugins {
id 'org.springframework.boot' version '2.2.6.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
id 'war'
}
group = 'com.java'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
// https://mvnrepository.com/artifact/org.optaplanner/optaplanner-core
compile group: 'org.optaplanner', name: 'optaplanner-core', version: '7.36.1.Final'
compile group: 'javax.inject', name: 'javax.inject', version: '1'
}
test {
useJUnitPlatform()
}

To make it work you just need to replace the #Inject annotation with #Autowire.
From the latest versions of Spring, the best practice is to use constructor dependency injection instead of #Autowire (the annotation is not required anymore as Spring will autowire beans automatically.
Try this:
#RestController
#RequestMapping("/api")
public class MainResource {
// Just the definition here
private SolverManager<Test, Long> solverManager;
pubilc MainResource(SolverManager<Test, Long> solverManager) {
// When Spring will start, the bean will be injected here and become
// available in this class
this.solverManager = solverManager;
}
#GetMapping("/test")
public Test test () {
// .....
}
// Other controller methods ....
}
I'm using IntelliJ, and it reports the error to me too. But I'm using the same code that I've posted in this answer and it works.
As you stated, the SolverManager bean is configured inside the optaplanner artifact, I suspect that the problem here is only the wrong annotation being used.
The IDE error bothers me too! But for the moment it works and I will leave it like this. In case I'll find a solution then I will add it here.

I am developing a API REST of route optimization with Spring Boot using OptaPlanner. I am just getting into the work with OptaPlanner and at one point I had this same problem. I had 'optaplanner-spring-boot-starter' and I added spring-boot-configuration-processor', with the idea of having the bean creation configuration that allows injecting the SolverManager in my classes, without success. Also I tried to change to other versions of OptaPlanner and without success. Finally I solved the problem adding the configuration that OptaPlanner includes in its code with the class 'RouteOptimizerConfig'. This class creates the bean of the solver, in such a way that already later I could inject it. This problem seems to be related to the fact that at a certain point the OptaPlanner SolverManager is overwritten.
Try this and add this class to your project:
#Configuration
class SolverConfig {
private final SolverFactory<VehicleRoutingSolution> solverFactory;
SolverConfig (SolverFactory<VehicleRoutingSolution> solverFactory) {
this.solverFactory = solverFactory;
}
#Bean
Solver<VehicleRoutingSolution> solver() {
return solverFactory.buildSolver();
}
}

It turns out, after a lot of online searches and digging through the Optaplanner Spring Boot packages the SolverManager bean is not provided for Spring. It seems the development focuses on the Quarkus framework.
I figured it was a good chance to try out Quarkus and once I made the change my code worked. There are some good videos on Youtube by the lead developer Geoffrey De Smet on setting up Optaplanner via Quarkus.

Related

Micronaut - What is Springframework #Bean equivalent?

I am very new to Micronauts and I have a fair bit of experience developing spring boot applications. With this background I was stumbled upon creating custom beans like how I used to create with #Bean annotations on Spring applications.
In my case I have a library that provides an Interface and its implementation class. I wanted to use the interface in my code and try to inject the implementation and it failes with below error
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [io.vpv.saml.metadata.service.MetaDataParser] exists for the given qualifier: #Named('MetaDataParserImpl'). Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Here is my code
#Singleton
public class ParseMetadataImpl implements ParseMetadata {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Inject
#Named("MetaDataParserImpl")
private MetaDataParser metaDataParser;
#Override
public IDPMetaData getIDPMetaData(URL url) throws IOException {
logger.info("Parsing {}", url);
logger.info("metaDataParser {}", metaDataParser);
return metaDataParser.parseIDPMetaData(url);
}
}
I am sure there is somehting wrong I am doing and need to understand what to do. I have this working by adding below code and removing annotations around metaDataParser.
#PostConstruct
public void initialize() {
//Want to Avoid This stuff
this.metaDataParser = new MetaDataParserImpl();
}
Using Spring Boot it would be possible to add a #Bean annotation to create some custom beans we can do #Autowired to inject it everywhere on our application. Is there an equivalent on Micronauths that I am missing. I went through the guide on https://docs.micronaut.io/2.0.0.M3/guide/index.html and was not able to get anything to get this working.
Can someone suggest how I can use the #Inject to inject custom beans?
Just incase you want to see this, here is the application on Github.
https://github.com/reflexdemon/saml-metadata-viewer
With the help from Deadpool and a bit of reading I got what I was looking for. The solution was creating #BeanFactory
See Javadoc here: https://docs.micronaut.io/latest/guide/ioc.html#builtInScopes
The #Prototype annotation is a synonym for #Bean because the default scope is prototype.
Thus here is an example that will match the the behavior of Spring framework
Here is the answer for anyone who also is looking for such a thing.
import io.micronaut.context.annotation.Factory;
import io.vpv.saml.metadata.service.MetaDataParser;
import io.vpv.saml.metadata.service.MetaDataParserImpl;
import javax.inject.Singleton;
#Factory
public class BeanFactory {
#Singleton
public MetaDataParser getMetaDataParser() {
return new MetaDataParserImpl();
}
}

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

Bean casting error from nested injections

I am working with Spring Integration with my project right now, specifically with MessageChannel/PublishSubscribeChannel. What I am trying to achieve is to create a broker module, so that other part of the system can call this module to send message to a specific MessageChannel.
Here is what I am doing now in the broker module:
#Configuration
public class BrokerConfiguration {
#Bean
public MessageChannel brokerChannel1() {
return new PublishSubscribeChannel();
}
}
and:
#Component
public class BrokerA {
#Autowired
#Qualifier("brokerChannel1")
public MessageChannel messageChannel;
public void sendAMessage() {
messageChannel.send(MessageBuilder.withPayload("This is a message!").build());
}
}
I have played around this setup by creating a SpringBootApplication within the broker module and it seems to work perfectly fine. However, when I try to use it in a different module of my system like this:
#Autowired
private BrokerA brokerA;
public void doSomethingHere() {
brokerA.sendAMessage();
}
I get a ClassCastException like this:
java.lang.ClassCastException: org.springframework.integration.channel.PublishSubscribeChannel cannot be cast to org.springframework.messaging.MessageChannel
And when I change messageChannel in BrokerA to the type of PublishSubscribeChannel, it will complain about PublishSubscribeChannel doesn't have a method called send().
This really baffles me. Any suggestions or comments? Thank you!
You have an old version of Spring Integration on the classpath; MessageChannel etc was moved from o.s.integration... to o.s.messaging in Spring 4.0.
You need to use Spring Integration 4.x.
Check your classpath, probably you have duplicated jars.
I ran your code on my environment with last spring boot version without any version specification about spring and it's working just right, the only error is on
MessageBuilder.withPayload("This is a message!") it should be MessageBuilder.withPayload("This is a message!").build()
And I verified using org.springframework.integration.support.MessageBuilder.
Try doing an explicit cast in the return statement of brokerChannel1() in BrokerConfiguration.

Error Injecting FeignClient from another Project

I am having trouble auto wiring a feign client from another project. It appears that the implementation of the feign client is not being generated and injected.
This is the error I am getting.
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'passportRestController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.wstrater.service.contacts.client.ContactService com.wstrater.service.passport.server.controllers.PassportRestController.contactService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.wstrater.service.contacts.client.ContactService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
The feign client is pretty straight forward. I have removed the imports for brevity.
package com.wstrater.service.contacts.client;
#FeignClient("contact-service")
public interface ContactService {
#RequestMapping(method = RequestMethod.GET, value = ContactConstants.CONTACTS_USER_ID_PATH)
public Collection<Contact> contactsByUserId(#PathVariable("userId") String userId);
}
I added the component scan to my project to include the application and it's controllers and to include the feign client in the other project.
package com.wstrater.service.passport.server;
#EnableEurekaClient
#EnableFeignClients
#SpringCloudApplication
#ComponentScan({"com.wstrater.service.passport.server",
"com.wstrater.service.contacts.client"})
public class PassportServiceApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(PassportServiceApplication.class, args);
}
}
The rest controller with most of the imports removed for brevity.
package com.wstrater.service.passport.server.controllers;
import com.wstrater.service.contacts.client.ContactService;
#RestController
public class PassportRestController {
#Autowired
private ContactService contactService;
#RequestMapping(PassportContstants.PASSPORT_USER_ID_PATH)
public ResponseEntity<Passport> passportByUserId(#PathVariable String userId) {
ResponseEntity<Passport> ret = null;
Collection<Contact> contacts = contactService.contactsByUserId(userId);
if (contacts == null || contacts.isEmpty()) {
ret = new ResponseEntity(HttpStatus.NOT_FOUND);
} else {
ret = ResponseEntity.ok(new Passport(contacts));
}
return ret;
}
}
I have tried defining the feign client interface in different projects and different packages and have only seen success when it put it in the same package as the application. This make be believe that it is a component scan issue even though I am including the package in the scan. I would like to keep the feign client interface in a shared project to define a reusable "contract" and for each project to have a unique package structure instead of defining the feign client with the application using it.
Thanks, Wes.
You need to tell the Feign scanner where to locate the interfaces.
You can use #EnableFeignClients(basePackages = {"my.external.feign.client.package", "my.local.package"}).
Direct Class/Interface name can be given like below
#EnableFeignClients(basePackageClasses=com.abc.xxx.client.XXFeignClient.class)
This parameter accept single or multiple class name
My main class was in package "com.abc.myservicename" and my main class name was "myservicename.java". I was using #SpringBootApplication(scanBasePackages="com.abc") annotation in my main class.
Changing the main class package name to "com.abc" has resolved the issue for me.
Thanks for the help. I added the right external package in
#EnableFeignClients(basePackages = {})
It still did not pick up the feign client implementation.
I had a PACT contract test where I was autowiring the api client bean. I had used #ExtendWith(SpringExtension.class) which was the issue.
I replaced with #SpringBootTest, which allowed the feign client bean to be exposed in this class
Faced the Same issue where i was not able to #Autowire the FeignClient interface, Changing the Version of Feign Client in pom.xml to 3.0.1 or latest has helped me in resolving the issue.
This worked for me.
Adding annotation to main class
#EnableFeignClients(defaultConfiguration = {FeignBasicConfiguration.class}, basePackages = {"com.example"})

Categories