graphql with map type

When graphql server (dgs framework) generate the graphql response, the Map attribute is rendered as {key=value}.
So for example

class DataObject{
....
Map<String, Double> cashByCurrencyUnadjustedUsd;
}

the dataFetcher returned the result as

from the client side, its also using dgs to parse the graphql response to DataObject.

Expected behavior

I would expect the client has no issue to parse the data, considering they are from the same project (dgs here).

Actual behavior

A jackson MismatchedInputException was thrown here:

Steps to reproduce

  1. Created a POJO with a map attribute
  2. use dgs data fetcher to response above pojo
  3. use dgs client to parse the graphql response into same POJO

https://github.com/Netflix/dgs-framework/issues/1149

the possible solution

Looks like this probably is an issue with graphql-java and graphql in general where Map is not supported type. I have tried to create a custom scalar type, something like

# in schema
scalar Map

# java code
@DgsScalar(name="Map")
public class DgsMap ....{
    public **String** serialize (Object dataFetcherResult) ..{
        return mapper.writeValueAsString(dataFetcherResult);
   }
}

this then would result out

which Jackson from dgs-client still has issue to parse.

In the end, I have left dgs-framework to parse the Map as String using default Map.toString(). Then from dgs-client, I swithed to Gson as a custom deserializer to parse the String back to Map.

Not sure whether that’s the optimal approach, but seems like thats the only option I found working at the moment.

so basically, there is no change needed on the dgs framework side. However, from the client, when dgs-client parse the response, it would use Gson to parse the `Map.toString` value.

something like

@JsonProperties(ignoreUnknown=true)
public class POJO{ //on client side

....

@Deserialize(CustomDeserializer.class)
Map<> cashByCurrencyUnadjustedUsd;
}


then in the CustomDeserializer, it basically deserialize the string using gson.

public class CustomDeserializerextends StdDeserializer<Map> { 

    Gson gson = new Gson();
    public CustomDeserializer() { 
        this(null); 
    } 

    public CustomDeserializer(Class<?> vc) { 
        super(vc); 
    }

    @Override
    public Map deserialize(JsonParser jp, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException {
        TextNode node = jp.getCodec().readTree(jp);
        String data = node.textValue();
        return gson.parse(data);
    }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s