Home > Enterprise >  GraphQL Scalar for java.time.LocalDate parses dates as StringValue
GraphQL Scalar for java.time.LocalDate parses dates as StringValue

Time:04-20

I try to parse a date, e.g. "2022-02-02" as java.time.LocalDate.

Why the values passed to the scalar class are wrapped into curly braces? And how do I fix this?

I configured the scalar for java.time.LocalDate:

@Component
public class DateScalar extends GraphQLScalarType {

public DateScalar() {
    super("Date", "java.time.LocalDate", new Coercing() {
        @Override
        public Object serialize(Object o) throws CoercingSerializeException {
            return DateTimeFormatter.ofPattern("yyyy-MM-dd").format((LocalDate) o);
        }

        @Override
        public Object parseValue(Object o) throws CoercingParseValueException {
            return LocalDate.parse(o.toString());
        }

        @Override
        public Object parseLiteral(Object o) throws CoercingParseLiteralException {
            if (o == null) {
                return null;
            }
            return parseValue(o.toString());
        }
        });
    }
}

This is the query:

mutation {
createEvent(createEventRequest: {
    name: "test",
    description: "test description",
    userId: 1,
    participants: [{
        firstName: "first",
        lastName: "last"
    }],
  location: {
    street: "street",
    streetNumber: "streetNumber",
    country: "country"
  },
  duration: {
    entireDay: false,
    recurringDate: false,
    start: "2018-09-03"
  }
}) {
    id
    name
    description
    participantResponses {
        id
        firstName
        lastName
    }
    locationResponse {
        id
        street
        streetNumber
        country
    }
    durationResponse {
        id
        start
        end
        entireDay
        recurringDate
    }
    userResponse {
        id
        firstName
        lastName
        email
    }
}
}

The error says that Text 'StringValue{value='2018-09-03'}' could not be parsed at index 0. I do not really understand why this is still wrapped into curly brackets.

java.time.format.DateTimeParseException: Text 'StringValue{value='2018-09-03'}' could not be parsed at index 0 at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2052) ~[na:na] at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1954) ~[na:na] at java.base/java.time.LocalDate.parse(LocalDate.java:430) ~[na:na] at java.base/java.time.LocalDate.parse(LocalDate.java:415) ~[na:na] at com.projects.calendar.scalar.DateScalar$1.parseValue(DateScalar.java:21) ~[classes/:na] at com.projects.calendar.scalar.DateScalar$1.parseLiteral(DateScalar.java:29) ~[classes/:na] at graphql.validation.ValidationUtil.parseLiteral(ValidationUtil.java:113) ~[graphql-java-9.2.jar:na] at graphql.validation.ValidationUtil.isValidLiteralValue(ValidationUtil.java:90) ~[graphql-java-9.2.jar:na] at graphql.validation.ValidationUtil.isValidLiteralValue(ValidationUtil.java:141) ~[graphql-java-9.2.jar:na] at graphql.validation.ValidationUtil.isValidLiteralValue(ValidationUtil.java:107) ~[graphql-java-9.2.jar:na] at graphql.validation.ValidationUtil.isValidLiteralValue(ValidationUtil.java:141) ~[graphql-java-9.2.jar:na] at graphql.validation.ValidationUtil.isValidLiteralValue(ValidationUtil.java:107) ~[graphql-java-9.2.jar:na] at graphql.validation.rules.ArgumentsOfCorrectType.checkArgument(ArgumentsOfCorrectType.java:23) ~[graphql-java-9.2.jar:na] at graphql.validation.RulesVisitor.checkArgument(RulesVisitor.java:98) ~[graphql-java-9.2.jar:na] at graphql.validation.RulesVisitor.enter(RulesVisitor.java:65) ~[graphql-java-9.2.jar:na] at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:33) ~[graphql-java-9.2.jar:na] at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:38) ~[graphql-java-9.2.jar:na] at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:38) ~[graphql-java-9.2.jar:na] at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:38) ~[graphql-java-9.2.jar:na] at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:38) ~[graphql-java-9.2.jar:na] at graphql.validation.LanguageTraversal.traverse(LanguageTraversal.java:28) ~[graphql-java-9.2.jar:na] at graphql.validation.Validator.validateDocument(Validator.java:42) ~[graphql-java-9.2.jar:na] at graphql.GraphQL.validate(GraphQL.java:539) ~[graphql-java-9.2.jar:na] at graphql.GraphQL.parseAndValidate(GraphQL.java:509) ~[graphql-java-9.2.jar:na] at graphql.GraphQL.lambda$parseValidateAndExecute$3(GraphQL.java:490) ~[graphql-java-9.2.jar:na] at graphql.execution.preparsed.NoOpPreparsedDocumentProvider.get(NoOpPreparsedDocumentProvider.java:11) ~[graphql-java-9.2.jar:na] at graphql.GraphQL.parseValidateAndExecute(GraphQL.java:486) ~[graphql-java-9.2.jar:na] at graphql.GraphQL.executeAsync(GraphQL.java:470) ~[graphql-java-9.2.jar:na] at graphql.GraphQL.execute(GraphQL.java:401) ~[graphql-java-9.2.jar:na] at graphql.servlet.GraphQLQueryInvoker.query(GraphQLQueryInvoker.java:92) ~[graphql-java-servlet-6.1.2.jar:na] at graphql.servlet.GraphQLQueryInvoker.query(GraphQLQueryInvoker.java:88) ~[graphql-java-servlet-6.1.2.jar:na] at graphql.servlet.GraphQLQueryInvoker.query(GraphQLQueryInvoker.java:39) ~[graphql-java-servlet-6.1.2.jar:na] at graphql.servlet.AbstractGraphQLHttpServlet.query(AbstractGraphQLHttpServlet.java:265) ~[graphql-java-servlet-6.1.2.jar:na] at graphql.servlet.AbstractGraphQLHttpServlet.lambda$new$2(AbstractGraphQLHttpServlet.java:183) ~[graphql-java-servlet-6.1.2.jar:na] at graphql.servlet.AbstractGraphQLHttpServlet.doRequest(AbstractGraphQLHttpServlet.java:236) ~[graphql-java-servlet-6.1.2.jar:na] at graphql.servlet.AbstractGraphQLHttpServlet.doRequestAsync(AbstractGraphQLHttpServlet.java:227) ~[graphql-java-servlet-6.1.2.jar:na] at graphql.servlet.AbstractGraphQLHttpServlet.doPost(AbstractGraphQLHttpServlet.java:257) ~[graphql-java-servlet-6.1.2.jar:na] at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.56.jar:4.0.FR] at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.56.jar:4.0.FR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.56.jar:9.0.56] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) ~[spring-web-5.3.15.jar:5.3.15] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.15.jar:5.3.15] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.15.jar:5.3.15] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.15.jar:5.3.15] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.56.jar:9.0.56] at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

