Read also:
In this part,
we will transform the application from first part from plain code into a
JSF+CDI application. The biggest issue of this case is represented by the final
method, PrinterTemplate#print().
For example, we may try to transform the concrete implementations (A1Printing
and A4Printing)
into CDI managed beans and invoke the print() method, as below:
@Named
@RequestScoped
public class
A1Printing extends PrinterTemplate {
@Override
public void feedWithPaper() {
System.out.println("Feed with paper A1
format.");
}
@Override
public void alignMargins() {
System.out.println("A1 margins top/0.5in,
bottom/0.5in, left/0.2in, right/0.2in.");
}
@Override
public void printStyle() {
System.out.println("A1 print in
grayscale.");
}
}
@Named
@RequestScoped
public class
A4Printing extends PrinterTemplate {
@Override
public void feedWithPaper() {
System.out.println("Feed with paper A4
format.");
}
@Override
public void alignMargins() {
System.out.println("A4 margins:
top/1.0in, bottom/0.75in, left/0.75in, right/0.75in.");
}
@Override
public void printStyle() {
System.out.println("A4 print in
colors.");
}
}
<h:form>
<h:commandButton value="Print A4"
action="#{a4Printing.print()}"/>
<h:commandButton value="Print A1"
action="#{a1Printing.print()}"/>
</h:form>
Or, we can
try to use a separate CDI managed bean and pass the A1Printing/A4Printing
instance via <f:setPropertyActionListener/>:
@Named
@RequestScoped
public class
MyBean {
private PrinterTemplate printer;
public PrinterTemplate getPrinter() {
return printer;
}
public void setPrinter(PrinterTemplate
printer) {
this.printer = printer;
}
public void printAction() {
printer.print();
}
}
<h:form>
<h:commandButton value="Print A1"
action="#{myBean.printAction()}">
<f:setPropertyActionListener
target="#{myBean.printer}" value="#{a1Printing}" />
</h:commandButton>
<h:commandButton value="Print A4"
action="#{myBean.printAction()}">
<f:setPropertyActionListener
target="#{myBean.printer}" value="#{a4Printing}" />
</h:commandButton>
</h:form>
But, these
approaches will not work because they will cause an error as: WELD-001437: Normal scoped bean class
template.method.PrinterTemplate is not proxyable because the type is final or
it contains a final method public final void
template.method.PrinterTemplate.print().
Practically,
the CDI container will create proxy objects for injected classes. In order to
provide a proxy object of the same type as the original object, CDI extends the
original object (extend the class you want to inject). This is happening
internally, so we may find "strange" the above exception. Since CDI
provides us a proxy subclass of the bean, is pretty easy to intuit that this
doesn't work very well with final methods/classes and private constructors (e.g.
public
final void template.method.PrinterTemplate.print()).If the class is not
final (e.g. PrinterTemplate),
the proxy can extend it, but cannot easily overwrite the final
method PrinterTemplate#print().
Now, we can
remove the final
keyword from PrinterTemplate#print()
method, but this will violate the template method design pattern concept, since
subclasses will be able to override the print() method and alter the
steps order.
So, a simple
approach will consist in instantiating A1Printing/A4Printing in bean (MyBean):
@Named
@RequestScoped
public class
MyBean {
public void printA1Action() {
PrinterTemplate printerA1 = new A1Printing();
printerA1.print();
}
public void printA4Action() {
PrinterTemplate printerA4 = new A4Printing();
printerA4.print();
}
}
<h:form>
<h:commandButton value="Print A1"
action="#{myBean.printA1Action()}"/>
<h:commandButton value="Print A4"
action="#{myBean.printA4Action()}"/>
</h:form>
Obviously,
this is not a very elegant approach! In order to keep everything in a single
method, we can pass the printing type as argument:
@Named
@RequestScoped
public class
MyBean {
public void printAction(String type) {
PrinterTemplate printer;
if (type.equals("a1")) {
printer = new A1Printing();
} else
{
printer = new A4Printing();
}
printer.print();
}
}
<h:form>
<h:commandButton value="Print A1"
action="#{myBean.printAction('a1')}"/>
<h:commandButton value="Print A4"
action="#{myBean.printAction('a4')}"/>
Niciun comentariu :
Trimiteți un comentariu