feat(graphql): GraphQL client support + @Mapped enum binding + WebSocket subprotocols#5141
Conversation
|
Compared 11 screenshots: 11 matched. |
Android screenshot updatesCompared 122 screenshots: 121 matched, 1 updated.
Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
Cloudflare Preview
|
✅ ByteCodeTranslator Quality ReportTest & Coverage
Benchmark Results
Static Analysis
Generated automatically by the PR CI workflow. |
|
Compared 122 screenshots: 122 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
Compared 94 screenshots: 94 matched. |
|
Compared 122 screenshots: 122 matched. Benchmark Results
Detailed Performance Metrics
|
|
Compared 122 screenshots: 122 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
…ket subprotocols Adds a GraphQL client stack that mirrors the existing OpenAPI/gRPC "spec -> generated typed client" architecture, plus two enabling enhancements. GraphQL: - Runtime com.codename1.io.graphql: GraphQL invoker (HTTP POST queries/ mutations + decodeJson + encodeVariables), GraphQLResponse (data and errors co-exist), GraphQLError, GraphQLClients registry, and GraphQLSubscription over com.codename1.io.WebSocket (graphql-transport-ws). - Annotations com.codename1.annotations.graphql: @GraphQLClient, @Query/@Mutation/@subscription, @var (reuses @Header and @mapped). - GraphQLClientAnnotationProcessor emits <Name>Impl + cn1app.GraphQLClientBootstrap. - cn1:generate-graphql mojo with hand-written SDL + operation-document parsers; precise operations mode and schema-only bounded-depth mode. - Bootstrap wired into JavaSEPort + Executor like the REST/gRPC ones. @mapped enum binding: - AnnotatedClass.isEnum() + PropertyTypeKind.enumType(); MappingAnnotationProcessor upgrades REFERENCE->ENUM and detects List<Enum>, emitting name()/valueOf (unknown -> null) across JSON and XML. GraphQL response/input fields now use real enum types. WebSocket subprotocols: - WebSocket.subprotocols(String...) + getSelectedSubprotocol(), threaded through WebSocketImpl. Sec-WebSocket-Protocol implemented in JavaSE, Android, iOS (webSocketTaskWithURL:protocols: + didOpenWithProtocol:), and JavaScript. GraphQL subscriptions offer graphql-transport-ws. Tests: GenerateGraphQLMojoTest, GraphQLClientAnnotationProcessorTest, GraphQLResponseTest, plus enum round-trip and subprotocol negotiation tests for the mapper and WebSocket (core mock + JavaSE RFC 6455 echo). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Documents cn1:generate-graphql, @GraphQLClient, the operations vs schema-only modes, generated output, HTTP/WebSocket wire protocol, and scope. Wired into Maven-Appendix-Goals.adoc beside the OpenAPI and gRPC goal sections. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Developer Guide build artifacts are available for download from this workflow run:
Developer Guide quality checks: |
…PC end-to-end Adds scripts/protocol-e2e: a Spring Boot server that exposes the same greeting service over REST (OpenAPI), GraphQL (Spring for GraphQL), and gRPC-Web (binary framing implemented directly, no Envoy needed), plus a Codename One client whose @restclient / @GraphQLClient / @GrpcClient sources (mirroring the cn1:generate-* output for the bundled specs) are wired by process-annotations and run on the JavaSE simulator via cn1:test. The client's AbstractTest classes perform real round-trips against the running server and assert the responses for all three protocols (GraphQL covers a query + an enum/int-variable mutation; gRPC covers a unary call; REST covers a typed GET). run-protocol-e2e.sh builds+starts the server and runs the client tests against it; .github/workflows/ protocol-e2e.yml runs it in CI alongside the hellocodenameone suites. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…yphen) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ling gate Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… & richer API OpenAPI enum support: cn1:generate-openapi now emits a Java enum per string `enum` schema (bound via the JSON mapper's name()), so model properties typed by an enum $ref get the generated enum; enums whose values are not valid Java identifiers degrade to String. gRPC already supported enums (@ProtoEnum); documented OpenAPI enums in the developer guide. GraphQL codegen fix: emit @Query/@Mutation/@subscription with a NAMED value (`value = "..."`) when operationName is also present -- a positional value alongside another element does not compile. Caught by the expanded e2e (which, unlike the mojo unit tests, compiles the generated sources); also asserted now in GenerateGraphQLMojoTest. Expanded the protocol-e2e test: the CN1 client is now GENERATED at build time (cn1:generate-openapi/-grpc/-graphql from the bundled specs into target/generated-sources/cn1), so codegen regressions break the test. The catalog API exercises enums (in response fields, path params, variables, and request fields), nested objects, list/repeated fields, multiple methods, and varied scalars across all three protocols. Validated end-to-end locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…note Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The proto / OpenAPI / GraphQL specs were committed in three places (specs/, client/common/cn1specs/, server/.../resources/graphql/), inviting drift. Now specs/ is the sole copy: the client generate-* executions read it via ../../specs, and the server copies schema.graphqls from ../specs onto the classpath at build time (process-resources) instead of committing a second copy. Validated end-to-end locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ializr skill The codename-one authoring skill that ships into every generated project only covered REST/OpenAPI (and only in passing). Add a dedicated references/api-clients.md covering all three "spec to typed client" generators that share one architecture -- REST/OpenAPI (@restclient), gRPC (@GrpcClient, gRPC-Web) and GraphQL (@GraphQLClient, subscriptions over WebSocket): the generate-* goals, annotations, response envelopes (Response/GrpcResponse/ GraphQLResponse), enum support, the EDT callback convention, and the scripts/protocol-e2e end-to-end reference. Wire it into SKILL.md (references index + task-routing table), cross-link from references/java-api-subset.md's networking section, and add the generate-grpc / generate-graphql goals alongside generate-openapi in references/build-and-run.md. Also fix stale drift in the protocol-e2e server pom comment (still described the old "greeting" service instead of the current "catalog" API). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Summary
Adds a GraphQL client stack that slots into the same "spec → generated typed client" architecture as the existing OpenAPI (
@RestClient) and gRPC (@GrpcClient) support, plus two enabling enhancements that the GraphQL work needed and that stand on their own.GraphQL (
cn1:generate-graphql+@GraphQLClient)com.codename1.io.graphql:GraphQLinvoker (HTTPPOSTqueries/mutations, publicdecodeJson/encodeVariables),GraphQLResponse<T>(data and errors co-exist for partial results),GraphQLError,GraphQLClientsregistry, andGraphQLSubscriptionover the new corecom.codename1.io.WebSocketusing thegraphql-transport-wsprotocol.com.codename1.annotations.graphql:@GraphQLClient,@Query/@Mutation/@Subscription,@Var(reuses@Headerand@Mapped).GraphQLClientAnnotationProcessoremits<Name>Impl+cn1app.GraphQLClientBootstrap, registered in the annotation-processor SPI and wired intoJavaSEPort/Executorexactly like the REST/gRPC bootstraps.cn1:generate-graphqlwith hand-written SDL + operation-document parsers. Two modes: precise operations mode (per-selection@Mappedtypes, fragments inlined, operation document embedded verbatim) and a schema-only quick-start mode (bounded-depth auto-selection,cn1.graphql.maxDepth).@Mappedenum bindingPreviously an enum-typed field was classified as a nested reference, found no mapper, and silently didn't serialise. Now
AnnotatedClass.isEnum()+PropertyTypeKind.enumType()letMappingAnnotationProcessorupgradeREFERENCE → ENUM(and detectList<Enum>), emittingname()on write andvalueOfon read (unknown values decode tonull) across both JSON and XML. GraphQL response/input fields now use real enum types instead ofString.WebSocket subprotocols (
Sec-WebSocket-Protocol)The core
WebSocketfacade gainssubprotocols(String...)+getSelectedSubprotocol(), threaded throughWebSocketImpl. Implemented across every port: JavaSE + Android hand-rolled handshakes, iOS (webSocketTaskWithURL:protocols:+didOpenWithProtocol:, with the matchingIOSNativebridge rename), and JavaScript (new WebSocket(url, protocols)+w.protocol). GraphQL subscriptions offergraphql-transport-wsduring the handshake.Tests
GenerateGraphQLMojoTest(operations + schema-only modes, fragments, enum/input emission, records vs classes),GraphQLClientAnnotationProcessorTest(impl/bootstrap,GraphQL.execute/subscribe, error cases), and a new enum round-trip case inMappingAnnotationProcessorTest.GraphQLResponseTest(envelope decode, partial errors, variable encoding) and a subprotocol case inWebSocketTest.JavaSEWebSocketImplTest.All of the above pass locally (34 GraphQL/mapping/WebSocket tests) against the current master base.
Test plan
cd maven && mvn install -Plocal-dev-javase -DskipTests— core + plugin compile.mvn -pl codenameone-maven-plugin test -Dtest=GenerateGraphQLMojoTest,GraphQLClientAnnotationProcessorTest,MappingAnnotationProcessorTestmvn -DunitTests -pl core-unittests test -Dtest=GraphQLResponseTest,WebSocketTestmvn -pl javase test -Dtest=JavaSEWebSocketImplTest./scripts/build-android-port.sh -DskipTests— Android handshake change compiles../scripts/build-ios-port.sh -DskipTests— iOS nativeWebSocketImpl.m+IOSNative.mbridge compile under ParparVM.🤖 Generated with Claude Code