Vaadin: value from DateField is null after conversion

蓝咒 提交于 2019-12-24 00:28:42

问题


I faced with problem that I'm incapable to save typed date in the DateField to the database. I'm using Hibernate as ORM framework and there is Order entity that has java.sql.Date fields. But as far as I know DateField works only with LocalDate/LocalDateTime. So then in order to bind those fields I created Converter class. The problem was that the Converter received a null value and that's why I got a stacktrace, but the issue was solved in this thread: Vaadin DateField saves null value to database Many thanks to @Cashbee. After the Converter class was fixed, the values were correctly saved to the database. But after a while the case repeated

Currently, when I click on the save() button, then the correct value comes to the Converter:

However, after the binding the value is null:

Could you please help me to find solution

VAADIN v.8.6.2

Entity(simplified):

/*imports...*/
import java.sql.Date;

@Entity
@DynamicInsert
@DynamicUpdate
@Table(name = "Orders")
public class Order{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "OrderID", nullable = false)
    private Long orderID;

    @Column(name = "CreationDate", nullable = false)
    private Date creationDate;

public Date getCreationDate() { return creationDate; }

public void setCreationDate(Date creationDate) { this.creationDate = creationDate; }

//... other getters & setters

}

Converter:

import com.vaadin.data.Converter;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;

import java.sql.Date;
import java.time.LocalDate;

public class SqlDateToLocalDateConverter implements Converter<LocalDate, java.sql.Date> {

    @Override
    public Result<java.sql.Date> convertToModel(LocalDate value, ValueContext context) {
        if (value == null) {
            return Result.ok(null);
        }
        return Result.ok( java.sql.Date.valueOf(value) );
    }

    @Override
    public LocalDate convertToPresentation(java.sql.Date value, ValueContext context) {
        if (value == null) {
            return LocalDate.now();
        }
        return value.toLocalDate();
    }
}

Class with bindings(simplified):

public class AddOrderModalView extends Window {

    private OrderService orderService = new OrderService();
    private Order order = new Order();
    Binder<Order> binder = new Binder<>(Order.class);

    private ChangeHandler changeHandler = new ChangeHandler() {
        @Override
        public void onChange() { }
    };

    private FormLayout formLayout = new FormLayout();
    private DateField creationDate = new DateField("Creation Date");
    private Button save = new Button("Save");
    private Button cancel = new Button("Cancel");


    public AddOrderModalView() {

        VerticalLayout subContent = new VerticalLayout();
        subContent.setSizeFull();

        HorizontalLayout actions = new HorizontalLayout();
        actions.addComponents(save, cancel);

        creationDate.setDateFormat("yyyy-MM-dd HH:mm:ss");

        formLayout.addComponents(creationDate, actions);

        subContent.addComponent(formLayout);
        setContent(subContent);

        save.addClickListener(e -> save());
        cancel.addClickListener(e -> close());

        bindingFields();

        setModal(true);
    }

    private void bindingFields() {
        binder.forField(this.creationDate)
                .withConverter(new SqlDateToLocalDateConverter())   //Converter java.sql.Data -> LocalDate and vise versa
                .bind(Order::getCreationDate, Order::setCreationDate);

        // ...other fields

       //binder.bindInstanceFields(this);

       binder.setBean(order);
    }

    public interface ChangeHandler { void onChange(); }


    private void save() {
        if (binder.validate().isOk()) {
            orderService.persist(order);
            close();
            changeHandler.onChange();
        }
    }
}

Stacktrace:

org.hibernate.PropertyValueException: not-null property references a null or transient value : com.haulmont.testtask.model.Order.creationDate
        at org.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:108)
        at org.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:56)
        at org.hibernate.action.internal.AbstractEntityInsertAction.nullifyTransientReferencesIfNotAlready(AbstractEntityInsertAction.java:115)
        at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:69)
        at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:645)
        at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:282)
        at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:263)
        at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317)
        at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:359)
        at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:292)
        at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:200)
        at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:131)
        at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
        at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
        at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
        at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
        at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
        at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:709)
        at org.hibernate.internal.SessionImpl.save(SessionImpl.java:701)
        at org.hibernate.internal.SessionImpl.save(SessionImpl.java:696)
        at com.haulmont.testtask.dao.OrderDao.persist(OrderDao.java:67)
        at com.haulmont.testtask.service.OrderService.persist(OrderService.java:18)
        at com.haulmont.testtask.ui.AddOrderModalView.save(AddOrderModalView.java:189)
        at com.haulmont.testtask.ui.AddOrderModalView.lambda$new$61446b05$1(AddOrderModalView.java:113)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:499)
        at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:273)
        at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:237)
        at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:1014)
        at com.vaadin.ui.Button.fireClick(Button.java:384)
        at com.vaadin.ui.Button$1.click(Button.java:57)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:155)
        at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:116)
        at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:445)
        at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:410)
        at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:274)
        at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:90)
        at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
        at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1601)
        at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:445)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:845)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1689)
        at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:225)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1676)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:581)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1174)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1106)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:213)
        at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:119)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
        at org.eclipse.jetty.server.Server.handle(Server.java:524)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:319)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:253)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
        at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)
        at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303)
        at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148)
        at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589)
        at java.lang.Thread.run(Thread.java:748)

回答1:


I have recreated your setup with only minor differences (using Vaddin 8.4.3 and no attempt to save to DB) and for me, it works.

However, I do have an idea where your problem is:

In your Converter method convertToPresentation(), you return LocalDate.now() if the java.sql.Date value is null.
This will show the value of today in the DateField, although the value of order.creationDate is still null.

The error would only come up if you never manually changed the value of creationDate via the DateField. As soon as you set a new Value there, your order.creationDate value will be updated successfully and no longer be null.

To prevent this from happening, please change the return value of convertToPresentation() to null if the value is null

@Override
public LocalDate convertToPresentation(java.sql.Date value, ValueContext context) {
    if (value == null) {
        //return LocalDate.now();
        return null;
    }
    return value.toLocalDate();
}

If you want the creationDate value to be set initially to today, you can do that in your bindings view before calling binder.setBean(order);

order.setCreationDate(new java.sql.Date(Calendar.getInstance().getTime().getTime());); //not sure how, I just googled it
binder.setBean(order);


来源:https://stackoverflow.com/questions/53762129/vaadin-value-from-datefield-is-null-after-conversion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!