我们在Wildfly 8.0.0服务器上运行JAVA Web应用程序。我们有一个电子邮件模板编辑器表单,该表单使用“小胡子字段”将一些可变数据放入模板中。邮件中还有一个枚举字段,用于指定模板的类型。实体结构是这样的:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE", discriminatorType = DiscriminatorType.STRING, length = 255)
@DiscriminatorOptions(force = true)
@DiscriminatorValue("MailTemplate")
@Table(name = "MailTemplate")
public abstract class MailTemplate extends MyAbstractEntity // AbstractEntity holds the common id field for all entities
{
private String body;
private String subject;
}
public class CustomMailTemplate extends MailTemplate implements java.io.Serializable {
@Enumerated(EnumType.STRING)
@Column(name = "templateType")
private CustomTemplateType templateType;
}
public enum CustomTemplateType implements java.io.Serializable {
OneTemplateType,
AnotherTemplateType,
AndAThirdOneTemplateType
}
我们使用JPA将实体持久化到Oracle数据库中。这是处理各种类型模板的控制器结构:
public abstract class AbstractMailTemplateEditController<T extends MailTemplate, TYPE> {
@Getter @Setter
protected T entity;
@Getter @Setter
protected String subject;
@Getter @Setter
protected String body;
@Getter @Setter
protected TYPE templateType;
}
public class CustomMailTemplateEditController extends AbstractMailTemplateEditController<CustomMailTemplate, CustomTemplateType> implements Serializable {
// this is in a service which injected, it's just for the code example
@PersistenceContext
private EntityManager em;
public void saveTemplate(){
// let's assume now that our entity property exists
entity.setBody(body);
entity.setSubject(subject);
entity.setTemplateType(templateType); // SOMETHING WRONG HAPPENS HERE!
em.merge(entity);
}
}
这是非常奇怪的部分:
重新启动服务器后,我们可以毫无问题地保存模板。经过'T'时间之后,我们无法保存模板,并且收到以下错误消息:
java.lang.String cannot be cast to CustomTemplateType
我开始调试它,并在
entity.setTemplateType(templateType);
行中看到templateType
是String
,但这仅在服务器重新启动后一段时间才会发生。在同一位置重新启动后,templateType
是CustomTemplateType
,我可以保存模板。它怎么会发生,我该怎么做才能解决此问题?
更新:根据Tobias Liefke的回答,我检查了我们如何在视图中使用此控制器,并且发现了以下内容:
<h:selectOneMenu value="#{bean.templateType}" styleClass="form-control" id="template-type" >
<f:selectItems value="#{bean.mailTemplateTypes}" var="item" itemLabel="#{msg[item]}" itemValue="#{item}" />
<f:selectItem itemLabel="Special template" itemValue="#{null}" />
</h:selectOneMenu>
#{bean.mailTemplateTypes}
是枚举列表。那么这可能是JSF错误吗?我的意思是过了一会儿(几天,几周没有重启服务器),JSF开始将所选的mailTemplateType
作为String
传递到#{bean.templateType}
值中。可能吗?我检查了以下问题:How to use enum values in f:selectItem(s),根据BalusC的回答,JSF为enum
内置了一个转换器。但这是设置templateType
变量的唯一部分。 最佳答案
问题是未绑定的<TYPE>
,它将被编译为protected Object templateType;
和public void setTemplateType(Object templateType)
应用程序中的某人正在用setTemplateType()
调用String
。如果他使用反射(如“ Mustache Fields”将执行此操作)或使用未绑定的AbstractMailTemplateEditController
,则这是可能的。
如果AbstractMailTemplateEditController
的所有子类都为TYPE
使用枚举,则可以将其绑定到Enum
:
public abstract class AbstractMailTemplateEditController<T extends MailTemplate, TYPE extends Enum<TYPE>> {
这将导致类文件中出现
public void setTemplateType(Enum<?> templateType)
-一旦有人使用ClassCastException
调用它,就会抛出String
。否则,您可以覆盖
setTemplateType
和CustomMailTemplateEditController
并进行显式类型检查:public class CustomMailTemplateEditController ... {
@Override
public void setTemplateType(CustomTemplateType templateType) {
super.setTemplateType(templateType);
}
}