有时java枚举是一个字符串

有时java枚举是一个字符串,java,jpa,enums,mustache,Java,Jpa,Enums,Mustache,我们在Wildfly 8.0.0服务器上运行JAVA web应用程序。我们有一个电子邮件模板编辑器表单,它使用Mustache字段将一些变量数据放入模板中。邮件还有一个枚举字段,用于指定模板的类型。实体结构如下所示: @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "DTYPE", discriminatorType = DiscriminatorType.STRI

我们在Wildfly 8.0.0服务器上运行JAVA web应用程序。我们有一个电子邮件模板编辑器表单,它使用Mustache字段将一些变量数据放入模板中。邮件还有一个枚举字段,用于指定模板的类型。实体结构如下所示:

@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);
    }
}
我开始调试它,并在
entity.setTemplateType(templateType)中调试它行我看到
templateType
是一个
字符串
,但这只有在服务器重新启动一段时间后才会发生。在相同位置重新启动后,
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
作为
字符串传递到
{bean.templateType}
值中。可能吗?我检查了这个问题:根据BalusC的回答,JSF有一个用于
enum
的内置转换器。但这是我们设置
templateType
变量的唯一部分。

问题在于未绑定的
,它将被编译为
受保护的对象templateType
公共void setTemplateType(对象模板类型)

应用程序中有人正在使用
字符串调用
setTemplateType()
。如果他使用反射(如Mustache字段所做的那样),或者使用未绑定的
AbstractMailTemplateEditController
,这是可能的

如果
AbstractMailTemplateEditController
的所有子类都为
TYPE
使用枚举,则可以将其绑定到
enum

public abstract class AbstractMailTemplateEditController<T extends MailTemplate, TYPE extends Enum<TYPE>> {

愚蠢的测试:如果您去掉lombok注释,只使用手动创建的getter/setter,会怎么样?我尝试了一下,但无法立即看到结果,因为错误取决于服务器运行时间。。。但如果它能工作,那就很奇怪了,因为我直接访问
templateType
字段,而不是使用getter setter方法。我无法在saveTemplate方法中找到正在声明或初始化templateType变量的位置。这就是为什么我无法确定它在某个时间变成字符串类型而不是枚举类型的可能原因。”但如果它起作用,那将很奇怪,因为我直接访问templateType字段,我没有使用getter setter方法。“我不太担心如何访问属性,而是担心Hibernate如何做到这一点。Hibernate通过代理工作,当涉及lombok时,代理可能无法完全正常工作。但这是我胡乱猜测的结果。@Gimby:我通过手动实现getter和setter消除了lombok,现在它可以工作了,但由于服务器的原因,我需要一些时间来确保它可以成为解决方案。
public abstract class AbstractMailTemplateEditController<T extends MailTemplate, TYPE extends Enum<TYPE>> {
public class CustomMailTemplateEditController ... {
    @Override 
    public void setTemplateType(CustomTemplateType templateType) {
        super.setTemplateType(templateType);
    }
}