Spring Resource Assembler throwing NoSuchBeanDefinitionException - spring

I am using ResourceAssemblerSupport from spring-hateoas in a spring boot Application
I have created the assembler like below:
public class MemberResourceAssembler extends ResourceAssemblerSupport<Member, MemberResource>{
public MemberResourceAssembler(Class<?> controllerClass, Class<MemberResource> resourceType) {
super(controllerClass, resourceType);
}
#Override
public MemberResource toResource(Member member) {
MemberResource memberResource=new MemberResource();
memberResource.setStatus(member.getStatus());
memberResource.setHeight(member.getHeight());
memberResource.setIs_veg(member.getIs_veg());
memberResource.setRace(member.getRace());
memberResource.setWeight(member.getWeight());
return memberResource;
}
}
And the reource class as below:
public class MemberResource extends ResourceSupport implements Serializable{
//relevant code here
}
The domain class is as below:
#Document(collection="Member")
public class Member {
//relevant code here
}
The repository class is as below:
public interface MemberRepository extends PagingAndSortingRepository<Member,Integer> {
Page<Member> findByStatusContainsIgnoreCase(#Param("q") String status, Pageable pageable);
}
Now I am trying to use in my controller as below:
#RestController
#RequestMapping("/members")
public class MemberController {
#Autowired
private MemberRepository memberRepository;
#Autowired
private MemberResourceAssembler assembler;
#RequestMapping(value = "/search", method = RequestMethod.GET)
public PagedResources<MemberResource> search(#RequestParam("status") String status, #PageableDefault Pageable pageable,
PagedResourcesAssembler<Member> pagedAssembler) {
Page<Member> members = memberRepository.findByStatusContainsIgnoreCase(status, pageable);
return pagedAssembler.toResource(members, assembler);
}
}
I am getting below exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.sg.resources.MemberResourceAssembler] 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)}
Using spring-hateoas version 0.19.0.RELEASE.All the dependencies are coming through starters of Spring Boot 1.3.0.RELEASE
There is a spring boot Application class in the parent package of the Controller class.The Autowire annotation on the repository is working properly.

Your MemberResourceAssembler should be annotated as #Component to make it available for autowiring.

I added a bean definition in the Application.class which solved the issue
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public MemberResourceAssembler memberResourceAssembler() {
return new MemberResourceAssembler(MemberController.class, MemberResource.class);
}
}

Related

Why can't #Autowired a JPA repository - Spring boot + JPA

I'm giving this error:
Parameter 0 of constructor in x.microservice.module.business.application.BusinessCreator required a bean of type 'x.microservice.module.business.infrastructure.HibernateJpaRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=false)
Action:
Consider defining a bean of type 'x.microservice.module.business.infrastructure.HibernateJpaRepository' in your configuration.
The controller:
#Slf4j
#RestController
public final class BusinessPostController {
#Autowired
private BusinessCreator creator;
#PostMapping(value = "/business")
public ResponseEntity create(#RequestBody Request request){
BusinessCreatorDto businessCreatorDto = new BusinessCreatorDto(IdentifierEpoch.generate(),request.getName());
return ResponseEntity.ok(
creator.create(businessCreatorDto)
);
}
}
The Application Layer:
#AllArgsConstructor
#Service
public class BusinessCreator {
#Autowired
private HibernateJpaRepository repository;
public BusinessResponse create(BusinessCreatorDto dto){
Business business = new Business(dto.getId(), dto.getName());
repository.save(business);
return BusinessResponse.fromAggregate(business);
}
}
In the Infrastructure layer
#Repository
public abstract class HibernateJpaRepository implements JpaRepository<Business, Long> {
}
The boot Application:
#EnableJpaRepositories
#SpringBootApplication
public class MicroserviceApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceApplication.class, args);
}
}
All dependencies are resolved and the others classes I believe that are irrellevant.
Any suggestions? Thank you very much
Probably, the error cause is HibernateJpaRepository - it has to be an interface that extends JpaRepository.
You could write your own Repository in a interface:
#Repository
public interface HibernateJpaRepository extends JpaRepository < Business, Long > {
}
Then your Class:
#AllArgsConstructor
#Service
public class BusinessCreator {
#Autowired
private HibernateJpaRepository repository;
public BusinessResponse create(BusinessCreatorDto dto){
Business business = new Business(dto.getId(), dto.getName());
repository.save(business);
return BusinessResponse.fromAggregate(business);
}
}

