Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map deserialization inside objects #25

Closed
mjp91 opened this issue Sep 18, 2017 · 7 comments
Closed

Map deserialization inside objects #25

mjp91 opened this issue Sep 18, 2017 · 7 comments

Comments

@mjp91
Copy link

mjp91 commented Sep 18, 2017

As mentioned in gitter:

Exception raised when trying to pass in a Map via a mutation:

mutation isoCountryUpdate {
  isoCountryUpdate(input: {
    clientMutationId: "1234"
      isoCountry: {
          id: 2747
          codeAlpha2: "YY"
          codeAlpha3: "YYY"
          name: "TEST"
          codeNumeric: "66"
          confirmationResponses: {key: "TEST", value: "NO"}
      }
    }) {
    clientMutationId
    result {
      id
      name
    }
  }
}
Caused by: java.lang.IllegalArgumentException: Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token
 at [Source: N/A; line: -1, column: -1] (through reference chain: p4.entities.common.IsoCountry["confirmationResponses"])
    at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3605) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:3546) ~[jackson-databind-2.8.9.jar:2.8.9]
    at io.leangen.graphql.metadata.strategy.value.jackson.JacksonValueMapper.fromInput(JacksonValueMapper.java:33) ~[spqr-0.9.3.jar:na]
    at io.leangen.graphql.metadata.strategy.value.ValueMapper.fromInput(ValueMapper.java:11) ~[spqr-0.9.3.jar:na]
    at io.leangen.graphql.generator.mapping.common.InputValueDeserializer.getArgumentValue(InputValueDeserializer.java:19) ~[spqr-0.9.3.jar:na]
    at io.leangen.graphql.execution.ResolutionEnvironment.getInputValue(ResolutionEnvironment.java:63) ~[spqr-0.9.3.jar:na]
    at io.leangen.graphql.execution.OperationExecutor.execute(OperationExecutor.java:91) ~[spqr-0.9.3.jar:na]
    at io.leangen.graphql.execution.OperationExecutor.execute(OperationExecutor.java:59) ~[spqr-0.9.3.jar:na]
    ... 129 common frames omitted
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token
 at [Source: N/A; line: -1, column: -1] (through reference chain: p4.entities.common.IsoCountry["confirmationResponses"])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.DeserializationContext.reportMappingException(DeserializationContext.java:1234) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1122) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1075) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer._deserializeFromEmpty(StdDeserializer.java:892) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:358) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:27) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:504) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:104) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140) ~[jackson-databind-2.8.9.jar:2.8.9]
    at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3600) ~[jackson-databind-2.8.9.jar:2.8.9]
    ... 136 common frames omitted
@brettcooper
Copy link

I believe we had the same issue and fixed it by setting:
generator.withScalarMappingStrategy(new MapScalarStrategy());

@kaqqao
Copy link
Member

kaqqao commented Oct 16, 2017

This will indeed change the way maps are treated, and will solve the immediate issue. Maps will be treated as complex scalar values (i.e. JSON blobs) and not transformed into lists of key-value pairs. But this means subselection is not possible (scalars are leaf types)...

@kaqqao
Copy link
Member

kaqqao commented Nov 18, 2017

@mjp91 @brettcooper @bpoussin
I was looking into what's needed to make Jackson deserialize maps when they're encoded as list of key-value pairs. It's doable, but quite complex. So I'm wondering if it's worth it.
In your use-cases so far, did you benefit from the current default behavior that represents maps as lists (preserving type-safety), or does the simple map-as-a-blob strategy offered by MapScalarStrategy suffice?

@mjp91
Copy link
Author

mjp91 commented Nov 20, 2017

@kaqqao we've got by treating them as scalars, would be nice to have the extra type safety and sub-selection but not a must

@brettcooper
Copy link

@kaqqao MapScalarStrategy() seems to serve our needs for the time being.

@kaqqao kaqqao closed this as completed in 59956d1 Jan 15, 2018
@kaqqao
Copy link
Member

kaqqao commented Jan 15, 2018

InputConverter mechanism has been completely overhauled to attach itself to the Jackson/Gson deserialization logic to properly apply the conversions throughout the object hierarchy. This unfortunately imposes limitations on TYPE_USE annotations on input fields (@GraphQLId being the only relevant example) because not a single JSON library for Java supports AnnotatedType as of yet.

Worth to note, maps are now treated as scalars by default, so the MapScalarStrategy is now deprecated.

@kvzn
Copy link

kvzn commented Jan 14, 2019

I solved the this JSON parse issue by replacing "Map<String, String> request" with "Map<String, Object> request"

@PostMapping(value = "/graphql", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public Map<String, Object> graphql(@RequestBody Map<String, Object> request, HttpServletRequest raw) {
        ExecutionResult executionResult = graphQL.execute(ExecutionInput.newExecutionInput()
                .query(request.get("query").toString())
                .operationName(request.get("operationName") != null ? request.get("operationName").toString() : null)
                .context(raw)
                .build());
        return executionResult.toSpecification();
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants