我们在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);行中看到templateTypeString,但这仅在服务器重新启动后一段时间才会发生。在同一位置重新启动后,templateTypeCustomTemplateType,我可以保存模板。
它怎么会发生,我该怎么做才能解决此问题?

更新:根据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

否则,您可以覆盖setTemplateTypeCustomMailTemplateEditController并进行显式类型检查:

public class CustomMailTemplateEditController ... {
    @Override
    public void setTemplateType(CustomTemplateType templateType) {
        super.setTemplateType(templateType);
    }
}

09-15 23:01