Upgrade Spring Boot 2.0.8 to 2.1.2 - Failed to load ApplicationContext in tests

When upgrading spring from 2.0.8 to 2.1.2 (using JDK 8) the application starts and runs fine but tests fail due to java.lang.IllegalStateException: Failed to load ApplicationContext.
I am using an abstract class which some tests do extend.
#SpringBootTest
#RunWith(SpringRunner.class)
public abstract class AbstractTestkonfiguration {
#TestConfiguration
static class TestEnvironmentConfiguration {
#Component
#PropertySource(value = "classpath:my-test.properties")
#ConfigurationProperties(prefix = "my")
public static class MyTestProperties extends EnvironmentalProperties {
}
}
}
The class EnvironmentalProperties is a class for type-safe configuration properties (Doc)
Before the upgrade that worked and a class of EnvironmentalProperties was provided but now I am getting a
[...]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.abc.EnvironmentalProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#javax.inject.Inject()}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1651)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1210)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1164)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
... 90 more
Could it be related to a change in Nested Configuration Class Detection (Upgrading to Spring Framework 5.x)? If so, how can I configure a bean of EnvironmentalProperties only for tests?
Update: Even if used as follows it doesn't work (same result).
#SpringBootTest
#RunWith(SpringRunner.class)
public abstract class AbstractTestkonfiguration {
#Configuration
public static class TestEnvironmentConfiguration {
#Bean
public MyTestProperties environmentalProperties(){
return new EnvironmentalProperties() {
// manual creation of an instance
}
}
}
}
There are a few changes that you have to make.
You haven't enabled the configuration properties via #EnableConfigurationProperties
The property source needs to be injected at test class
Remove #Component annotation
Here is a working example;
src/test/resources/my-test.properties
my.server.name=foo
my.server=test
And
src/main/resources/application.properties
my.name=production
The production configuration.
#ConfigurationProperties(prefix = "my")
#PropertySource(value = "classpath:application.properties")
public class EnvironmentalProperties {
private String name;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
#SpringBootTest
#TestPropertySource(value = {"classpath:my-test.properties", "classpath:application.properties"})
#RunWith(SpringRunner.class)
public class AbstractTestkonfiguration {
#Autowired
private MyTestProperties myTestProperties;
#TestConfiguration
#EnableConfigurationProperties(MyTestProperties.class)
public static class TestEnvironmentConfiguration {
#ConfigurationProperties(prefix = "my")
public static class MyTestProperties extends EnvironmentalProperties {
private String server;
public String getServer() {
return server;
}
public void setServer(final String server) {
this.server = server;
}
}
}
#Test
public void check_configuration () {
Assert.assertEquals(myTestProperties.getServer(), "test");
Assert.assertEquals(myTestProperties.getName(), "production");
}
This works on Java 11 & spring-boot 2.1.2.RELEASE. Please note, this is only an example. You will have to adapt it to your project properly.

Spring: Register a component within a test class

I am registering an ErrorHandler for my Spring Scheduler and would like to test that is is correctly registered in a SpringTest
So far I have tried:
Handler
#Component
public class ScheduledErrorHandler implements ErrorHandler {
#Autowired
private ErrorService errorService;
#Override
public void handleError(final Throwable t) {
errorService.handle(t);
}
}
Registering the Handler
#EnableScheduling
#Configuration
public class SchedulingConfiguration implements SchedulingConfigurer {
#Autowired
private ScheduledErrorHandler handler;
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
final ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(1);
scheduler.setErrorHandler(handler);
scheduler.initialize();
taskRegistrar.setScheduler(scheduler);
}
//...
}
Testing it's registered
#ContextConfiguration(classes = {
SchedulerConfiguration.class,
SchedulerErrorHandler.class
})
#RunWith(SpringRunner.class)
public class SchedulerErrorHandlerTest {
#MockBean
private ErrorService service;
#Autowired
private ExampleScheduledJob job;
#Test
public void verifyHandlerGetsCalled() {
// Wait until the job runs
if(!job.latch.await(5, SECONDS)) {
fail("Job never ran");
}
verify(service).handle(any(RuntimeException.class));
}
#Component
public static class ExampleScheduledJob {
private final CountDownLatch latch = new CountDownLatch(1);
#Scheduled(fixedRate=1000)
public void run() {
latch.countDown();
throw new RuntimeException("error");
}
}
}
However when I do this I get a DependencyNotFound error saying Spring cannot create my test class as no Bean named ExampleScheduledJob can be found. How can I register it only for the sake of this test?
Error creating bean with name
'com.example.demo.SchedulerErrorHandlerTest': Unsatisfied dependency
expressed through field 'job'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
'com.example.demo.SchedulerErrorHandlerTest$ExampleScheduledJob'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
This should work
#ContextConfiguration(classes = {
SchedulingConfiguration.class,
SchedulerErrorHandlerTest.ExampleScheduledJob.class,
ScheduledErrorHandler.class
})
#RunWith(SpringRunner.class)
You can register your test configuration class (ExampleScheduledJob) as indicated above. Since it is a static inner class, you need to use it like SchedulerErrorHandlerTest.ExampleScheduledJob

