15

I am new to Spring Boot and I'm getting the following error when writing a file upload API:

Error:Description:
Field fileStorageService in com.primesolutions.fileupload.controller.FileController required a bean of type 'com.primesolutions.fileupload.service.FileStorageService' that could not be found.
The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.primesolutions.fileupload.service.FileStorageService' in your configuration.*

Controller class:

public class FileController 
{
    private static final Logger logger = LoggerFactory.getLogger(FileController.class);

    @Autowired
    private FileStorageService fileStorageService;

    @PostMapping("/uploadFile")
    public UploadFileResponse uploadFile(@RequestParam("file") MultipartFile file) {
        String fileName = fileStorageService.storeFile(file);

        String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
                .path("/downloadFile/")
                .path(fileName)
                .toUriString();

        return new UploadFileResponse(fileName, fileDownloadUri,
                file.getContentType(), file.getSize());
    }

    @PostMapping("/uploadMultipleFiles")
    public List<UploadFileResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
        return Arrays.asList(files)
                .stream()
                .map(file -> uploadFile(file))
                .collect(Collectors.toList());
    }
}

Service class:

private final Path fileStorageLocation;


    @Autowired
    public FileStorageService(FileStorageProperties fileStorageProperties) {
        this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
                .toAbsolutePath().normalize();

        try {
            Files.createDirectories(this.fileStorageLocation);
        } catch (Exception ex) {
            throw new FileStorageException("Could not create the directory where the uploaded files will be stored.", ex);
        }
    }

    public String storeFile(MultipartFile file) {
        // Normalize file name
        String fileName = StringUtils.cleanPath(file.getOriginalFilename());

        try {
            // Check if the file's name contains invalid characters
            if(fileName.contains("..")) {
                throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName);
            }

            // Copy file to the target location (Replacing existing file with the same name)
            Path targetLocation = this.fileStorageLocation.resolve(fileName);
            Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);

            return fileName;
        } catch (IOException ex) {
            throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex);
        }
    }

Configuration class:

@ConfigurationProperties(prefix = "file")
public class FileStorageProperties {

    private String uploadDir;

    public String getUploadDir()
    {
        return uploadDir;
    }

    public void setUploadDir(String uploadDir) {
        this.uploadDir = uploadDir;
    }
}

Main:

@SpringBootApplication
@EnableConfigurationProperties({
        FileStorageProperties.class
})
public class FileApplication {
    public static void main(String[] args) {
        SpringApplication.run(FileApplication.class, args);
    }
}

properties file

## MULTIPART (MultipartProperties)
# Enable multipart uploads
spring.servlet.multipart.enabled=true
# Threshold after which files are written to disk.
spring.servlet.multipart.file-size-threshold=2KB
# Max file size.
spring.servlet.multipart.max-file-size=200MB
# Max Request Size
spring.servlet.multipart.max-request-size=215MB

## File Storage Properties
# All files uploaded through the REST API will be stored in this directory
file.upload-dir=C:/Projects/SpringBootProject/Primesolutions/PrimeSolutions/FileUpload

I'm trying to read the file upload property and pass it to the controller class.

Christopher Schneider
  • 3,745
  • 2
  • 24
  • 38
Akash
  • 153
  • 1
  • 3
  • 6
  • 3
    Is your `FileStorageService` class annotated with `@Service` or `@Component`? It's not clear from the code that you've included. – Jordan Jan 30 '20 at 19:30
  • No jordan it is annotated with @Autowired – Akash Jan 30 '20 at 19:45
  • Your constructor is annotated with `@Autowired`, but for Spring to be able to take a class and autowire it into other classes, the entire class needs to be annotated with `@Component`, or one of the other annotations that implement the same interface (such as `@Service` or `@Controller`). This lets Spring know that this class should be managed by Spring. If you annotate your service at the top level (just above `public class FileStorageService`) with `@Service`, that should solve your issue. – Jordan Jan 30 '20 at 19:50
  • It is possible that sometimes the class is already imported thru' another Jar which interferes with the existing class or interface. – Smart Coder Apr 05 '22 at 17:58
  • Are your classes stored inside sub-packages ? Try removing them and putting them in the same package as the main class or the root package and try running your program. – Peter Gichia May 06 '23 at 07:57

12 Answers12

13

The error seems to indicate that Spring does not know any bean of type com.primesolutions.fileupload.service.FileStorageService.

As said in the comment, make sure you class FileStorageServiceis annotated by @Service or @Component:

@Service
public class FileStorageService {
...
}

Make also sure that this class is located in a sub-package of your class FileApplication. For example, if your FileApplication class is located in a package com.my.package, make sure your FileStorageService is located in the package com.my.package.** (same package or any sub package).

