JavaEE - Strategy Pattern - Error while injecting Lambda

20 Views Asked by At

I am learning java EE by buildig a supply manager app. I'm trying to implement the strategy pattern, by having a SalesCalculatorService interface:

public interface SalesCalculatorService extends Serializable {

    List<Number> getSalesData();
}

concrete Implementations like this one..


@Stateless
@MonthlySalesCalculatorQualifier 
public class  MonthlySalesCalculatorService implements SalesCalculatorService, Serializable{

    private static final long serialVersionUID = 1L;
    @Inject
    private ProfitInvoiceService profitInvoiceService;
    
    @Transactional
    public List<Number> getSalesData(){
        
        List<Number> salesList = new ArrayList<>();
        Map<Month, List<ProfitInvoice>>  salesMap = profitInvoiceService.getInvoicesPerMonth();
        
        salesMap.keySet().forEach(e -> {
            List<ProfitInvoice> invoiceList = salesMap.get(e);
            double totalValue = invoiceList
                    .stream()
                    .mapToDouble(invoice -> {
                        ProfitInvoice profitInvoice = profitInvoiceService.findById(ProfitInvoice.class, invoice.getId());
                        return profitInvoice.getTotalAmount();
                    })
                    .sum();
            salesList.add(Double.valueOf(totalValue));
            
        });
        return salesList;
    }

}

A class with a method that produces a lambda that takes a string as an argument and returns the correct concrete implementation

public class SalesCalculatorStrategyProducer implements Serializable {

    
    private static final long serialVersionUID = 1L;
    
    @Produces @Named("salesCalculatorStrategy")
    Function<String, SalesCalculatorService> salesCalculatorStrategyProducer = (String strategy) -> {
        switch (strategy) {
        case "monthly":
            return new MonthlySalesCalculatorService();
        case "quarter":
            return new QuarterSalesCalculatorService();
        default:
            throw new IllegalArgumentException("Invalid strategy: " + strategy);
        }
    };
}

And a viewScoped bean where i would like to call the lambda to select implementation at runtime to display data in a chart

@Named
@ViewScoped
public class BarChartProductSales  extends BarChartView {
    
    private static final long serialVersionUID = 1L;
    
    
    @Inject @Named("salesCalculatorStrategy")
    private Function<String, SalesCalculatorService> salesCalculatorStrategyProducer;
    
    
    
     @Override
     public List<Number> getChartData() {
         
         return salesCalculatorStrategyProducer.apply("quarter").getSalesData();
         
     }

Unfortunately i get a serialization error when i try to load the page... All classes implement serializable and if i try to directly inject my concrete impletantion in the bean everything works fine. The error:

SEVERE: Servlet.service() for servlet [FacesServlet] in context with path [/manager] threw exception [jakarta.el.ELException: Error reading [barModel] on type [com.charts.BarChartProductSales$$OwbNormalScopeProxy0]] with root cause
jakarta.enterprise.inject.IllegalProductException: A producer method or field of scope @Dependent returns an unserializable object for injection into an injection point Field Injection Point, field name :  salesCalculatorStrategyProducer, Bean Owner : [BarChartProductSales, WebBeansType:MANAGED, Name:barChartProductSales, API Types:[java.lang.Object,java.io.Serializable,com.charts.BarChartProductSales,com.charts.BarChartView], Qualifiers:[jakarta.enterprise.inject.Default,jakarta.enterprise.inject.Any,jakarta.inject.Named]] that requires a passivation capable dependency
    at org.apache.webbeans.inject.AbstractInjectable.inject(AbstractInjectable.java:120)
    at org.apache.webbeans.inject.InjectableField.doInjection(InjectableField.java:65)
    at org.apache.webbeans.portable.InjectionTargetImpl.injectFields(InjectionTargetImpl.java:231)
    at org.apache.webbeans.portable.InjectionTargetImpl.inject(InjectionTargetImpl.java:217)
    at org.apache.webbeans.portable.InjectionTargetImpl.inject(InjectionTargetImpl.java:207)
    at org.apache.webbeans.component.AbstractOwbBean.create(AbstractOwbBean.java:128)
    at org.apache.webbeans.component.ManagedBean.create(ManagedBean.java:66)

Can Function type be serialized? I get the same error even if i simplify the method by using Function<String, String> so the classes shouldn't be the problem but rather the Function type itself?....

If i try to use the produces annotation to produce a simple string instead of a lambda the injection correctly works.. Any other way to do change implementation at runtime with the strategy pattern?

0

There are 0 best solutions below