有时 java 枚举是一个字符串
Sometimes java enum is a String
我们 运行 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);
}
}
这是非常奇怪的部分:
服务器重启后,我们可以毫无问题地保存我们的模板。 '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)
您的应用程序中有人正在用 String
呼叫 setTemplateType()
。如果他使用反射(就像 Mustache Fields 会做的那样)或者如果他使用未绑定的 AbstractMailTemplateEditController
.
,这是可能的
如果 AbstractMailTemplateEditController
的所有子 class 都使用 TYPE
的枚举,您可以将其绑定到 Enum
:
public abstract class AbstractMailTemplateEditController<T extends MailTemplate, TYPE extends Enum<TYPE>> {
这将导致 class 文件中的 public void setTemplateType(Enum<?> templateType)
- 一旦有人用 String
.[=26 调用它,它就会抛出 ClassCastException
=]
否则你可以覆盖 setTemplateType
和 CustomMailTemplateEditController
并进行显式类型检查:
public class CustomMailTemplateEditController ... {
@Override
public void setTemplateType(CustomTemplateType templateType) {
super.setTemplateType(templateType);
}
}
我们 运行 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);
}
}
这是非常奇怪的部分:
服务器重启后,我们可以毫无问题地保存我们的模板。 '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)
您的应用程序中有人正在用 String
呼叫 setTemplateType()
。如果他使用反射(就像 Mustache Fields 会做的那样)或者如果他使用未绑定的 AbstractMailTemplateEditController
.
如果 AbstractMailTemplateEditController
的所有子 class 都使用 TYPE
的枚举,您可以将其绑定到 Enum
:
public abstract class AbstractMailTemplateEditController<T extends MailTemplate, TYPE extends Enum<TYPE>> {
这将导致 class 文件中的 public void setTemplateType(Enum<?> templateType)
- 一旦有人用 String
.[=26 调用它,它就会抛出 ClassCastException
=]
否则你可以覆盖 setTemplateType
和 CustomMailTemplateEditController
并进行显式类型检查:
public class CustomMailTemplateEditController ... {
@Override
public void setTemplateType(CustomTemplateType templateType) {
super.setTemplateType(templateType);
}
}