开发者

Conditional injection of bean

开发者 https://www.devze.com 2023-04-06 22:43 出处:网络
I want to have inject a bean based on a String parameter passed from client. public interface Report {

I want to have inject a bean based on a String parameter passed from client.

public interface Report {
    generateFile();
}

public class ExcelReport extends Report {
    //implementation for generateFile
}

public class CSVReport extends Report {
    //implementation for generateFile
}

class MyCo开发者_如何学编程ntroller{
    Report report;
    public HttpResponse getReport() {
    }
}

I want report instance to be injected based on the parameter passed. Any help would be greatly appretiated. Thanks in advance


Use Factory method pattern:

public enum ReportType {EXCEL, CSV};

@Service
public class ReportFactory {

    @Resource
    private ExcelReport excelReport;

    @Resource
    private CSVReport csvReport

    public Report forType(ReportType type) {
        switch(type) {
            case EXCEL: return excelReport;
            case CSV: return csvReport;
            default:
                throw new IllegalArgumentException(type);
        }
    }
}

The report type enum can be created by Spring when you call your controller with ?type=CSV:

class MyController{

    @Resource
    private ReportFactory reportFactory;

    public HttpResponse getReport(@RequestParam("type") ReportType type){
        reportFactory.forType(type);
    }

}

However ReportFactory is pretty clumsy and requires modification every time you add new report type. If the report types list if fixed it is fine. But if you plan to add more and more types, this is a more robust implementation:

public interface Report {
    void generateFile();
    boolean supports(ReportType type);
}

public class ExcelReport extends Report {
    publiv boolean support(ReportType type) {
        return type == ReportType.EXCEL;
    }
    //...
}

@Service
public class ReportFactory {

    @Resource
    private List<Report> reports;

    public Report forType(ReportType type) {
        for(Report report: reports) {
            if(report.supports(type)) {
                return report;
            }
        }
        throw new IllegalArgumentException("Unsupported type: " + type);
    }
}

With this implementation adding new report type is as simple as adding new bean implementing Report and a new ReportType enum value. You could get away without the enum and using strings (maybe even bean names), however I found strongly typing beneficial.


Last thought: Report name is a bit unfortunate. Report class represents (stateless?) encapsulation of some logic (Strategy pattern), whereas the name suggests it encapsulates value (data). I would suggest ReportGenerator or such.

0

精彩评论

暂无评论...
验证码 换一张
取 消