Problem with AbstractJavaScriptComponent in Vaadin 7.4.

Hello!

I’ve moved my application from Vaadin 7.3.10 to Vaadin 7.4.3. After adjusting the new dependencies, and replacing references from “org.json” to “elemental.json”, my custom AbstractJavaScriptComponent seems to have problems to convert Java types to Javascript types when calling the “callFunction(…)” method.

public class JsMap extends AbstractJavaScriptComponent {

    private static final long serialVersionUID = 1L;
    
    public JsMap() {
    
        super();
                
    }
    
    public void drawDevices(List<Integer> identifiers, List<List<String>> dataStrings, List<List<Double>> locations, List<Integer> connectionsStatus, List<Boolean> errorsStatus)
    {
        callFunction("drawDevices", identifiers, dataStrings, locations, connectionsStatus, errorsStatus);
    }
    
}

Seems that Vaadin doesn’t like List<List<…>> anymore, throwing this exception:

abr 07, 2015 8:07:58 AM com.vaadin.server.DefaultErrorHandler doDefault
GRAVE: 
elemental.json.JsonException: Collection is missing generics
    at com.vaadin.server.JsonCodec.encodeChild(JsonCodec.java:900)
    at com.vaadin.server.JsonCodec.encodeCollection(JsonCodec.java:884)
    at com.vaadin.server.JsonCodec.encode(JsonCodec.java:665)
    at com.vaadin.server.JsonCodec.encodeArrayContents(JsonCodec.java:873)
    at com.vaadin.server.JsonCodec.encode(JsonCodec.java:688)
    at com.vaadin.server.JavaScriptCallbackHelper.invokeCallback(JavaScriptCallbackHelper.java:97)
    at com.vaadin.ui.AbstractJavaScriptComponent.callFunction(AbstractJavaScriptComponent.java:181)
    at es.ccu.teseo.web.component.JsMap.drawDevices(JsMap.java:50)
    at es.ccu.teseo.web.ui.view.MapView.refreshMap(MapView.java:443)
    at es.ccu.teseo.web.ui.view.MapView.loadData(MapView.java:336)

Any idea?

Best regards,

Antonio Perdices.

Hummm… Same problem here?

https://vaadin.com/forum#!/thread/9568077

There’s a ticket open for it :

https://vaadin.com/forum#!/thread/9568077

Problem still persist in 7.4.5.

http://dev.vaadin.com/ticket/15446

Hello Antonio, I found the same problem still in Vaadin 7.4.7
I narrowed the problem to the following to the method com.vaadin.server.JsonCodec::encodeChild
I opted for replacing the method with my own version:

//Hack Demch
private static JsonValue encodeChild(Type targetType, int typeIndex, Object o, ConnectorTracker connectorTracker) {
Type childType = null;
if (targetType instanceof ParameterizedType) {
childType = ((ParameterizedType) targetType).getActualTypeArguments()[typeIndex]
;
} else {
childType = Object.class;
}
EncodeResult encodeResult = encode(o, null, childType, connectorTracker);
return encodeResult.getEncodedValue();
}
//HackE

Thanks Diego! I will try it as soon as possible.

EDIT: Diego, I assume you run your self-compiled Vaadin libraries… True?

There’s faster way—probably it’s not a bug—only problem is that it’s not described enough!

Change your code as follows (cf.
stackoverflow.com
): for field and method parameters/returned value (provided they’re in fact types with parameters!) you may use

Field field = …
ParametrizedType ​type = (ParameterizedType) field.getGenericType();

and

Method method = …
int parameterNo = 1; // first parameter
type = (ParameterizedType) method.getGenericParameterTypes()[parameterNo - 1]
; 

and

Method method = …
ParametrizedType type = (ParametrizedType) method.getGenericReturnType();

For example if you have
arguments
of class
List
then this class is refered to as
type
above/belowe and
String
is
parameterType
below. If you have type in superclass (e.g. java
Collection
) you might even use:

ParametrizedType ​type = arguments.getClass().getGenericSuperclass()

Then instead of something similar to

JsonArray encodedValue = (JsonArray) JsonCodec.encode(arguments, null, parameterType, null);

you should write

JsonValue encodedValue = JsonCodec.encode(arguments, null, type, null).getEncodedValue();

I wanna cookie! :slight_smile:

This is a GSON Workaround:

pom.xml:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.3.1</version>
</dependency>

src/main/java/my/package/JsMap.java:

[code]
package my.package;

@JavaScript({ “js/JsMapConnector.js” })
@SuppressWarnings(“serial”)
public class JsMap extends AbstractJavaScriptComponent {
public JsMap() {
super();
}
public void drawDevices(List identifiers, List<List> dataStrings, List<List> locations, List connectionsStatus, List errorsStatus)
{
Gson gson = new GsonBuilder().create();
callFunction(“drawDevices”, gson.toJson(identifiers), gson.toJson(dataStrings), gson.toJson(locations), gson.toJson(connectionsStatus), gson.toJson(errorsStatus));
}
}
[/code]src/main/resources/my/package/JsMapConnector.js:

window.my_package_JsMap = function() {
    this.drawDevices = function(identifiers, dataStrings, locations, connectionsStatus, errorsStatus) {
        //parse String to JSON
        identifiers=JSON.parse(identifiers);
        dataStrings=JSON.parse(dataStrings);
        locations=JSON.parse(locations);
        connectionsStatus=JSON.parse(connectionsStatus);
        errorsStatus=JSON.parse(errorsStatus);
        
        console.log(identifiers);
        console.log(dataStrings);
        console.log(locations);
        console.log(connectionsStatus);
        console.log(errorsStatus);
    };
}