BigDecimal in a client-side widget?

I’m writing some client-side code, and I’d like to use BigDecimal. I know initially BigDecimal wasn’t supported by GWT’s compiler, but it has been supported since GWT 2.1. I know there were some projects (e.g. GWT-math) for BigDecimal support in older versions of GWT, but I was expecting it to work out of the box with recent vaadin?

To reproduce:

  • Creat a new addon project in eclipse (using maven vaadin-archetype-widget v7.4.4)
  • add a BigDecimal field to the State
  • Compile

Output:

<snip>
[INFO]
 Compiling module com.curocomp.vaadinaddon.test.demo.DemoWidgetSet
[INFO]
    Computing all possible rebind results for 'com.vaadin.client.metadata.ConnectorBundleLoader'
[INFO]
       Rebinding com.vaadin.client.metadata.ConnectorBundleLoader
[INFO]
          Invoking generator com.vaadin.server.widgetsetutils.ConnectorBundleLoaderFactory
[INFO]
             Populating eager bundle
[INFO]
                Visiting UnsafeHtmlRendererConnector with ConnectorInitVisitor
[INFO]
                   UnsafeHtmlRendererConnector will be in the eager bundle
[INFO]
                Will serialize class com.vaadin.shared.communication.SharedState as a b
<snip>
[INFO]
             Populating ColorPickerGridConnector bundle
[INFO]
                Visiting ColorPickerGridConnector with ConnectorInitVisitor
[INFO]
                   ColorPickerGridConnector will be in the ColorPickerGridConnector bundle
[INFO]
                Will serialize class com.vaadin.shared.ui.colorpicker.ColorPickerGridState as a bean
[INFO]
             [ERROR]
 java.math.BigDecimal has the property 'scale' without getter defined.

My state object:

public class TestState extends com.vaadin.shared.AbstractComponentState {
    public BigDecimal decimalData = BigDecimal.ONE;
}

I’d really appreciate any suggestions to what I might be doing wrong!

Thanks!
Dave

I’ve just tried something equivalent using a pure GWT project (from gwt-maven-plugin archetype) that returns a BigDecimal froma n RPC call, and the pure GWT project works fine.

Is this caused by how Vaadin uses/configures the GWT compiler? The vaadin jars do contain com.google.gwt.user.client.rpc.core.java.math.BigDecimal_CustomFieldSerializer etc. so I’m still thinking this
should
work as expected with Vaadin?

Dave

The problem is that Vaadin state/rpc serialization does not support BigDecimal so the framework tries to serialize the BigDecimal as a Java bean.

Yes, I was sure there was a ticket about it but apparently not. At least the missing support was discussed at some point.

Ah - good to know it’s not just me then! :wink:

Is there a way for me to work around this? Perhaps giving the Vaadin state/rpc serialisation config or a hint to use the BigDecimal_CustomFieldSerializer ?

Or does this require a patch / fix to vaadin itself?

For anyone else stumbling where I was, I found two interfaces:

  • com.vaadin.server.communication.JSONSerializer;
  • com.vaadin.client.communication.JSONSerializer;


It appears I can teach Vaadin how to serialise a BigDecimal by implementing both of these:

Client side:

public class BigDecimal_Serializer implements JSONSerializer<BigDecimal> {

    @Override
    public BigDecimal deserialize(Type type, JsonValue jsonValue, ApplicationConnection connection) {
        return new BigDecimal(jsonValue.asString());
    }

    @Override
    public JsonValue serialize(BigDecimal value, ApplicationConnection connection) {
        return Json.create(value.toString());
    }
}

Server side:

public class BigDecimal_Serializer implements JSONSerializer<BigDecimal> {

    @Override
    public BigDecimal deserialize(Type type, JsonValue jsonValue, ConnectorTracker connectorTracker) {
        return new BigDecimal(jsonValue.asString());
    }

    @Override
    public JsonValue serialize(BigDecimal value, ConnectorTracker connectorTracker) {
        return Json.create(value.toString());
    }
}

And all my troubles have dissapeared!

Thanks for your help Artur & Johannes.

Dave

It seems this only partially works…

The clientside serializer is registered and invoked on the clientside. However the server-side serializer doesn’t get registered, so is ignored. For passing a BigDecimal from server to client, this will confusingly be enough - but it doesn’t allow the server to construct a BigDecimal returned from the client.

Unfortunately it seems that just registering a server-side JSONSerializer will not be sufficient, as the customSerializers are only used if the default actions fail - including casting to a Number.

What are the chances of a feature to fix this in the next release? I’m happy raise a ticket / submit a patch if it’s likely to be accepted?

Kind regards,
Dave

We are facing the same problem using a custom bean class… Have a look here: https://vaadin.com/forum#!/thread/10853785

I cannot find a way to register the JSONSerializer on server- and client-side. Where must both objects have to be registered? I found the class JsonCodec, but most of the “interesting” parts are private.

Hi Jens,

  1. As you noted, all the interesting parts are private, so I coudln’t find a nice way to provide custom serializers to the server side. I (for a rather nasty experiment) was able to use my server-side serializers by using Reflection to add them to the static JsonCode.customSerializers map from VaadinServlet.servletInitialized().
  2. In my case, providing a custom serializer for BigDecimal wasn’t sufficient, because the customSerializers are only considered after the default serialization policies. For BigDecimal, this would therefore always be serialized by castning to Number, and taking the Double value. (see JsonCodec.java:649 / 650)

Overall, this was very unsatisfactory. The “least bad” solution I came up with (and the approach I took in the end) is to not use BigDecimal (or other “problematic” types) in my state/RPC interfaces. My BigDecimal_Serializer implementations above (and the equivelents in the GWT source) use a string representation to serialise BigDecimal, so I have taken to simply using the String representation on my state objects. I still use BigDecimal on server-side and in the client-side widget, converting to/from strings in the server-side component and in the client-side connector.

Quite a disapointing solution, but at least one I can rationalise…

Dave

Thanks a lot for your help… So you can confirm that the GWT-serialization mechanisms like adding _CustomFieldSerializer implementations are not considered during Vaadin compilation? Is this right? Unfortunately, that would be a very disappointing but useful piece of information.

Hi Jens,

I’m a user, so only know what I’ve discovered digging around the code.

But as far as I can see, they’re not considered for vaadin’s state serialization. I didn’t actually dig into whether the same applies for the RPC interfaces.

If you end up discovering more, I would be very interested to hear!

Dave

Hi,

I was trying to find a way to ignore some fields in a State object, and I found this thread.

I also came upon the @JsonIgnore annotation used in vaadin charts (https://dev.vaadin.com/review/#/c/11748/3/addon/src/main/java/com/vaadin/addon/charts/model/ChartModel.java ). But it lloks like the charts use a different state serialization mechanism, based on Json serialization, and I couldn’t find any documentation on how to use that custom serialization.

Would the JSON serialization used in charts solve the BigDecimal serialization? If so, how could we implement that specific serialization?