diff --git a/docs/demos/common/src/main/java/com/example/hello/GreeterCallSite.java b/docs/demos/common/src/main/java/com/example/hello/GreeterCallSite.java new file mode 100644 index 00000000000..38d3022b858 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/hello/GreeterCallSite.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +package com.example.hello; + +import com.codename1.components.ToastBar; +import java.util.Arrays; + +/// Call site for the `@GrpcClient` interface `cn1:generate-grpc` emits. +/// Included by the developer guide's `generate-grpc` appendix. +class GreeterCallSite { + + // tag::appendix-goal-generate-grpc-java-002[] + void sayHello(String bearerToken) { + GreeterGrpc greeter = GreeterGrpc.of("https://grpc.example.com"); + HelloRequest request = new HelloRequest("Ada", Arrays.asList("ada", "countess"), Mood.HAPPY); + + greeter.sayHello(request, bearerToken, response -> { + if (response.isOk() && response.getResponseData() != null) { + ToastBar.showInfoMessage(response.getResponseData().message()); + } else if (response.isOk()) { + ToastBar.showErrorMessage("The server returned an empty reply"); + } else { + // getResponseCode() is the gRPC status, not the HTTP one -- + // a gRPC-Web call can carry a failure under HTTP 200. + ToastBar.showErrorMessage("gRPC status " + response.getResponseCode() + + ": " + response.getResponseErrorMessage()); + } + }); + } + // end::appendix-goal-generate-grpc-java-002[] +} diff --git a/docs/demos/common/src/main/java/com/example/hello/GreeterGrpc.java b/docs/demos/common/src/main/java/com/example/hello/GreeterGrpc.java new file mode 100644 index 00000000000..17423ea2a0a --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/hello/GreeterGrpc.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-grpc. +package com.example.hello; + +import com.codename1.annotations.grpc.GrpcClient; +import com.codename1.annotations.grpc.Rpc; +import com.codename1.annotations.rest.Header; +import com.codename1.io.grpc.GrpcClients; +import com.codename1.io.grpc.GrpcResponse; +import com.codename1.util.OnComplete; + +// tag::appendix-goal-generate-grpc-java-001[] +@GrpcClient("helloworld.Greeter") +public interface GreeterGrpc { + + @Rpc("SayHello") + void sayHello(com.example.hello.HelloRequest request, @Header("Authorization") String bearerToken, OnComplete> callback); + + static GreeterGrpc of(String baseUrl) { + return GrpcClients.create(GreeterGrpc.class, baseUrl); + } +} +// end::appendix-goal-generate-grpc-java-001[] diff --git a/docs/demos/common/src/main/java/com/example/hello/HelloReply.java b/docs/demos/common/src/main/java/com/example/hello/HelloReply.java new file mode 100644 index 00000000000..97c1fc36d08 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/hello/HelloReply.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-grpc. +package com.example.hello; + +import com.codename1.annotations.grpc.ProtoField; +import com.codename1.annotations.grpc.ProtoMessage; + +@ProtoMessage +public record HelloReply( + @ProtoField(tag = 1) String message, + @ProtoField(tag = 2, wireType = ProtoField.WireKind.SINT, name = "emoji_code") int emojiCode, + @ProtoField(tag = 3) com.example.hello.HelloRequest echo +) {} diff --git a/docs/demos/common/src/main/java/com/example/hello/HelloRequest.java b/docs/demos/common/src/main/java/com/example/hello/HelloRequest.java new file mode 100644 index 00000000000..32f4d9639f4 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/hello/HelloRequest.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-grpc. +package com.example.hello; + +import com.codename1.annotations.grpc.ProtoField; +import com.codename1.annotations.grpc.ProtoMessage; +import java.util.List; + +@ProtoMessage +public record HelloRequest( + @ProtoField(tag = 1) String name, + @ProtoField(tag = 2) List aliases, + @ProtoField(tag = 3) com.example.hello.Mood mood +) {} diff --git a/docs/demos/common/src/main/java/com/example/hello/Mood.java b/docs/demos/common/src/main/java/com/example/hello/Mood.java new file mode 100644 index 00000000000..55828a15f47 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/hello/Mood.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-grpc. +package com.example.hello; + +import com.codename1.annotations.grpc.ProtoEnum; + +@ProtoEnum +public enum Mood { + UNKNOWN(0), + HAPPY(1), + SAD(2); + + public final int number; + Mood(int n) { this.number = n; } + + public static Mood forNumber(int n) { + for (Mood v : values()) { + if (v.number == n) return v; + } + return null; + } +} diff --git a/docs/demos/common/src/main/java/com/example/petstore/PetApi.java b/docs/demos/common/src/main/java/com/example/petstore/PetApi.java index 45e66f18216..09130e88f37 100644 --- a/docs/demos/common/src/main/java/com/example/petstore/PetApi.java +++ b/docs/demos/common/src/main/java/com/example/petstore/PetApi.java @@ -1,10 +1,38 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-openapi. package com.example.petstore; import com.codename1.annotations.rest.Body; +import com.codename1.annotations.rest.Cookie; +import com.codename1.annotations.rest.DELETE; import com.codename1.annotations.rest.GET; import com.codename1.annotations.rest.Header; +import com.codename1.annotations.rest.PATCH; import com.codename1.annotations.rest.POST; +import com.codename1.annotations.rest.PUT; import com.codename1.annotations.rest.Path; +import com.codename1.annotations.rest.Query; import com.codename1.annotations.rest.RestClient; import com.codename1.io.rest.Response; import com.codename1.io.rest.RestClients; @@ -14,15 +42,20 @@ @RestClient public interface PetApi { + @POST("/pet") + void addPet(@Body com.example.petstore.model.Pet body, @Header("Authorization") String bearerToken, OnComplete> callback); + + @PUT("/pet") + void updatePet(@Body com.example.petstore.model.Pet body, @Header("Authorization") String bearerToken, OnComplete> callback); + + @GET("/pet/findByStatus") + void findPetsByStatus(@Query("status") String status, @Header("Authorization") String bearerToken, OnComplete>> callback); + @GET("/pet/{petId}") - void getPetById(@Path("petId") Long petId, - @Header("Authorization") String bearerToken, - OnComplete> callback); + void getPetById(@Path("petId") Long petId, @Header("Authorization") String bearerToken, OnComplete> callback); - @POST("/pet") - void addPet(@Body com.example.petstore.model.Pet body, - @Header("Authorization") String bearerToken, - OnComplete> callback); + @DELETE("/pet/{petId}") + void deletePet(@Path("petId") Long petId, @Header("Authorization") String bearerToken, OnComplete> callback); static PetApi of(String baseUrl) { return RestClients.create(PetApi.class, baseUrl); diff --git a/docs/demos/common/src/main/java/com/example/petstore/PetApiCallSite.java b/docs/demos/common/src/main/java/com/example/petstore/PetApiCallSite.java new file mode 100644 index 00000000000..d9236dda515 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/petstore/PetApiCallSite.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +package com.example.petstore; + +import com.codename1.components.ToastBar; + +/// Call site for the `@RestClient` interface `cn1:generate-openapi` emits. +/// Included by the developer guide's `generate-openapi` appendix. +class PetApiCallSite { + + // tag::appendix-goal-generate-openapi-java-003[] + void loadPet(String bearerToken) { + PetApi api = PetApi.of("https://petstore3.swagger.io/api/v3"); + + api.getPetById(10L, bearerToken, response -> { + // Two things have to be settled before the payload is a Pet. + // The generated impl passes null when the request never + // completed, and on an error status it forwards the raw + // Response under this type -- so on that path + // getResponseData() is the error body, not a Pet, and + // touching it as one is a cast that does not throw on iOS. + if (response == null) { + ToastBar.showErrorMessage("The request did not complete"); + } else if (response.getResponseCode() < 200 || response.getResponseCode() > 299) { + ToastBar.showErrorMessage(response.getResponseErrorMessage()); + } else if (response.getResponseData() == null) { + ToastBar.showErrorMessage("The server returned no pet"); + } else { + ToastBar.showInfoMessage(response.getResponseData().name()); + } + }); + } + // end::appendix-goal-generate-openapi-java-003[] +} diff --git a/docs/demos/common/src/main/java/com/example/petstore/StoreApi.java b/docs/demos/common/src/main/java/com/example/petstore/StoreApi.java new file mode 100644 index 00000000000..e4318617392 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/petstore/StoreApi.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-openapi. +package com.example.petstore; + +import com.codename1.annotations.rest.Body; +import com.codename1.annotations.rest.Cookie; +import com.codename1.annotations.rest.DELETE; +import com.codename1.annotations.rest.GET; +import com.codename1.annotations.rest.Header; +import com.codename1.annotations.rest.PATCH; +import com.codename1.annotations.rest.POST; +import com.codename1.annotations.rest.PUT; +import com.codename1.annotations.rest.Path; +import com.codename1.annotations.rest.Query; +import com.codename1.annotations.rest.RestClient; +import com.codename1.io.rest.Response; +import com.codename1.io.rest.RestClients; +import com.codename1.util.OnComplete; + +@RestClient +public interface StoreApi { + + @POST("/store/order") + void placeOrder(@Body com.example.petstore.model.Order body, @Header("Authorization") String bearerToken, OnComplete> callback); + + @GET("/store/order/{orderId}") + void getOrderById(@Path("orderId") Long orderId, @Header("Authorization") String bearerToken, OnComplete> callback); + + @DELETE("/store/order/{orderId}") + void deleteOrder(@Path("orderId") Long orderId, @Header("Authorization") String bearerToken, OnComplete> callback); + + static StoreApi of(String baseUrl) { + return RestClients.create(StoreApi.class, baseUrl); + } +} diff --git a/docs/demos/common/src/main/java/com/example/petstore/UserApi.java b/docs/demos/common/src/main/java/com/example/petstore/UserApi.java new file mode 100644 index 00000000000..696050235d7 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/petstore/UserApi.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-openapi. +package com.example.petstore; + +import com.codename1.annotations.rest.Body; +import com.codename1.annotations.rest.Cookie; +import com.codename1.annotations.rest.DELETE; +import com.codename1.annotations.rest.GET; +import com.codename1.annotations.rest.Header; +import com.codename1.annotations.rest.PATCH; +import com.codename1.annotations.rest.POST; +import com.codename1.annotations.rest.PUT; +import com.codename1.annotations.rest.Path; +import com.codename1.annotations.rest.Query; +import com.codename1.annotations.rest.RestClient; +import com.codename1.io.rest.Response; +import com.codename1.io.rest.RestClients; +import com.codename1.util.OnComplete; + +@RestClient +public interface UserApi { + + @POST("/user") + void createUser(@Body com.example.petstore.model.User body, @Header("Authorization") String bearerToken, OnComplete> callback); + + @GET("/user/{username}") + void getUserByName(@Path("username") String username, @Header("Authorization") String bearerToken, OnComplete> callback); + + static UserApi of(String baseUrl) { + return RestClients.create(UserApi.class, baseUrl); + } +} diff --git a/docs/demos/common/src/main/java/com/example/petstore/model/Category.java b/docs/demos/common/src/main/java/com/example/petstore/model/Category.java new file mode 100644 index 00000000000..1b5a8e71088 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/petstore/model/Category.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-openapi. +package com.example.petstore.model; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record Category(@JsonProperty("id") Long id, @JsonProperty("name") String name) {} diff --git a/docs/demos/common/src/main/java/com/example/petstore/model/Order.java b/docs/demos/common/src/main/java/com/example/petstore/model/Order.java new file mode 100644 index 00000000000..9f37044741a --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/petstore/model/Order.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-openapi. +package com.example.petstore.model; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record Order(@JsonProperty("id") Long id, @JsonProperty("petId") Long petId, @JsonProperty("quantity") Integer quantity, @JsonProperty("shipDate") String shipDate, @JsonProperty("status") String status, @JsonProperty("complete") Boolean complete) {} diff --git a/docs/demos/common/src/main/java/com/example/petstore/model/Pet.java b/docs/demos/common/src/main/java/com/example/petstore/model/Pet.java index 98ac91c5ad8..79071e56291 100644 --- a/docs/demos/common/src/main/java/com/example/petstore/model/Pet.java +++ b/docs/demos/common/src/main/java/com/example/petstore/model/Pet.java @@ -1,18 +1,32 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-openapi. package com.example.petstore.model; -import com.codename1.properties.Property; -import com.codename1.properties.PropertyBusinessObject; -import com.codename1.properties.PropertyIndex; +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; // tag::appendix-goal-generate-openapi-java-002[] -public class Pet implements PropertyBusinessObject { - public final Property id = new Property("id"); - public final Property name = new Property("name"); - private final PropertyIndex index = new PropertyIndex(this, "Pet", id, name); - - @Override - public PropertyIndex getPropertyIndex() { - return index; - } -} +@Mapped +public record Pet(@JsonProperty("id") Long id, @JsonProperty("name") String name, @JsonProperty("category") com.example.petstore.model.Category category, @JsonProperty("photoUrls") java.util.List photoUrls, @JsonProperty("tags") java.util.List tags, @JsonProperty("status") String status) {} // end::appendix-goal-generate-openapi-java-002[] diff --git a/docs/demos/common/src/main/java/com/example/petstore/model/User.java b/docs/demos/common/src/main/java/com/example/petstore/model/User.java new file mode 100644 index 00000000000..1d39d3e890a --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/petstore/model/User.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-openapi. +package com.example.petstore.model; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record User(@JsonProperty("id") Long id, @JsonProperty("username") String username, @JsonProperty("firstName") String firstName, @JsonProperty("lastName") String lastName, @JsonProperty("email") String email, @JsonProperty("password") String password, @JsonProperty("phone") String phone, @JsonProperty("userStatus") Integer userStatus) {} diff --git a/docs/demos/common/src/main/java/com/example/starwars/AddReviewData.java b/docs/demos/common/src/main/java/com/example/starwars/AddReviewData.java new file mode 100644 index 00000000000..5ebb10e2bd0 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/AddReviewData.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record AddReviewData( + AddReviewData_CreateReview createReview +) {} diff --git a/docs/demos/common/src/main/java/com/example/starwars/AddReviewData_CreateReview.java b/docs/demos/common/src/main/java/com/example/starwars/AddReviewData_CreateReview.java new file mode 100644 index 00000000000..fde719bb43c --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/AddReviewData_CreateReview.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record AddReviewData_CreateReview( + Integer stars, + String commentary +) {} diff --git a/docs/demos/common/src/main/java/com/example/starwars/ColorInput.java b/docs/demos/common/src/main/java/com/example/starwars/ColorInput.java new file mode 100644 index 00000000000..60473800f05 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/ColorInput.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record ColorInput( + Integer red, + Integer green, + Integer blue +) {} diff --git a/docs/demos/common/src/main/java/com/example/starwars/Episode.java b/docs/demos/common/src/main/java/com/example/starwars/Episode.java new file mode 100644 index 00000000000..93ce646160f --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/Episode.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +public enum Episode { + NEWHOPE, + EMPIRE, + JEDI +} diff --git a/docs/demos/common/src/main/java/com/example/starwars/HeroNameData.java b/docs/demos/common/src/main/java/com/example/starwars/HeroNameData.java new file mode 100644 index 00000000000..fcc27ad46dd --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/HeroNameData.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record HeroNameData( + HeroNameData_Hero hero +) {} diff --git a/docs/demos/common/src/main/java/com/example/starwars/HeroNameData_Hero.java b/docs/demos/common/src/main/java/com/example/starwars/HeroNameData_Hero.java new file mode 100644 index 00000000000..97e94f16ed3 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/HeroNameData_Hero.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; +import java.util.List; + +@Mapped +public record HeroNameData_Hero( + String name, + List friends +) {} diff --git a/docs/demos/common/src/main/java/com/example/starwars/HeroNameData_Hero_Friends.java b/docs/demos/common/src/main/java/com/example/starwars/HeroNameData_Hero_Friends.java new file mode 100644 index 00000000000..05299a0d771 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/HeroNameData_Hero_Friends.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record HeroNameData_Hero_Friends( + String name +) {} diff --git a/docs/demos/common/src/main/java/com/example/starwars/OnReviewData.java b/docs/demos/common/src/main/java/com/example/starwars/OnReviewData.java new file mode 100644 index 00000000000..6d37cc6f156 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/OnReviewData.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record OnReviewData( + OnReviewData_ReviewAdded reviewAdded +) {} diff --git a/docs/demos/common/src/main/java/com/example/starwars/OnReviewData_ReviewAdded.java b/docs/demos/common/src/main/java/com/example/starwars/OnReviewData_ReviewAdded.java new file mode 100644 index 00000000000..b3aba88f286 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/OnReviewData_ReviewAdded.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record OnReviewData_ReviewAdded( + Integer stars +) {} diff --git a/docs/demos/common/src/main/java/com/example/starwars/ReviewInput.java b/docs/demos/common/src/main/java/com/example/starwars/ReviewInput.java new file mode 100644 index 00000000000..a0901ee3a07 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/ReviewInput.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +import com.codename1.annotations.JsonProperty; +import com.codename1.annotations.Mapped; + +@Mapped +public record ReviewInput( + Integer stars, + String commentary, + ColorInput favoriteColor +) {} diff --git a/docs/demos/common/src/main/java/com/example/starwars/StarWarsApi.java b/docs/demos/common/src/main/java/com/example/starwars/StarWarsApi.java new file mode 100644 index 00000000000..1772da15c93 --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/StarWarsApi.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +// Generated by cn1:generate-graphql. +package com.example.starwars; + +import com.codename1.annotations.graphql.GraphQLClient; +import com.codename1.annotations.graphql.Query; +import com.codename1.annotations.graphql.Mutation; +import com.codename1.annotations.graphql.Subscription; +import com.codename1.annotations.graphql.Var; +import com.codename1.annotations.rest.Header; +import com.codename1.io.graphql.GraphQLClients; +import com.codename1.io.graphql.GraphQLResponse; +import com.codename1.io.graphql.GraphQLSubscription; +import com.codename1.util.OnComplete; + +// tag::appendix-goal-generate-graphql-java-001[] +@GraphQLClient("https://example.com/graphql") +public interface StarWarsApi { + + @Query(value = "query HeroName($episode: Episode) { hero(episode: $episode) { ...HeroFields friends { name } } } fragment HeroFields on Character { name }", operationName = "HeroName") + void heroName(@Var("episode") Episode episode, @Header("Authorization") String bearerToken, OnComplete> callback); + + @Mutation(value = "mutation AddReview($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars commentary } }", operationName = "AddReview") + void addReview(@Var("ep") Episode ep, @Var("review") ReviewInput review, @Header("Authorization") String bearerToken, OnComplete> callback); + + @Subscription(value = "subscription OnReview($ep: Episode!) { reviewAdded(episode: $ep) { stars } }", operationName = "OnReview") + GraphQLSubscription onReview(@Var("ep") Episode ep, @Header("Authorization") String bearerToken, GraphQLSubscription.Handler handler); + + static StarWarsApi of(String endpoint) { + return GraphQLClients.create(StarWarsApi.class, endpoint); + } +} +// end::appendix-goal-generate-graphql-java-001[] diff --git a/docs/demos/common/src/main/java/com/example/starwars/StarWarsCallSite.java b/docs/demos/common/src/main/java/com/example/starwars/StarWarsCallSite.java new file mode 100644 index 00000000000..f10c9cb8b4f --- /dev/null +++ b/docs/demos/common/src/main/java/com/example/starwars/StarWarsCallSite.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +package com.example.starwars; + +import com.codename1.components.ToastBar; +import com.codename1.io.graphql.GraphQLResponse; +import com.codename1.io.graphql.GraphQLSubscription; + +/// Call sites for the `@GraphQLClient` interface `cn1:generate-graphql` emits. +/// Included by the developer guide's `generate-graphql` appendix. +class StarWarsCallSite { + + // tag::appendix-goal-generate-graphql-java-002[] + void heroName(String bearerToken) { + StarWarsApi api = StarWarsApi.of("https://swapi.example.com/graphql"); + + api.heroName(Episode.EMPIRE, bearerToken, response -> { + // isOk() classifies the GraphQL payload, not the trip: a call that + // never reached the server, and a 2xx whose body would not parse, + // both arrive with an empty errors array and null data, so isOk() + // answers true for them. getResponseErrorMessage() is the one + // thing that is null only on a clean success -- it carries the + // first GraphQL error, the transport failure, or the parse + // failure -- and the HTTP code catches an error status whose body + // happened to decode. + boolean reachedTheServer = response.getResponseCode() >= 200 + && response.getResponseCode() <= 299; + if (!reachedTheServer || response.getResponseErrorMessage() != null) { + ToastBar.showErrorMessage(response.getResponseErrorMessage()); + } else if (response.getData() == null || response.getData().hero() == null) { + // And an error-free answer still need not have found anything: + // the schema declares hero as Character, not Character!. + ToastBar.showInfoMessage("No hero for that episode"); + } else { + ToastBar.showInfoMessage(response.getData().hero().name()); + } + }); + } + // end::appendix-goal-generate-graphql-java-002[] + + // tag::appendix-goal-generate-graphql-java-003[] + GraphQLSubscription watchReviews(String bearerToken) { + StarWarsApi api = StarWarsApi.of("https://swapi.example.com/graphql"); + + return api.onReview(Episode.JEDI, bearerToken, + new GraphQLSubscription.Handler() { + @Override + public void onNext(GraphQLResponse response) { + // onError is for the end of the stream. A per-field failure + // arrives here instead, as a next payload whose errors array + // is non-empty and whose data may be partial or absent. + if (response.hasErrors()) { + ToastBar.showErrorMessage(response.getResponseErrorMessage()); + } + OnReviewData data = response.getData(); + if (data != null && data.reviewAdded() != null) { + ToastBar.showInfoMessage(data.reviewAdded().stars() + " stars"); + } + } + + @Override + public void onError(GraphQLResponse response) { + ToastBar.showErrorMessage(response.getResponseErrorMessage()); + } + + @Override + public void onComplete() { + } + }); + // Hold on to the handle and call cancel() to end the stream -- + // leaving the form is the usual place to do it. + } + // end::appendix-goal-generate-graphql-java-003[] +} diff --git a/docs/demos/common/src/main/snippets/developer-guide/appendix-goal-generate-openapi-petstore.json b/docs/demos/common/src/main/snippets/developer-guide/appendix-goal-generate-openapi-petstore.json new file mode 100644 index 00000000000..e128f838d58 --- /dev/null +++ b/docs/demos/common/src/main/snippets/developer-guide/appendix-goal-generate-openapi-petstore.json @@ -0,0 +1,112 @@ +{ + "openapi": "3.0.3", + "info": { "title": "Swagger Petstore", "version": "1.0.20" }, + "servers": [ { "url": "https://petstore3.swagger.io/api/v3" } ], + "paths": { + "/pet": { + "post": { + "tags": ["pet"], "operationId": "addPet", + "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } } } }, + "responses": { "200": { "description": "ok", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } } } } } + }, + "put": { + "tags": ["pet"], "operationId": "updatePet", + "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } } } }, + "responses": { "200": { "description": "ok", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } } } } } + } + }, + "/pet/findByStatus": { + "get": { + "tags": ["pet"], "operationId": "findPetsByStatus", + "parameters": [ { "name": "status", "in": "query", "schema": { "type": "string" } } ], + "responses": { "200": { "description": "ok", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Pet" } } } } } } + } + }, + "/pet/{petId}": { + "get": { + "tags": ["pet"], "operationId": "getPetById", + "parameters": [ { "name": "petId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" } } ], + "responses": { "200": { "description": "ok", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } } } } } + }, + "delete": { + "tags": ["pet"], "operationId": "deletePet", + "parameters": [ { "name": "petId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" } } ], + "responses": { "200": { "description": "ok" } } + } + }, + "/store/order": { + "post": { + "tags": ["store"], "operationId": "placeOrder", + "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Order" } } } }, + "responses": { "200": { "description": "ok", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Order" } } } } } + } + }, + "/store/order/{orderId}": { + "get": { + "tags": ["store"], "operationId": "getOrderById", + "parameters": [ { "name": "orderId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" } } ], + "responses": { "200": { "description": "ok", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Order" } } } } } + }, + "delete": { + "tags": ["store"], "operationId": "deleteOrder", + "parameters": [ { "name": "orderId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" } } ], + "responses": { "200": { "description": "ok" } } + } + }, + "/user": { + "post": { + "tags": ["user"], "operationId": "createUser", + "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } }, + "responses": { "200": { "description": "ok", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } } + } + }, + "/user/{username}": { + "get": { + "tags": ["user"], "operationId": "getUserByName", + "parameters": [ { "name": "username", "in": "path", "required": true, "schema": { "type": "string" } } ], + "responses": { "200": { "description": "ok", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } } + } + } + }, + "components": { + "schemas": { + "Category": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" } } }, + "Tag": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" } } }, + "Pet": { + "type": "object", + "properties": { + "id": { "type": "integer", "format": "int64" }, + "name": { "type": "string" }, + "category": { "$ref": "#/components/schemas/Category" }, + "photoUrls": { "type": "array", "items": { "type": "string" } }, + "tags": { "type": "array", "items": { "$ref": "#/components/schemas/Tag" } }, + "status": { "type": "string" } + } + }, + "Order": { + "type": "object", + "properties": { + "id": { "type": "integer", "format": "int64" }, + "petId": { "type": "integer", "format": "int64" }, + "quantity": { "type": "integer", "format": "int32" }, + "shipDate": { "type": "string", "format": "date-time" }, + "status": { "type": "string" }, + "complete": { "type": "boolean" } + } + }, + "User": { + "type": "object", + "properties": { + "id": { "type": "integer", "format": "int64" }, + "username": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "email": { "type": "string" }, + "password": { "type": "string" }, + "phone": { "type": "string" }, + "userStatus": { "type": "integer", "format": "int32" } + } + } + } + } +} diff --git a/docs/developer-guide/appendix_goal_generate_graphql.adoc b/docs/developer-guide/appendix_goal_generate_graphql.adoc index e4d1f4f7eaf..02873b28f8b 100644 --- a/docs/developer-guide/appendix_goal_generate_graphql.adoc +++ b/docs/developer-guide/appendix_goal_generate_graphql.adoc @@ -113,14 +113,34 @@ their `name()`. Built-in scalars map to their boxed Java type The `@GraphQLClient` interface looks like: +[source,java] +---- +include::../demos/common/src/main/java/com/example/starwars/StarWarsApi.java[tag=appendix-goal-generate-graphql-java-001,indent=0] +---- + Call sites use the static factory. Queries and mutations report through an `OnComplete>`: +[source,java] +---- +include::../demos/common/src/main/java/com/example/starwars/StarWarsCallSite.java[tag=appendix-goal-generate-graphql-java-002,indent=0] +---- + +NOTE: The call sites here are written against the Java 17 output, where the +response types are records. On a Java 8 target the generator emits classes +with public fields instead, so `response.getData().hero().name()` becomes +`response.getData().hero.name`. + A subscription returns a `GraphQLSubscription` handle whose `cancel()` ends the stream: +[source,java] +---- +include::../demos/common/src/main/java/com/example/starwars/StarWarsCallSite.java[tag=appendix-goal-generate-graphql-java-003,indent=0] +---- + The `Impl` class that performs the request lives in `target/generated-sources` -- the project source never references it diff --git a/docs/developer-guide/appendix_goal_generate_grpc.adoc b/docs/developer-guide/appendix_goal_generate_grpc.adoc index 0c42eeb74bc..1b8c3c12f4e 100644 --- a/docs/developer-guide/appendix_goal_generate_grpc.adoc +++ b/docs/developer-guide/appendix_goal_generate_grpc.adoc @@ -74,9 +74,24 @@ optional `name` attribute so introspection tooling can recover it. The `@GrpcClient` interface looks like: +[source,java] +---- +include::../demos/common/src/main/java/com/example/hello/GreeterGrpc.java[tag=appendix-goal-generate-grpc-java-001,indent=0] +---- + Call sites use the static factory: +[source,java] +---- +include::../demos/common/src/main/java/com/example/hello/GreeterCallSite.java[tag=appendix-goal-generate-grpc-java-002,indent=0] +---- + +NOTE: The call site above is written against the Java 17 output, where the +messages are records. On a Java 8 target the generator emits classes with a +public no-arg constructor and public fields instead, so construction becomes +`new HelloRequest(); r.name = ...` and a read is `reply.message` rather than `reply.message()`. + The `GrpcImpl` class that actually performs the gRPC-Web POST lives in `target/generated-sources` -- the project source diff --git a/docs/developer-guide/appendix_goal_generate_openapi.adoc b/docs/developer-guide/appendix_goal_generate_openapi.adoc index 174a44d87a7..8e6354cea3c 100644 --- a/docs/developer-guide/appendix_goal_generate_openapi.adoc +++ b/docs/developer-guide/appendix_goal_generate_openapi.adoc @@ -48,25 +48,39 @@ files (only missing files are written). ==== Generated output -For the Swagger Petstore reference spec the goal emits, under +The listings in this section are the goal's own output, generated from a +Swagger Petstore specification cut down to the `pet`, `store` and `user` +tags. That spec is in the repository at +`docs/demos/common/src/main/snippets/developer-guide/appendix-goal-generate-openapi-petstore.json`, +so you can run the goal against it and compare. The committed copies carry a +license header and the `tag::` markers this guide includes them by; strip +those two additions and the rest is exactly what the goal wrote. + +One `@RestClient` interface per tag and one model per schema land under `common/src/main/java`: [listing] ---- com/example/petstore/ PetApi.java // @RestClient interface, methods addPet, updatePet, - // findPetsByStatus, getPetById, deletePet, ... - StoreApi.java // @RestClient interface, methods getInventory, - // placeOrder, getOrderById, deleteOrder - UserApi.java // @RestClient interface + // findPetsByStatus, getPetById, deletePet + StoreApi.java // @RestClient interface, methods placeOrder, + // getOrderById, deleteOrder + UserApi.java // @RestClient interface, methods createUser, + // getUserByName com/example/petstore/model/ Pet.java // @Mapped record (Java 17+) or class (Java 8) Order.java User.java Category.java - Tag.java ---- +`Tag.java` is missing from that list on purpose. The Petstore declares +`Tag` and `Category` with the same two properties, and identical shapes +collapse to one record, so `Pet.tags()` comes back typed as a list of +`Category`. Give the two schemas different shapes if you want them to +stay separate classes. + Each `@RestClient` interface method is annotated with the HTTP verb and path; parameters are annotated `@Path` / `@Query` / `@Header` / `@Body` so the processor knows how to assemble the `Rest` call. The @@ -91,6 +105,15 @@ collisions between an API class name and a same-named model. Call sites use the static factory: +[source,java] +---- +include::../demos/common/src/main/java/com/example/petstore/PetApiCallSite.java[tag=appendix-goal-generate-openapi-java-003,indent=0] +---- + +NOTE: The call site here is written against the Java 17 output, where `Pet` +is a record. On a Java 8 target the generator emits a class with public +fields instead, so `pet.name()` becomes `pet.name`. + The `ApiImpl` class that actually performs the HTTP call lives in `target/generated-sources` -- the project source never references diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/GenerateOpenApiMojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/GenerateOpenApiMojo.java index 9c4b47ef670..2f21bbbc7cc 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/GenerateOpenApiMojo.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/GenerateOpenApiMojo.java @@ -379,6 +379,9 @@ private SchemaInfo buildSchemaInfo(String name, Map schema) { /// emitted record/class. We keep the first-encountered name and alias /// the duplicates to it. private void unifyShapes() { + // Java type name of a schema that gets unified away -> the name of + // the schema it collapsed into. + Map renamed = new LinkedHashMap(); for (Map.Entry e : schemaByName.entrySet()) { SchemaInfo info = e.getValue(); String shape = shapeOf(info); @@ -388,10 +391,57 @@ private void unifyShapes() { nameAliases.put(info.specName, info.javaName); } else { info.isCanonical = false; + if (!info.javaName.equals(prior.javaName)) { + renamed.put(info.javaName, prior.javaName); + } info.javaName = prior.javaName; nameAliases.put(info.specName, prior.javaName); } } + if (renamed.isEmpty()) { + return; + } + // Property types were resolved in pass 2, before any of this was + // known, so a property pointing at a schema that has just been + // unified away still names a class nothing emits. Left alone that + // is a generated model which does not compile -- the Swagger + // Petstore hits it, where Tag and Category have the same shape and + // Pet references both. + for (SchemaInfo info : schemaByName.values()) { + for (PropInfo p : info.props) { + p.javaType = retypeModelReferences(p.javaType, renamed); + } + } + } + + /// Rewrites every `.` occurrence in a resolved + /// Java type to the canonical name it was unified into. The match has + /// to end on a non-identifier character so `model.Tag` inside + /// `model.TagSummary` is left alone. + private String retypeModelReferences(String javaType, Map renamed) { + if (javaType == null) { + return null; + } + String out = javaType; + for (Map.Entry e : renamed.entrySet()) { + String stale = modelPackage + "." + e.getKey(); + String canonical = modelPackage + "." + e.getValue(); + int from = 0; + for (;;) { + int at = out.indexOf(stale, from); + if (at < 0) { + break; + } + int after = at + stale.length(); + if (after < out.length() && Character.isJavaIdentifierPart(out.charAt(after))) { + from = after; + continue; + } + out = out.substring(0, at) + canonical + out.substring(after); + from = at + canonical.length(); + } + } + return out; } private static String shapeOf(SchemaInfo s) { diff --git a/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/GenerateOpenApiMojoTest.java b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/GenerateOpenApiMojoTest.java index 9213073b6f3..1ac5b4d3ce4 100644 --- a/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/GenerateOpenApiMojoTest.java +++ b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/GenerateOpenApiMojoTest.java @@ -1,5 +1,24 @@ /* * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. */ package com.codename1.maven; @@ -197,6 +216,42 @@ void respectsOverwriteFalseAndPreservesUserEdits(@TempDir Path tmp) throws Excep "overwrite=false should preserve user edits; was:\n" + apiSrc); } + /// The Swagger Petstore case: Tag and Category have the same shape, so one + /// is unified away, and Pet references both. Property types are resolved + /// before unification runs, so the surviving reference used to name the + /// dropped class and the emitted model did not compile. + @Test + void unifiedAwaySchemaIsNotLeftDanglingInAReference(@TempDir Path tmp) throws Exception { + String spec = + "{\"openapi\":\"3.0.0\",\"info\":{\"title\":\"t\",\"version\":\"1\"}," + + "\"paths\":{\"/pet\":{\"get\":{\"tags\":[\"Pet\"],\"operationId\":\"getPet\"," + + " \"responses\":{\"200\":{\"description\":\"ok\",\"content\":{\"application/json\":" + + " {\"schema\":{\"$ref\":\"#/components/schemas/Pet\"}}}}}}}}," + + "\"components\":{\"schemas\":{" + + " \"Category\":{\"type\":\"object\",\"properties\":{" + + " \"id\":{\"type\":\"integer\",\"format\":\"int64\"},\"name\":{\"type\":\"string\"}}}," + + " \"Tag\":{\"type\":\"object\",\"properties\":{" + + " \"id\":{\"type\":\"integer\",\"format\":\"int64\"},\"name\":{\"type\":\"string\"}}}," + + " \"Pet\":{\"type\":\"object\",\"properties\":{" + + " \"category\":{\"$ref\":\"#/components/schemas/Category\"}," + + " \"tags\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/components/schemas/Tag\"}}}}" + + "}}}"; + File out = tmp.toFile(); + new GenerateOpenApiMojo.Generator(parse(spec), "com.example.petstore", out, + true, /*emitRecords*/ true, new SystemStreamLog()).run(); + + File tag = new File(out, "com/example/petstore/model/Tag.java"); + File category = new File(out, "com/example/petstore/model/Category.java"); + assertTrue(category.exists(), "Category is the canonical shape and must be emitted"); + assertFalse(tag.exists(), "Tag is structurally identical and should unify away"); + + String petSrc = readString(new File(out, "com/example/petstore/model/Pet.java")); + assertFalse(petSrc.contains("model.Tag"), + "Pet must not reference the class that was unified away; was:\n" + petSrc); + assertTrue(petSrc.contains("java.util.List tags"), + "the tags property should retype to the surviving class; was:\n" + petSrc); + } + @Test void parseJavaVersionHandlesShapes() { org.junit.jupiter.api.Assertions.assertEquals(8, GenerateOpenApiMojo.parseJavaVersion("1.8")); diff --git a/scripts/developer-guide/missing-code-blocks-baseline.txt b/scripts/developer-guide/missing-code-blocks-baseline.txt index 2d64765057a..9f552230ed0 100644 --- a/scripts/developer-guide/missing-code-blocks-baseline.txt +++ b/scripts/developer-guide/missing-code-blocks-baseline.txt @@ -20,12 +20,6 @@ Monetization.asciidoc You are now ready to see the full magic of the `validateAn SVG-Transcoder.asciidoc the generated class directly: The-Components-Of-Codename-One.asciidoc Call the builder from a Maven plugin, an Ant task or a one-shot `main`: The-Components-Of-Codename-One.asciidoc This code should output "The result was 7" to the console. It's fully asynchronous, so you can include this code anywhere without worrying about it "bogging down" your code. The full signature of this form of the https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html#execute(java.lang.String,com.codename1.util.SuccessCallback)[execute()] method is: -appendix_goal_generate_graphql.adoc The `@GraphQLClient` interface looks like: -appendix_goal_generate_graphql.adoc an `OnComplete>`: -appendix_goal_generate_graphql.adoc ends the stream: -appendix_goal_generate_grpc.adoc Call sites use the static factory: -appendix_goal_generate_grpc.adoc The `@GrpcClient` interface looks like: -appendix_goal_generate_openapi.adoc Call sites use the static factory: io.asciidoc In the above code you do the following: io.asciidoc Since you assume most developers reading this will be familiar with Java here is the way to implement the multipart upload in the servlet API: io.asciidoc That's what the new method of `URLImage` does: