Java Vaadin 14-文本字段未正确显示枚举

Java Vaadin 14-文本字段未正确显示枚举,java,vaadin,Java,Vaadin,我有一段信息作为字符串代码值存储在数据库表中。我已经定义了一个枚举,使代码具有可读性。实体类使用枚举定义字段 当我在Vaadin网格中显示数据时,它会显示枚举值,这是所需的。但是,我也尝试在表单文本字段中显示相同的数据,这表现出不同的行为。我必须为数据绑定编写一个转换器以避免运行时错误,但结果与我预期的相反——它显示代码值而不是枚举 一些代码可以说明: 枚举类型: public enum TaskType { TASK_VIEW("00"), INTERACTIVE(&q

我有一段信息作为字符串代码值存储在数据库表中。我已经定义了一个枚举,使代码具有可读性。实体类使用枚举定义字段

当我在Vaadin网格中显示数据时,它会显示枚举值,这是所需的。但是,我也尝试在表单文本字段中显示相同的数据,这表现出不同的行为。我必须为数据绑定编写一个转换器以避免运行时错误,但结果与我预期的相反——它显示代码值而不是枚举

一些代码可以说明:

枚举类型:

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)
inside
convertToModel()
。调用
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 "";
      }
    }
  }
}