This is the graphqls file if needed:

type Query {
    user(id : Int) : UserResponse,
    userByEmail(email : String) : [UserResponse]
}

type Mutation {
    createUser(createUserRequest: CreateUserRequest) : UserResponse
    createEvent(createEventRequest: CreateEventRequest) : EventResponse
}

input CreateEventRequest {
    name: String,
    description: String,
    participants: [Participant],
    location: Location,
    duration: Duration,
    userId: Int
}

input Duration {
    start:Date,
    end:Date,
    entireDay:Boolean      ,
    recurringDate:Boolean
}

input Location {
    street:String ,
    streetNumber:String,
    country:String
}

input Participant {
    firstName: String,
    lastName: String
}

type UserResponse {
    id: Int,
    firstName: String,
    lastName: String,
    email: String
}

type EventResponse {
    id: Int,
    name: String,
    description: String,
    participantResponses: [ParticipantResponse],
    locationResponse: LocationResponse,
    durationResponse: DurationResponse,
    userResponse: UserResponse
}

type DurationResponse {
    id: Int
    start: Date
    end: Date
    entireDay: Boolean
    recurringDate: Boolean
}


type LocationResponse {
    id: Int,
    street: String ,
    streetNumber: String ,
    country: String
}

type ParticipantResponse {
    id: Int,
    firstName: String,
    lastName: String
}

input CreateUserRequest {
    firstName: String!,
    lastName: String!,
    email: String!
}

scalar Date

CodePudding user response:

The GraphQL is sending the date string as full text as you have declared this as Date. Alternatively, you can declare start as String and parse the string to Date at Java end.

input Duration {
start: String,
end: String,
entireDay:Boolean      ,
recurringDate:Boolean

}

CodePudding user response:

The parseLiteral method parameter is actually a node of the abstract syntax tree produced from parsing the GraphQL query. The method implementation should extract the literal value from the node:

@Override
public LocalDate parseLiteral(Object input) throws CoercingParseLiteralException {
  if (input instanceof StringValue) {
    try {
      return LocalDate.parse(((StringValue) input).getValue());
    } catch (DateTimeParseException e) {
      throw new CoercingParseLiteralException("Cannot parse ["   input   "] to LocalDate", e);
    }
  } else {
    throw new CoercingParseLiteralException(
        "Expected literal of type StringValue but was "   input.getClass());
  }
}
  • Related