Troubleshooting GWT RPC

Originally posted on 2020-11-11

GWT RPC is great. It lets you share data structures from the server with the client. There are some restrictions but overall it works really well for the kinds of projects I'm involved with.

But like anything else there are always times when things just don't work. If you're trying to use GWT RPC and you're getting 500 errors, possibly without any exceptions thrown in your code that you can see, then here are my tips for getting up and running again.

Make sure the class you're sending to the client implements IsSerializable!

If you forget to do this the code may compile but the server will never be able to send that class to the client. Luckily you just need to usually change something like this:

public class ServiceData {

To this:

import com.google.gwt.user.client.rpc.IsSerializable;

public class ServiceData implements IsSerializable {

And everything else is taken care of for you.

Make sure you have a no argument constructor

This isn't strictly required if your class can be instantiated with a default constructor. This means that you don't have any final fields that are assigned inside another constructor. If you have a constructor that does any work/assignments its best to create a no argument constructor to be safe.

Use concrete classes and make copies of things like lists when the source type is unknown

I was trying to copy a List<String> into an object I was sending over the wire. My expectation was that the source type was ArrayList<String> or something similar. However, it was actually an UnmodifiableRandomAccessList from the java.util.Collections.

In AWS Lambda I was seeing that the request was completing successfully and then the function just returned an error:

(79139e27-da08-4cf8-8f60-6a4f270e97d3) Endpoint response body before transformations: [Binary Data]
(79139e27-da08-4cf8-8f60-6a4f270e97d3) Method response body after transformations: The call failed on the server; see server log for details

It should look more like this:

(130994dd-2340-40fe-b37f-ab6f34650744) Endpoint response body before transformations: [Binary Data]
(130994dd-2340-40fe-b37f-ab6f34650744) Method response body after transformations: ��ZIw�F�/:�9Dc#����E����f�@�Eb,Z�맺�w��3�9Hz������~���F��,���Y�_�)�c�������l	?�-����36������Mm�ˍ��8����^�T<���`���â%S۝Ö���v�b�����`qv�<t����}�JMú�"�w|p�b3�!�hin����|c����E��i��X�$S�K���fri(�`!��2��b=X"�ė�}�4��G�i�y�J��&�D��5JΜ��'����:h!WǶ �Id���1��1�\�C�%��$p��3�O=ц-y�}!���H����-yo����
2 S��"E�W�u�3����X��1Ɩ>4JZ�+-f�|3�hϧ�`�-�g1��c��b��="y8�E��nI"d�Q�N�"�uD�s}g�b,r.�����w�(LO�zV�gn{k!���S#ʐ��a:Ԧ�$���G��]�#��|dut���<�Nd�wE�C:V�zd�T�\�Y�RHD�>r���څ�O�1պ�L5������c��l��f�:��m�ü��ƭ�~3u!&3� �p]�|�&/0M|ϕ]�"��Q�<#�����vOE[��`]�FK3�6�����D���#��d�*�4�R�QM�ri��`<����
S"��B��	#I�����x�p�CH�pD�����;j�i�5
�+-�wk�]��ɠS-t��!�TG>�DB>b܋ϱ�$����au�A��0G�-�di3�� �y1������!^�)�����>�����������>¥'W?c[~.�*N�E:;�bÅ�'��do���$�S��7Z�,]�>:��Tl�;�Vc���':���ԩX��;Lf/R�|���ҥ�ȓ�
����b��𥻧l�C,N�7ɋ�t2�-�*B�[j�b�L�^I!#�i�Z����� [TRUNCATED]

So if you're having trouble getting data over the wire I'd recommend:

Change all List<T> members of the class you're serializing to ArrayList<T>. Normally we recommend against this in Java but in this case we need to find out where a different list implementation is being used.

Find anywhere that an assignment to the new ArrayList<T> breaks and replace code that looks like this:

returnObject.data = otherClass.data;

To something like this:

returnObject.data = new ArrayList<T>(otherClass.data);

Personally I like to make a constructor to do the work for me so I can't forget. It also keeps the downstream code a bit cleaner. Like this:

public class ReturnObject implements IsSerializable {
    public ArrayList<String> data;

    public ServiceData() {
        // Required for GWT RPC serialization
    }

    public ServiceData(List<String> data) {
        this.data = new ArrayList<>(data);
    }
}

Then I can create an initialize the object in a one-liner so I don't need multi-line Lambdas or additional functions to do the construction work.