Spring Boot cannot autowired component with abstract and interface

In my Spring Boot 2.0.2 application I am trying to inject a component herited from abstract class which implements an interface and it doesn't work.
Code :
Component Abstract : (Do I need to put #Component ?)
package app.project.service;
#Component
public abstract class AbstractStepService implements IStepService {
protected final void addTask() {
...
}
#Override
public StepDataDto launch() throws StepException {
...
}
}
Interface :
package app.project.service;
public interface IStepService {
StepDataDto launch() throws StepException;
}
package app.project.service;
Component :
#Component
public class CStepServiceImpl extends AbstractStepService implements IStepService {
#PostConstruct
private void defineTasks() {
}
}
package app.project.service;
Junit Test :
#RunWith(SpringRunner.class)
#SpringBootTest
public class CStepServiceTest {
#Autowired
#Qualifier("cStepServiceImpl")
private IStepService service;
}
package app.project;
Application :
#SpringBootApplication
#ComponentScan(basePackages ={"app.project.service"})
public class MyApplication {}
Error message when launching my Junit test :
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'app.project.service.IStepService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=cStepServiceImpl)}
Any idea ?
Thanks
Change your declaration like this
#Autowired
#Qualifier("CStepServiceImpl")
private IStepService service;
or
#Autowired
private IStepService CStepServiceImpl;
That should work. The bean name created automatically by spring has CStepServiceImpl name.
You can also name your bean like this
#Component(value = "myName")
public class CStepServiceImpl extends AbstractStepService implements IStepService {
}
and use myName during Autowiring.

Unsatisfied dependency during test

I have a spring boot 2.0.0 M2 application who run well.
I use autowired on constructor
#RequestMapping(value = "/rest")
#RestController
public class AddressRestController extends BaseController{
private final AddressService AddressService;
#Autowired
public AddressRestController(final AddressService AddressService) {
this.AddressService = AddressService;
}
...
}
#Service
public class AddressServiceImpl extends BaseService implements AddressService {
#Autowired
public AddressServiceImpl(final AddressRepository AddressRepository) {
this.AddressRepository = AddressRepository;
}
private final AddressRepository AddressRepository;
...
}
public interface AddressRepository extends JpaRepository<Address, Integer>, AddressRepositoryCustom {
}
#Repository
public class AddressRepositoryImpl extends SimpleJpaRepository implements AddressRepositoryCustom {
#PersistenceContext
private EntityManager em;
#Autowired
public AddressRepositoryImpl(EntityManager em) {
super(Address.class, em);
}
...
}
When i try to run a basic test
#RunWith(SpringJUnit4ClassRunner.class)
public class AddressServiceTest {
#Autowired
private AddressService service;
#MockBean
private AddressRepository restTemplate;
#Test
public void getAddress(){
MockitoAnnotations.initMocks(this);
Pageable page = PageRequest.of(0, 20);
Page<Address> pageAdr = mock(Page.class);
given(this.restTemplate.findAll(page)).willReturn(pageAdr);
Page<AddressDto> pageDto = service.getAddress(page);
}
}
I get this error
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'com.sonos.arcor.service.AddressServiceTest': Unsatisfied dependency
expressed through field 'service'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type ''com.sonos.arcor.service.AddressService'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I don't understand why i get this error.
You need to annotate the test with SpringBootTest so that spring initialize an application context
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications
#SpringBootTest
#RunWith(SpringJUnit4ClassRunner.class)
public class AddressServiceTest {
// the remaining test
}
Also you do not need MockitoAnnotations.initMocks(this);
Spring takes care of the mock handling
When [#MockBean is]used on a field, the instance of the created mock will also be
injected. Mock beans are automatically reset after each test method
see Mocking and spying beans

Resources