简体   繁体   中英

Accessing injected properties results in NullPointerException

This is the first time for me working with Quarkus and CDI and I think I'm getting it wrong.

In my application users can download some files. I'd like to control how many files are being downloaded simultaneously. I thought I could do this by creating a bean with @ApplicationScoped annotation, forcing instantiation at startup, and then injecting it wherever I need to know how many files are currently downloading.

This is what I managed to do:

@ApplicationScoped
public class DownloadState {
    private int downloadingFiles;

    void startup(@Observes StartupEvent event) {
        setDownloadingFiles(0);
        System.out.println("downloading files: " + downloadingFiles);
    }

    public int getDownloadingFiles() {
        return downloadingFiles;
    }

    public void setDownloadingFiles(int downloadingFiles) {
        this.downloadingFiles = downloadingFiles;
    }

    public void incrementDownloadingFiles() {
        downloadingFiles++;
    }

    public void decrementDownloadingFiles() {
        downloadingFiles--;
    }
}

Doing this I can see the log at startup saying "downloading files: 0", so I know the class has been instantiated.

I try to access the number of downloading files here:

public class Downloader {
    private static final Logger LOG = Logger.getLogger(Downloader.class);

    @Inject
    DownloadState downloadState;

    private Dotenv dotenv = Dotenv.configure()
        .directory("../")
        .filename(".env.local")
        .load();

    private String fileName = dotenv.get("DOWNLOAD_PATH");
    private String url;

    public Downloader(String url, String fileName) {
        this.url = url;
        this.fileName += fileName;
    }

    public void downloadProduct() {

        LOG.info("Downloading Files: " + downloadState.getDownloadingFiles());
        //...
    }
}

Whenever downloadProduct is called a NullPointerException is thrown on the line LOG.info("Downloading Files: " + downloadState.getDownloadingFiles());

Am I getting CDI totally wrong? Any help is really appreciated, thank you in advance.

I assume you're calling the Downloader constructor directly -- in which case, indeed no injection will happen and your downloadState will be null . Dependency injection is "contagious" -- you have to use it everywhere.

In your case, I'd probably just make Downloader also @ApplicationScoped , inject it everywhere you use it, and probably move the url and fileName parameters from constructor to downloadProduct . Actually at that point, the number of downloadingFiles could also be in Downloader . (Also note that it can be accessed from multiple threads -- so I'd probably use an AtomicInteger for downloadingFiles .)

All in all, something like this:

@ApplicationScoped
public class Downloader {
    private static final Logger LOG = Logger.getLogger(Downloader.class);

    private final AtomicInteger downloadingFiles = new AtomicInteger(0);

    private final String downloadPath = Dotenv.configure()
        .directory("../")
        .filename(".env.local")
        .load()
        .get("DOWNLOAD_PATH");

    public void downloadProduct(String url, String fileName) {
        String path = downloadPath + fileName;

        int current = downloadingFiles.incrementAndGet();
        LOG.info("Downloading Files: " + current);
        //...
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM