Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@SpringBootApplication and @ComponentScan not working together (bean configuration)

I have a multi module project but I am having a problem with my configuration. I have a my main method in package nl.example.hots.boot

@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan(basePackages = {"nl.*"})
@EntityScan("nl.*")
public class HotsApplication {

    public static void main(String[] args) {
        SpringApplication.run(HotsApplication.class, args);
    }

In the nl.example.hots.core.* package I have the class:

@Service
@AllArgsConstructor
@Transactional(propagation = Propagation.REQUIRED)
public class MapImportService {

    private MapInputModelMapper mapInputModelMapper;
    private MapEntityRepository mapEntityRepository;

    public void add(final MapInputModel mapInputModel) {
        System.out.println(mapInputModel.getName());
        mapEntityRepository.save(mapInputModelMapper.mapToEntiy(mapInputModel));
    }

and:

@Component
@Mapper
public interface MapInputModelMapper {

    MapInputModel mapToInputModel(final MapEntity n);

    MapEntity mapToEntiy(final MapInputModel n);

}

The repository is in the package nl.example.hots.persistence.*

I get the following error when running the application:

Description:

Parameter 0 of constructor in nl.example.hots.core.dataimport.MapImportService.MapImportService required a bean of type 'nl.timonschultz.hots.core.map.mapper.MapInputModelMapper' that could not be found.


Action:

Consider defining a bean of type 'nl.example.hots.core.map.mapper.MapInputModelMapper' in your configuration.

When I remove the @EnableAutoConfiguration and @ComponentScan annotations it works. The application starts without the bean error.

In that case however my restcontroller does not work anymore:

{
    "timestamp": "2018-07-18T20:48:39.414+0000",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/maps"
}

When I remove the MapImportService class (and the bean error doesn't pop up) it works on the same url.

package nl.example.hots.api.data_import;

@RestController
@AllArgsConstructor
public class ImportController {

    private static final String URL = // a url
    private Reader reader;

    @RequestMapping("/maps")
    public String abilityStreamImport() {
        reader.readStream(URL); // calls a class in nl.example.hots.core.*
        return "Greetings from APP!";
    }
}

I tried several different combinations and I have a different project as and example where the annotations are used together and it works right. Can somebody explain why the annotations generate the bean error when used together? And why the controller gives an error when only using @SpringBootApplication?

In my Pom.XML the boot module has a dependency on the API layer that has a dependency on the core layer that has a dependeny on the persistence layer. I'm using mapstruct and Lombok in the project.

--- edit: repository ---

@Entity(name = "MAPS")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class MapEntity extends HasId<Long> {

    private String name;

    @ElementCollection
    private List<String> translations;

}

@Repository
public interface MapEntityRepository extends JpaRepository<MapEntity, Long> {
}

@MappedSuperclass
public abstract class HasId<T> {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Setter
    @Getter
    private T id;
}

project structure:

hots-application;
- hots-api
    - pom.xml
    - nl.example.hots.api.dataimport.ImportController;
- hots-boot
    - pom.xml
    - nl.example.hots.boot.HotsApplication;
- hots-core
    - pom.xml
    - nl.example.hots.core.dataimport.mapImportService.MapImportService;
    - nl.example.hots.core.map.mapper.MapInputModelMapper
- hots-persistence
    - pom.xml
    - nl.example.hots.persistence.common.HasId;
    - nl.example.hots.persistence.map.MapEntity;
    - nl.example.hots.persistence.map.MapEntityRepository;
pom.xml
like image 599
Bowerick Avatar asked Jul 18 '18 20:07

Bowerick


2 Answers

Spring Boot will scan all the packages and sub packages starting with the package that the @SpringBootApplication annotated class is in. Your class is in nl.example.hots.boot scanning only that package. The other classes are in different, non-scanned packages.

Due to this package structure and not following the best practices you basically loose a lot of the auto configuration features (Spring Data JPA, ReST etc) and you have to resort to manually enabling/configuring that. Partially through adding additional @ComponentScan annotation, for JPA the @EntityScan annotations. But you would also need to add all the @EnableJpaRepository etc. annotations as those aren't added anymore (at least not with the right packages).

The fix is fairly easy. Move your @SpringBootApplication annotated class to the nl.example.hots package (as stated in the best practices). Remove the annotations other then @SpringBootApplication and simply start your application.

like image 156
M. Deinum Avatar answered Sep 28 '22 06:09

M. Deinum


You're missing the @Autowired annotation on your @AllArgsConstructor, try:

@AllArgsConstructor(onConstructor = @__(@Autowired))
like image 29
MattR Avatar answered Sep 28 '22 06:09

MattR