javajakarta-eecdijava-ee-8

CDI factory design pattern with properties file


I have a interface like this :

@Singleton
public interface StorageEngine {
    String upload(InputStream inputStream);

    InputStream download(String fileName);

    int size(String fileName);

    boolean delete(String fileName);
}

and multiple implementation :

public class LocalFileSystemEngine implements StorageEngine {
   // Implement methods ...
}

public class DropboxEngine implements StorageEngine {
   // Implement methods ...
}

public class GoogleDriveEngine implements StorageEngine {
   // Implement methods ...
}

and this Producer class :

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Any;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ApplicationScoped
public class StorageProducer {
    private static final Logger logger = LoggerFactory.getLogger(StorageProducer.class);

    @Inject
    @ConfigProperty(name = "storage.engine-type",defaultValue = "local-filesystem")
    private String engineType;

    @Inject
    @Any
    private Instance<StorageEngine> storageEngineInstance;

    @Produces
    public StorageEngine getStorageEngine() {
        // How to implement ???
    }
}

my goal is :
read engine type from microprofile properties file and produce storage engine .
Is there any way to inject StorageEngine without qualifier annotation ?

I need to have only this on injection point class:

@MultipartConfig
@WebServlet(urlPatterns = "/file")
public class FileServlet extends HttpServlet {
     @Inject
    private StorageEngine storageEngine;    
    

    // Implement service method 
} 

anyone can help me ?


Solution

  • All of the solutions are too complicated. Qualifiers are not needed.

    Restrict the bean types of the concrete implementations and then have your producer method pick the right one:

    @Typed(LocalFileSystemEngine.class) // <-- NOTE
    public class LocalFileSystemEngine implements StorageEngine {
       // Implement methods ...
    }
    
    @Typed(DropboxEngine.class) // <-- NOTE
    public class DropboxEngine implements StorageEngine {
       // Implement methods ...
    }
    
    @Typed(GoogleDriveEngine.class) // <-- NOTE
    public class GoogleDriveEngine implements StorageEngine {
       // Implement methods ...
    }
    
    @Produces
    public StorageEngine getStorageEngine(@ConfigProperty(name = "storage.engine-type",
                                                          defaultValue = "local-filesystem")
                                          String type,
                                          LocalFilesystemEngine lfe,
                                          DropboxEngine de,
                                          GoogleDriveEngine gde) {
      return switch (type) {
        case "local-filesystem" -> lfe;
        case "google-drive" -> gde;
        case "dropbox" -> de;
        default -> throw new CreationException();
      };
    }