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
- Created a POJO with a map attribute
- use dgs data fetcher to response above pojo
- 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);
}
}
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);
}
}