Few notes to improve your code by the way :

  • When your class has only one not default constructor, the use of @Autowired on the constructor is optional.

  • Do not put too much code in your constructor. Use instead the @PostConstruct annotation.


    @Service
    public class FileStorageService {
        private FileStorageProperties props;
        // @Autowired is optional in this case
        public FileStorageService (FileStorageProperties fileStorageProperties) {
            this.props = fileStorageProperties;
            this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
                    .toAbsolutePath().normalize();
        }

        @PostConstruct
        public void init() {
            try {
                Files.createDirectories(this.fileStorageLocation);
            } catch (Exception ex) {
                throw new FileStorageException("Could not create the directory where the uploaded files will be stored.", ex);
            }
        }
    }

  • It is better to avoid the @Autowired on a field. Use the constructor instead. It is better for your tests, and more maintainable:
public class FileController {
    private FileStorageService service;

    public FileController(FileStorageService service) {
        this.service = service;
    }
}
RUARO Thibault
  • 2,672
  • 1
  • 9
  • 14
  • Small question here. Suppose the FileStorage class mentioned inherits from an interface. Which of them is to be annotated as Service? In my case, I annotated both, and it did not seem to have an issue, but it would be great to know which one is to marked. – Lycanthropeus Apr 14 '21 at 09:19
  • Check this link: https://stackoverflow.com/questions/16351780/where-should-service-annotation-be-kept-interface-or-implementation. It is best to annotate the implementation class instead of the interface – RUARO Thibault Jun 20 '21 at 18:35
  • The key for me was where was the class located in a package, Thanks! – Luis Manrique Aug 29 '21 at 15:46
  • Need to ensure that no similar class exists from another imported jar. – Smart Coder Apr 05 '22 at 20:52
9

I solved this problem using where i use @Autowired annotation just replace with this`

@Autowired(required = false)

`

wazirX
  • 147
  • 1
  • 3
2

When @Autowired doesn’t work

There are several reasons @Autowired might not work.

When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection. Also when you use @Autowired in the class of which you created a new instance, the Spring context will not be known to it and thus most likely this will also fail. Another reason can be that the class you want to use @Autowired in, is not picked up by the ComponentScan. This can basically be because of two reasons.

  1. The package is outside the ComponentScan search path. Move the package to a scanned location or configure the ComponentScan to fix this.

  2. The class in which you want to use @Autowired does not have a Spring annotation. Add one of the following annotatons to the class: @Component, @Repository, @Service, @Controller, @Configuration. They have different behaviors so choose carefully! Read more here.

I solved this problem using :

@ComponentScan({ "com.yourpkg.*" })

Make sure you @ComponentScan cover all classes contains annotatons : @Component, @Repository, @Service, @Controller, @Configuration.

Reference : https://technology.amis.nl/2018/02/22/java-how-to-fix-spring-autowired-annotation-not-working-issues/

Abd Abughazaleh
  • 4,615
  • 3
  • 44
  • 53
2

Tried with removing the (exclude = {DataSourceAutoConfiguration.class }) parameter with @SpringBootApplication:

Before:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })

public class SpringBootMain { ...

After:

@SpringBootApplication

public class SpringBootMain { ...

Worked for me.

1

The class which is going to be Autowired should be marked with @Service or @Component. Also if the class is in different package then need to add the @ComponentScan annotation in the main class as follows.

@ComponentScan({"com.beta.replyservice", "com.beta.ruleService"})
@SpringBootApplication
Senthuran
  • 1,583
  • 2
  • 15
  • 19
0

Solution is

@Autowired(required = false) 
private FileStorageService fileStorageService;
0

When I work with a microservice project I get this error while the project I currently work on has the model class but DB config even though the other microservices have the DB config. I created the DB config and the problem has been solved.

menoktaokan
  • 346
  • 3
  • 13
-1

Make sure to have respective annotations for classes. The same issue got solved for me when I add @Service annotation for interfaces and implemented service classes.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
-1

I use @Service on the service class which has to be Autowired. It solves my error. or you can use @Autowired(required = false) to disable the auto wiring for a particular instance.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
-1

I had the same issue. It was solved for me when I added a dependency on "spring-webmvc".

Ryan M
  • 18,333
  • 31
  • 67
  • 74
-1

=> Error should look like this:

***************************
APPLICATION FAILED TO START
***************************
Description:

Field accountPresentation in june14th.account.TestSpringBoot required a bean of type 'june14th.controller.AccountPresentation' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)

Action:

Consider defining a bean of type 'june14th.controller.AccountPresentation' in your configuration.

Solution to the problem:-

  1. First and most important step is look whether your code has the needed dependencies.
  2. Check your Folder structure (this error is mainly due to this problem, always check your package structure) i.e, check wheather the main package and its sub packages are well structured

eg:

package X.account; //consider this is my main file package
package X.controller; //consider this as my presentation file package

when you run this program this will cause our "APPLICATION FAILED TO START" error, because of our package structure..look

package X.account; //main file package [the next fie should inside this package i.e as a sub package]

package.X.account.controller // this is the right way

I think this should solve your problem.

  1. Put @Autowired(required=true) //do only if above will not work
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
-1

When I had the same problem, I just added a default constructor in my service class and it started working.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109