Java Vaadin 14-文本字段未正确显示枚举
我有一段信息作为字符串代码值存储在数据库表中。我已经定义了一个枚举,使代码具有可读性。实体类使用枚举定义字段 当我在Vaadin网格中显示数据时,它会显示枚举值,这是所需的。但是,我也尝试在表单文本字段中显示相同的数据,这表现出不同的行为。我必须为数据绑定编写一个转换器以避免运行时错误,但结果与我预期的相反——它显示代码值而不是枚举 一些代码可以说明: 枚举类型:Java Vaadin 14-文本字段未正确显示枚举,java,vaadin,Java,Vaadin,我有一段信息作为字符串代码值存储在数据库表中。我已经定义了一个枚举,使代码具有可读性。实体类使用枚举定义字段 当我在Vaadin网格中显示数据时,它会显示枚举值,这是所需的。但是,我也尝试在表单文本字段中显示相同的数据,这表现出不同的行为。我必须为数据绑定编写一个转换器以避免运行时错误,但结果与我预期的相反——它显示代码值而不是枚举 一些代码可以说明: 枚举类型: public enum TaskType { TASK_VIEW("00"), INTERACTIVE(&q
public enum TaskType {
TASK_VIEW("00"), INTERACTIVE("01"), BATCH("02"), FOLDER("07"), URL("08"), USER_DEFINED("11");
private String codeValue;
private TaskType(String codeValue) {
this.codeValue = codeValue;
}
public String getCodeValue() {
return codeValue;
}
public static TaskType fromCodeValue(String value) {
switch (value) {
case "00":
return TASK_VIEW;
case "01":
return INTERACTIVE;
case "02":
return BATCH;
case "07":
return FOLDER;
case "08":
return URL;
case "11":
return USER_DEFINED;
default:
return null;
}
}
}
实体类:
@Entity
public class TaskMaster extends AbstractEntity {
private TaskType type;
// other fields
public TaskType getType() {
return type;
}
public void setType(TaskType type) {
this.type = type;
}
// other methods
}
数据库字段和枚举类型之间的转换器:
@Converter(autoApply = true)
public class TaskTypeConverter implements AttributeConverter<TaskType, String> {
@Override
public String convertToDatabaseColumn(TaskType type) {
if (type != null) {
return type.getCodeValue();
} else {
return null;
}
}
@Override
public TaskType convertToEntityAttribute(String dbData) {
if (dbData != null) {
return TaskType.fromCodeValue(dbData);
} else {
return null;
}
}
}
@转换器(autoApply=true)
公共类TaskTypeConverter实现AttributeConverter{
@凌驾
公共字符串convertToDatabaseColumn(TaskType类型){
if(type!=null){
返回类型:getCodeValue();
}否则{
返回null;
}
}
@凌驾
公共任务类型convertToEntityAttribute(字符串dbData){
if(dbData!=null){
返回TaskType.fromCodeValue(dbData);
}否则{
返回null;
}
}
}
栅格视图类:
public class TaskMasterListView extends VerticalLayout {
private Grid<TaskMaster> grid = new Grid<>(TaskMaster.class);
private TaskMasterService taskService;
public TaskMasterListView(TaskMasterService taskService) {
this.taskService = taskService;
...
}
@PostConstruct
public void init() {
List<TaskMaster> items = taskService.findAll();
grid.setItems(items);
}
private void configureGrid() {
grid.addClassName("tasks-grid");
grid.setColumns("internalTaskID", "taskID", "name", "type", "objectName", "version",
"formName");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
}
...
}
公共类TaskMasterListView扩展了垂直布局{
私有网格=新网格(TaskMaster.class);
私人TaskMasterService taskService;
公共TaskMasterListView(TaskMasterService taskService){
this.taskService=taskService;
...
}
@施工后
公共void init(){
List items=taskService.findAll();
网格。设置项(项);
}
私有void configureGrid(){
addClassName(“任务网格”);
setColumns(“internalTaskID”、“taskID”、“名称”、“类型”、“对象名称”、“版本”,
“格式名称”);
grid.getColumns().forEach(col->col.setAutoWidth(true));
}
...
}
详细信息视图(显示不正确):
公共类TaskDetailView扩展了FormLayout{
私有静态最终记录器Logger=LoggerFactory.getLogger(TaskDetailView.class);
私有文本字段类型;
//其他GUI对象
私人活页夹;
公共任务详细视图(){
配置视图();
bindData();
}
公共无效加载任务(TaskTreeView.TaskSelectionEvent事件){
if(event.getSelected()!=null){
binder.setBean(event.getSelected());
}
}
私有void bindData(){
活页夹=新活页夹(TaskMaster.class);
binder.setBean(新的TaskMaster());
binder.forField(type).withConverter(新的TaskTypeConverter()).bind(“type”);
//其他绑定
}
私有静态类TaskTypeConverter实现转换器{
@凌驾
公共结果转换模型(字符串值、ValueContext上下文){
info(“convertToModel:value={}”,value);
返回Result.ok(TaskType.fromCodeValue(value));
}
@凌驾
公共字符串convertToPresentation(TaskType值、ValueContext上下文){
if(值!=null){
info(“convertToPresentation:value={}”,value.toString());
返回值。getCodeValue();
}否则{
logger.info(“convertToPresentation:null”);
返回“”;
}
}
}
}
例如,如果网格中显示类型为=07
的实体,它将显示文件夹,这就是我想要的。但是,当我在文本字段中显示类型所在的同一对象时,它显示的是07
,而不是文件夹
知道这是怎么回事吗?它似乎与我需要的正好相反。您的静态类TaskTypeConverter
被活页夹用于从TaskType.FOLDER
转换。现在让我们看看您的convertToPresentation()
做了什么:它调用value.getCodeValue()
,因此您的文本字段中当然填充了07
。
但是,您希望返回枚举名称,因此需要调用固有的枚举方法value.name()
,反之亦然,调用TaskType.valueOf(value)
insideconvertToModel()
。调用valueOf()时,不要忘记捕获IllegalArgumentException
和NPE
最好不要使用.name()
,而是使用一个友好的名称f.e.“Folder”,可以保存在枚举中
但是,您可能应该使用选择
或组合框
,让用户从预定义的一组值中进行选择,即从枚举中进行选择,而不是从文本字段中进行选择
通过setItemLabelGenerator()
或渲染器设置友好名称(如果您需要自定义它而不仅仅是文本)。在这种情况下,不需要选择框或组合框-用于显示目的。将字符串代码值存储在实体而不是枚举中会更容易吗?然后只需使用某种转换器在网格、文本字段中呈现它,不管怎样?我认为对TaskType使用枚举的抽象是正确的。与原始字符串相比,使用枚举类型更可取。codeValue
应该封装在enum中,至于友好的显示名称,您可以使用另一个enum字段,从name()
计算它(下划线到空格,大写首字母…),或者更好的是,对于i18n,使用某种具有不同翻译的属性文件。
public class TaskDetailView extends FormLayout {
private static final Logger logger = LoggerFactory.getLogger(TaskDetailView.class);
private TextField type;
// other GUI objects
private Binder<TaskMaster> binder;
public TaskDetailView() {
configureView();
bindData();
}
public void loadTask(TaskTreeView.TaskSelectionEvent event) {
if (event.getSelected() != null) {
binder.setBean(event.getSelected());
}
}
private void bindData() {
binder = new Binder<>(TaskMaster.class);
binder.setBean(new TaskMaster());
binder.forField(type).withConverter(new TaskTypeConverter()).bind("type");
// other bindings
}
private static class TaskTypeConverter implements Converter<String, TaskType> {
@Override
public Result<TaskType> convertToModel(String value, ValueContext context) {
logger.info("convertToModel: value={}", value);
return Result.ok(TaskType.fromCodeValue(value));
}
@Override
public String convertToPresentation(TaskType value, ValueContext context) {
if (value != null) {
logger.info("convertToPresentation: value={}", value.toString());
return value.getCodeValue();
} else {
logger.info("convertToPresentation: null");
return "";
}
}
}
}