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

时间:2021-01-23 14:05:02

标签: java vaadin

我有一条信息作为字符串代码值存储在数据库表中。我定义了一个枚举以使代码易于阅读。实体类使用枚举定义字段。

当我在 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;
    }
  }
}

网格视图类:

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));
  }

  ...
}

详细信息视图(显示错误的地方):

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 "";
      }
    }
  }
}

所以,举个例子,如果一个 type = 07 的实体显示在网格中,它会显示 FOLDER,这就是我想要的。但是,当我在文本字段中显示相同类型的对象时,它会显示 07 而不是 FOLDER

知道这里发生了什么吗?它似乎与我需要的相反。

1 个答案:

答案 0 :(得分:2)

您的 static class TaskTypeConverter 用于由活页夹从 TaskType.FOLDER 转换。现在让我们看看您的 convertToPresentation() 做了什么:它调用 value.getCodeValue() 所以当然您的 TextField 填充了 07。 但是,您想要返回枚举名称,因此您需要调用固有的枚举方法 value.name(),反之亦然,在 TaskType.valueOf(value) 中调用 convertToModel()。调用 IllegalArgumentException 时不要忘记捕获 valueOf() 和 NPE!


最好不要使用 .name(),而是使用友好名称 f.e.您可以在枚举中保存的“文件夹”。


但是,您可能应该使用 Select<TaskType>ComboBox<TaskType> 让用户从一组预定义的值中进行选择,即从枚举而不是 TextField 中进行选择。

如果您需要自定义的不仅仅是文本,请通过 setItemLabelGenerator() 或渲染器设置友好名称。