LocalDate presentation in ComboBox

Hi, I have a ComboBox which presents a list of possible dates to execute a project planning. There’s a BeamItemContainer of LocalDate objects attached to the ComboBox using setContainerDataSource.

It all works well but the LocalDate presentation is using the “yyyy-MM-ddd” format and I need it to be shown as “ddd/MM/yyyy”.

I tried to create a converter but had no success whatsoever. Can you please tell me what I’m doing wrong?

List<LocalDate> availableDates = new ArrayList<LocalDate>(projectPlanningWrapper.getPossibleDatesToPlan());
BeanItemContainer<LocalDate> container = new BeanItemContainer<LocalDate>(LocalDate.class);

Collections.sort(availableDates);
container.addAll(availableDates);

possibleDatesToPlan.setContainerDataSource(container)
possibleDatesToPlan.setConverter(new Converter() {

    private static final long serialVersionUID = 1L;

    @Override
    public Object convertToModel(Object value, Class targetType, Locale locale) throws ConversionException {
        if(value == null) {
            return null;
        } else{
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
            return LocalDate.parse((String) value, formatter);
        }
    }

    @Override
    public Object convertToPresentation(Object value, Class targetType, Locale locale) throws ConversionException {
        if (value == null){
            return null;
        }
        
        else{
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
            return ((LocalDate) value).format(formatter);
        }
    }

    @Override
    public Class getModelType() {
        return LocalDate.class;
    }

    @Override
    public Class getPresentationType() {
        return String.class;
    }
});

Hi,

you can set the captions of individual items by comboBox.setItemCaption(itemId, caption), which might be enough for your needs. If you need the same conversion in many places, one possible solution would be to create a new ConverterFactory for the session, which would look like something like the following:

    public class StringToLocalDateConverter implements Converter<String, LocalDate> {

        @Override
        public LocalDate convertToModel(String value, Class<? extends LocalDate> targetType, Locale locale)
                throws com.vaadin.data.util.converter.Converter.ConversionException {
            if(value == null) {
                return null;
            } else{
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
                return LocalDate.parse((String) value, formatter);
            }
        }

        @Override
        public String convertToPresentation(LocalDate value, Class<? extends String> targetType, Locale locale)
                throws com.vaadin.data.util.converter.Converter.ConversionException {
               if (value == null){
                    return null;
                }
                
                else{
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
                    return ((LocalDate) value).format(formatter);
                }
        }

        @Override
        public Class<LocalDate> getModelType() {
            return LocalDate.class;
        }

        @Override
        public Class<String> getPresentationType() {
            return String.class;
        }
        
    }
    
    public class MyConverterFactory extends DefaultConverterFactory {
        @Override
        protected <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> findConverter(
                Class<PRESENTATION> presentationType, Class<MODEL> modelType) {
            // Your specific localDate converter
            if (presentationType == String.class && modelType == LocalDate.class) {
                return (Converter<PRESENTATION, MODEL>) new StringToLocalDateConverter();
            }
            // Fall back to default in other cases
            return super.findConverter(presentationType, modelType);
        }
    }

    private void createComboBox(VerticalLayout layout) {
        VaadinSession.getCurrent().setConverterFactory(new MyConverterFactory());
        LocalDate ld = LocalDate.now();
        LocalDate ld2 = ld.plusDays(3);
        List<LocalDate> list = new ArrayList<>();
        list.add(ld);
        list.add(ld2);
        BeanItemContainer<LocalDate> bic = new BeanItemContainer<>(LocalDate.class, list);
        ComboBox cb = new ComboBox();
        cb.setContainerDataSource(bic);
        layout.addComponent(cb);
    }

Hi, Olli. Thanks for the help.

In the end I decided to create a method that converts from LocalDate to Date and another one to do the other way. Still, it seems like a terrible solution to convert every value before I put it inside the comboBox and then convert it back when the user choose one (I have to use it in a filter). But I’ll have to stay with that for a while.

Thanks again.

I’d suggest to throw in
Viritin add-on
and using it’s TypedSelect component. It just makes things just so much easier:

https://github.com/viritin/viritin/blob/master/src/test/java/org/vaadin/viritin/it/examples/LocalDateSelector.java

cheers,
matti