我目前正在审查代码,发现CDI转换器如下:
@Named
@RequestScoped
public class BankConverter implements Converter, Serializable
{
@EJB
private BankService bankService;
@Override
public Object getAsObject( FacesContext ctx, UIComponent comp, String identifier )
{
if ( identifier == null || identifier.trim().isEmpty() )
{
return null;
}
Bank bank = null;
try
{
bank = this.bankService.findByPrimaryKey( Long.valueOf( identifier ) );
}
catch( Exception e )
{
// omitted
}
return bank;
}
@Override
public String getAsString( FacesContext ctx, UIComponent comp, Object obj )
{
if ( obj == null || ( ( Bank ) obj ).getId() == null )
{
return null;
}
return ( ( Bank ) obj ).getId().toString();
}
}
转换器基本上总是这样使用(注意converter="#{bankConverter}"
):
<p:autoComplete id="bank"
value="#{employeeDepotManager.selectedBank}"
var="bnk"
converter="#{bankConverter}"
completeMethod="#{autoCompleter.completeBankSearch}"
itemLabel="#{bnk.name}"
itemValue="#{bnk}"
forceSelection="false"
minQueryLength="3"
global="true"
validator="#{employeeDepotManager.validateBank}"
scrollHeight="200">
<p:ajax event="itemSelect" update="bank-code bank-name" />
<p:column>#{bnk.code}</p:column>
<p:column>#{bnk.name}</p:column>
</p:autoComplete>
我目前正在与同事讨论哪个作用域将是最好的转换器…
从JSF页面引用的管理器bean的95%是@ViewScoped
,所以我认为最好的转换器是@ViewScoped
(而不是@RequestScoped,据我所知,这将为每个AJAX请求重新创建一个转换器实例)。
然后我的同事补充说,转换器应该是@Dependent
,因为这会自动将转换器放入周围bean所在的范围。我的感觉告诉我,这行不通。然而,我不能真的不同意,因为我的知识基本上就到此为止了。
@ViewScoped
时,可能是转换器的最佳作用域是什么呢?
PS:注意,我们正在使用Seam 3来混合@Named
和@ViewScoped
由于大多数转换器实际上是无状态的,因此它们很容易是@ApplicationScoped
,在我看来,这是它们最自然的作用域。然而,一些转换器实际上不是。例如,<f:convertDateTime>
标签后面的DateTimeConverter
确实保存了一些状态。此外,@FacesConverter
的默认实现使用Application#createConverter(String converterId)
在需要时创建一个新的转换器实例,因此每个请求可以创建多次。
此外,就我而言,自定义转换器在作用域方面与引用的支持bean没有任何交集,因此它们是否为ViewScoped
并不重要。在选择转换器的作用域时,真正重要的是转换器实例中所保持的状态的作用域,正如BalusC正确地发现的那样。
至于您问题中的转换器实际上是无状态的,它可以安全地为@ApplicationScoped
。