diff --git a/.github/workflows/samples-java-dubbo.yaml b/.github/workflows/samples-java-dubbo.yaml new file mode 100644 index 000000000000..5623adf01e4d --- /dev/null +++ b/.github/workflows/samples-java-dubbo.yaml @@ -0,0 +1,37 @@ +name: Samples Java Dubbo + +on: + push: + paths: + - 'samples/server/petstore/java-dubbo/**' + pull_request: + paths: + - 'samples/server/petstore/java-dubbo/**' + +jobs: + build: + name: Build Java Dubbo + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sample: + # servers + - samples/server/petstore/java-dubbo + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: 17 + - name: Cache maven dependencies + uses: actions/cache@v4 + env: + cache-name: maven-repository + with: + path: | + ~/.m2 + key: ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}-${{ hashFiles('**/pom.xml') }} + - name: Build + working-directory: ${{ matrix.sample }} + run: mvn clean package --no-transfer-progress diff --git a/bin/configs/java-dubbo-server.yaml b/bin/configs/java-dubbo-server.yaml new file mode 100644 index 000000000000..fd57997b19df --- /dev/null +++ b/bin/configs/java-dubbo-server.yaml @@ -0,0 +1,15 @@ +generatorName: dubbo +outputDir: samples/server/petstore/java-dubbo +inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml +templateDir: modules/openapi-generator/src/main/resources/java-dubbo +additionalProperties: + hideGenerationTimestamp: "true" + artifactId: openapi-dubbo-server-petstore + basePackage: "org.openapitools.example" + title: "OpenAPI Petstore" + serviceInterface: true + serviceImplementation: true + useTags: true + dubboVersion: "3.2.18" + javaVersion: "17" + registryAddress: "zookeeper://127.0.0.1:2181" diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DubboCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DubboCodegen.java new file mode 100644 index 000000000000..f8338376b6df --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DubboCodegen.java @@ -0,0 +1,887 @@ +/* + * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * Copyright 2018 SmartBear Software + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law of or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openapitools.codegen.languages; + +import com.samskivert.mustache.Mustache; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.Schema; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.openapitools.codegen.*; + +import org.openapitools.codegen.meta.features.*; +import org.openapitools.codegen.model.ModelMap; +import org.openapitools.codegen.model.ModelsMap; +import org.openapitools.codegen.model.OperationMap; +import org.openapitools.codegen.model.OperationsMap; +import org.openapitools.codegen.templating.mustache.TrimWhitespaceLambda; +import org.openapitools.codegen.utils.ModelUtils; +import org.openapitools.codegen.utils.ProcessUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.*; +import java.util.stream.Collectors; +import java.util.Objects; + +import static org.apache.commons.lang3.StringUtils.isNotEmpty; +import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; +import org.openapitools.codegen.utils.CamelizeOption; +import static org.openapitools.codegen.utils.StringUtils.camelize; +import org.openapitools.codegen.model.OperationsMap; +import org.openapitools.codegen.model.OperationMap; +import org.openapitools.codegen.model.ModelMap; + + +public class DubboCodegen extends AbstractJavaCodegen { + private final Logger LOGGER = LoggerFactory.getLogger(DubboCodegen.class); + + + public static final String TITLE = "title"; + public static final String CONFIG_PACKAGE = "configPackage"; + public static final String BASE_PACKAGE = "basePackage"; + public static final String INTERFACE_ONLY = "interfaceOnly"; + public static final String USE_TAGS = "useTags"; + public static final String DUBBO_VERSION = "dubboVersion"; + public static final String JAVA_VERSION = "javaVersion"; + public static final String SERVICE_INTERFACE = "serviceInterface"; + public static final String SERVICE_IMPLEMENTATION = "serviceImplementation"; + public static final String USE_GENERIC_RESPONSE = "useGenericResponse"; + public static final String REGISTRY_ADDRESS = "registry-address"; + + @Setter protected String title = null; + @Getter @Setter protected String configPackage = "org.openapitools.configuration"; + @Getter @Setter protected String basePackage = "org.openapitools"; + + @Setter protected boolean interfaceOnly = false; + @Setter protected boolean useTags = true; + @Setter protected String javaVersion = "17"; + @Setter protected String dubboVersion = "3.2.18"; + @Setter protected boolean serviceInterface = true; + @Setter protected boolean serviceImplementation = true; + @Setter protected boolean useGenericResponse = false; + @Setter protected String registryAddress = "zookeeper://127.0.0.1:2181"; + + public DubboCodegen() { + super(); + + modifyFeatureSet(features -> features + .includeDocumentationFeatures(DocumentationFeature.Readme) + .wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON, WireFormatFeature.XML, WireFormatFeature.Custom)) + .securityFeatures(EnumSet.of(SecurityFeature.OAuth2_Implicit, SecurityFeature.OAuth2_AuthorizationCode, + SecurityFeature.OAuth2_ClientCredentials, SecurityFeature.OAuth2_Password, + SecurityFeature.ApiKey, SecurityFeature.BasicAuth)) + .excludeGlobalFeatures(GlobalFeature.Callbacks, GlobalFeature.LinkObjects, GlobalFeature.ParameterStyling) + .includeSchemaSupportFeatures(SchemaSupportFeature.Polymorphism) + .excludeParameterFeatures(ParameterFeature.Cookie)); + + dateLibrary = "java8"; + + useBeanValidation = false; + serializableModel = true; + outputFolder = "generated-code/java-dubbo"; + embeddedTemplateDir = templateDir = "java-dubbo"; + invokerPackage = "org.openapitools"; + apiPackage = invokerPackage + ".api"; + modelPackage = invokerPackage + ".model"; + artifactId = "openapi-dubbo"; + + additionalProperties.put("hideGenerationTimestamp", true); + additionalProperties.put("withXml", false); + + importMapping.remove("ApiModel"); + importMapping.remove("ApiModelProperty"); + + setDocumentationProvider(DocumentationProvider.NONE); + setAnnotationLibrary(AnnotationLibrary.NONE); + + supportsInheritance = false; + supportsMixins = false; + + importMapping.remove("ApiModel"); + importMapping.remove("ApiModelProperty"); + importMapping.remove("Schema"); + importMapping.remove("io.swagger.annotations.ApiModel"); + importMapping.remove("io.swagger.annotations.ApiModelProperty"); + importMapping.remove("io.swagger.v3.oas.annotations.media.Schema"); + + typeMapping.clear(); + typeMapping.put("integer", "Integer"); + typeMapping.put("long", "Long"); + typeMapping.put("float", "Float"); + typeMapping.put("double", "Double"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("string", "String"); + typeMapping.put("array", "List"); + typeMapping.put("map", "Map"); + typeMapping.put("object", "Object"); + typeMapping.put("date", "LocalDate"); + typeMapping.put("DateTime", "OffsetDateTime"); + typeMapping.put("date-time", "OffsetDateTime"); + typeMapping.put("number", "BigDecimal"); + typeMapping.put("decimal", "BigDecimal"); + typeMapping.put("binary", "byte[]"); + typeMapping.put("file", "org.springframework.web.multipart.MultipartFile"); + typeMapping.put("uuid", "UUID"); + typeMapping.put("byte", "byte[]"); + typeMapping.put("ByteArray", "byte[]"); + typeMapping.put("binary", "byte[]"); + typeMapping.put("password", "String"); + + languageSpecificPrimitives.clear(); + languageSpecificPrimitives.add("String"); + languageSpecificPrimitives.add("boolean"); + languageSpecificPrimitives.add("Boolean"); + languageSpecificPrimitives.add("Double"); + languageSpecificPrimitives.add("Integer"); + languageSpecificPrimitives.add("Long"); + languageSpecificPrimitives.add("Float"); + languageSpecificPrimitives.add("Object"); + languageSpecificPrimitives.add("List"); + languageSpecificPrimitives.add("Map"); + languageSpecificPrimitives.add("Set"); + + importMapping.put("List", "java.util.List"); + importMapping.put("Map", "java.util.Map"); + importMapping.put("Set", "java.util.Set"); + importMapping.put("ArrayList", "java.util.ArrayList"); + importMapping.put("HashMap", "java.util.HashMap"); + importMapping.put("HashSet", "java.util.HashSet"); + importMapping.put("Date", "java.util.Date"); + importMapping.put("Arrays", "java.util.Arrays"); + importMapping.put("OffsetDateTime", "java.time.OffsetDateTime"); + importMapping.put("LocalDate", "java.time.LocalDate"); + importMapping.put("LocalTime", "java.time.LocalTime"); + importMapping.put("LocalDateTime", "java.time.LocalDateTime"); + importMapping.put("BigDecimal", "java.math.BigDecimal"); + importMapping.put("BigInteger", "java.math.BigInteger"); + importMapping.put("UUID", "java.util.UUID"); + importMapping.put("MultipartFile", "org.springframework.web.multipart.MultipartFile"); + + typeMapping.put("List", "List"); + typeMapping.put("Set", "Set"); + typeMapping.put("Map", "Map"); + + updateOption(CodegenConstants.INVOKER_PACKAGE, this.getInvokerPackage()); + updateOption(CodegenConstants.ARTIFACT_ID, this.getArtifactId()); + updateOption(CodegenConstants.API_PACKAGE, apiPackage); + updateOption(CodegenConstants.MODEL_PACKAGE, modelPackage); + + apiTestTemplateFiles.clear(); + + apiTemplateFiles.clear(); + apiTemplateFiles.put("api.mustache", ".java"); + apiTemplateFiles.put("apiDubbo.mustache", ".java"); + apiTemplateFiles.put("apiController.mustache", ".java"); + apiDocTemplateFiles.clear(); + + modelTemplateFiles.clear(); + modelTemplateFiles.put("model.mustache", ".java"); + modelDocTemplateFiles.clear(); + + additionalProperties.put("dubboVersion", dubboVersion); + additionalProperties.put("javaVersion", javaVersion); + + cliOptions.add(new CliOption(TITLE, "API title name").defaultValue(title)); + cliOptions.add(new CliOption(CONFIG_PACKAGE, "configuration package for generated code") + .defaultValue(this.getConfigPackage())); + cliOptions.add(new CliOption(BASE_PACKAGE, "base package (invokerPackage) for generated code") + .defaultValue(this.getBasePackage())); + cliOptions.add(CliOption.newBoolean(INTERFACE_ONLY, + "Whether to generate only API interface stubs without the server files.", interfaceOnly)); + cliOptions.add(CliOption.newBoolean(USE_TAGS, "use tags for creating interface and controller classnames", useTags)); + cliOptions.add(new CliOption(DUBBO_VERSION, "Dubbo version").defaultValue(dubboVersion)); + cliOptions.add(new CliOption(JAVA_VERSION, "Java version").defaultValue(javaVersion)); + cliOptions.add(CliOption.newBoolean(SERVICE_INTERFACE, "Generate service interface", serviceInterface)); + cliOptions.add(CliOption.newBoolean(SERVICE_IMPLEMENTATION, "Generate service implementation", serviceImplementation)); + cliOptions.add(CliOption.newBoolean(USE_GENERIC_RESPONSE, "Use generic response wrapper", useGenericResponse)); + cliOptions.add(new CliOption(REGISTRY_ADDRESS, "Registry address (e.g., zookeeper://127.0.0.1:2181 or nacos://127.0.0.1:8848)") + .defaultValue(registryAddress)); + + supportedLibraries.put(DEFAULT_LIBRARY, "Default Dubbo library"); + setLibrary(DEFAULT_LIBRARY); + + CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use"); + libraryOption.setEnum(supportedLibraries); + libraryOption.setDefault(DEFAULT_LIBRARY); + cliOptions.add(libraryOption); + setLibrary(DEFAULT_LIBRARY); + } + + @Override + public CodegenType getTag() { + return CodegenType.SERVER; + } + + @Override + public String getName() { + return "dubbo"; + } + + @Override + public String getHelp() { + return "Generates a Java Apache Dubbo server application."; + } + + private boolean isOutputFolderPointingToSourceDirectory() { + if (outputFolder == null) { + return false; + } + + String normalizedPath = outputFolder.replace('\\', '/'); + return normalizedPath.endsWith("/src/main/java") || normalizedPath.endsWith("src/main/java"); + } + + @Override + public String outputFolder() { + if (isOutputFolderPointingToSourceDirectory()) { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + + for (StackTraceElement element : stackTrace) { + String methodName = element.getMethodName(); + String className = element.getClassName(); + + if (className.equals("org.openapitools.codegen.DefaultGenerator")) { + if (methodName.equals("generateVersionMetadata") || + methodName.equals("generateFilesMetadata")) { + + return outputFolder + File.separator + ".." + File.separator + ".." + File.separator + ".."; + } + } + } + } + + return outputFolder; + } + + public String getIgnoreFileOutputPath() { + if (isOutputFolderPointingToSourceDirectory()) { + return outputFolder + File.separator + ".." + File.separator + ".." + File.separator + ".."; + } + return outputFolder; + } + + @Override + public void processOpts() { + final List> configOptions = + additionalProperties.entrySet().stream() + .filter(e -> !Arrays.asList("hideGenerationTimestamp").contains(e.getKey())) + .filter(e -> cliOptions.stream().map(CliOption::getOpt).anyMatch(opt -> opt.equals(e.getKey()))) + .map(e -> org.apache.commons.lang3.tuple.Pair.of(e.getKey(), e.getValue().toString())) + .collect(Collectors.toList()); + additionalProperties.put("configOptions", configOptions); + + super.processOpts(); + + supportingFiles.removeIf(sf -> sf.getDestinationFilename().equals(".openapi-generator-ignore")); + + openapiGeneratorIgnoreList = new HashSet<>(); + openapiGeneratorIgnoreList.add("# Dubbo generator explicitly disables .openapi-generator-ignore"); + + importMapping.remove("ApiModel"); + importMapping.remove("ApiModelProperty"); + importMapping.remove("io.swagger.annotations.ApiModel"); + importMapping.remove("io.swagger.annotations.ApiModelProperty"); + importMapping.remove("Schema"); + importMapping.remove("io.swagger.v3.oas.annotations.media.Schema"); + + String userTitle = (String) additionalProperties.get(TITLE); + boolean userProvidedTitle = userTitle != null && !userTitle.equals("OpenAPI Dubbo"); + + if (userProvidedTitle) { + this.title = userTitle; + } + + additionalProperties.put("userProvidedTitle", userProvidedTitle); + + additionalProperties.put("title", this.title); + + if (additionalProperties.containsKey(CONFIG_PACKAGE)) { + this.setConfigPackage((String) additionalProperties.get(CONFIG_PACKAGE)); + } + + if (additionalProperties.containsKey(BASE_PACKAGE)) { + String basePackageName = (String) additionalProperties.get(BASE_PACKAGE); + this.setBasePackage(basePackageName); + this.setInvokerPackage(basePackageName); + + this.apiPackage = basePackageName + ".api"; + this.modelPackage = basePackageName + ".model"; + + if (!additionalProperties.containsKey(CONFIG_PACKAGE)) { + this.configPackage = basePackageName + ".configuration"; + } + + updateOption(CodegenConstants.API_PACKAGE, this.apiPackage); + updateOption(CodegenConstants.MODEL_PACKAGE, this.modelPackage); + updateOption(CodegenConstants.INVOKER_PACKAGE, this.getInvokerPackage()); + } + + if (additionalProperties.containsKey(INTERFACE_ONLY)) { + this.interfaceOnly = Boolean.parseBoolean(additionalProperties.get(INTERFACE_ONLY).toString()); + } + + if (additionalProperties.containsKey(USE_TAGS)) { + this.useTags = Boolean.parseBoolean(additionalProperties.get(USE_TAGS).toString()); + } + + if (additionalProperties.containsKey(DUBBO_VERSION)) { + this.dubboVersion = (String) additionalProperties.get(DUBBO_VERSION); + } + + if (additionalProperties.containsKey(JAVA_VERSION)) { + this.javaVersion = (String) additionalProperties.get(JAVA_VERSION); + } + + if (additionalProperties.containsKey(SERVICE_INTERFACE)) { + this.serviceInterface = Boolean.parseBoolean(additionalProperties.get(SERVICE_INTERFACE).toString()); + } + + if (additionalProperties.containsKey(SERVICE_IMPLEMENTATION)) { + this.serviceImplementation = Boolean.parseBoolean(additionalProperties.get(SERVICE_IMPLEMENTATION).toString()); + } + + if (additionalProperties.containsKey(USE_GENERIC_RESPONSE)) { + this.useGenericResponse = Boolean.parseBoolean(additionalProperties.get(USE_GENERIC_RESPONSE).toString()); + } + + if (additionalProperties.containsKey(REGISTRY_ADDRESS)) { + this.registryAddress = (String) additionalProperties.get(REGISTRY_ADDRESS); + } + + additionalProperties.put("title", this.title); + additionalProperties.put("configPackage", this.configPackage); + additionalProperties.put("basePackage", this.basePackage); + additionalProperties.put("apiPackage", this.apiPackage); + additionalProperties.put("modelPackage", this.modelPackage); + additionalProperties.put("invokerPackage", this.getInvokerPackage()); + additionalProperties.put("interfaceOnly", interfaceOnly); + additionalProperties.put("useTags", useTags); + additionalProperties.put("dubboVersion", dubboVersion); + additionalProperties.put("javaVersion", javaVersion); + additionalProperties.put("serviceInterface", serviceInterface); + additionalProperties.put("serviceImplementation", serviceImplementation); + additionalProperties.put("useGenericResponse", useGenericResponse); + additionalProperties.put("registryAddress", registryAddress); + + supportingFiles.clear(); + + if (isOutputFolderPointingToSourceDirectory()) { + String rootPath = ".." + File.separator + ".." + File.separator + ".."; + supportingFiles.add(new SupportingFile("pom.mustache", rootPath, "pom.xml")); + supportingFiles.add(new SupportingFile("README.mustache", rootPath, "README.md")); + + } else { + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + } + + if (serviceImplementation && !interfaceOnly) { + String mainClassName; + boolean isUserTitle = (Boolean) additionalProperties.getOrDefault("userProvidedTitle", false); + + if (isUserTitle) { + String titleName = (String) additionalProperties.get(TITLE); + mainClassName = camelize(titleName.trim(), CamelizeOption.UPPERCASE_FIRST_CHAR) + "Application"; + } else { + mainClassName = "OpenApiGeneratorApplication"; + } + + String testClassName = mainClassName + "Tests"; + additionalProperties.put("mainClassName", mainClassName); + additionalProperties.put("testClassName", testClassName); + + if (isOutputFolderPointingToSourceDirectory()) { + supportingFiles.add(new SupportingFile("mainApplication.mustache", + basePackage.replace(".", File.separator), + mainClassName + ".java")); + + supportingFiles.add(new SupportingFile("applicationTest.mustache", + ".." + File.separator + ".." + File.separator + ".." + File.separator + "src" + File.separator + "test" + File.separator + "java" + File.separator + basePackage.replace(".", File.separator), + testClassName + ".java")); + + supportingFiles.add(new SupportingFile("application.mustache", + ".." + File.separator + ".." + File.separator + ".." + File.separator + "src" + File.separator + "main" + File.separator + "resources", + "application.yml")); + } else { + supportingFiles.add(new SupportingFile("mainApplication.mustache", + (sourceFolder + File.separator + basePackage).replace(".", File.separator), + mainClassName + ".java")); + + supportingFiles.add(new SupportingFile("applicationTest.mustache", + (testFolder + File.separator + basePackage).replace(".", File.separator), + testClassName + ".java")); + + supportingFiles.add(new SupportingFile("application.mustache", + "src/main/resources".replace("/", File.separator), + "application.yml")); + } + } + + additionalProperties.put("lambdaTrimWhitespace", new TrimWhitespaceLambda()); + + additionalProperties.put("documentationProvider", "none"); + additionalProperties.put("annotationLibrary", "none"); + additionalProperties.put("hideGenerationTimestamp", true); + additionalProperties.put("useBeanValidation", false); + additionalProperties.put("performBeanValidation", false); + + } + + private boolean isDubbo33OrHigher(String version) { + if (version == null || version.trim().isEmpty()) { + return false; + } + + try { + String cleanVersion = version.split("-")[0]; + String[] parts = cleanVersion.split("\\."); + if (parts.length >= 2) { + int major = Integer.parseInt(parts[0]); + int minor = Integer.parseInt(parts[1]); + + return major > 3 || (major == 3 && minor >= 3); + } + } catch (NumberFormatException e) { + LOGGER.warn("Unable to parse Dubbo version: " + version); + } + + return false; + } + + @Override + public Map postProcessSupportingFileData(Map objs) { + generateYAMLSpecFile(objs); + objs = super.postProcessSupportingFileData(objs); + + objs.put("interfacePackage", apiPackage + ".interfaces"); + objs.put("consumerPackage", apiPackage + ".consumer"); + objs.put("providerPackage", apiPackage + ".provider"); + + objs.put("registryAddress", registryAddress); + + boolean isDubbo33Plus = isDubbo33OrHigher(dubboVersion); + objs.put("isDubbo33Plus", isDubbo33Plus); + + boolean isZookeeperRegistry = registryAddress != null && registryAddress.startsWith("zookeeper://"); + boolean isNacosRegistry = registryAddress != null && registryAddress.startsWith("nacos://"); + objs.put("isZookeeperRegistry", isZookeeperRegistry); + objs.put("isNacosRegistry", isNacosRegistry); + + String nacosClientVersion = isDubbo33Plus ? "2.5.0" : "2.2.4"; + objs.put("nacosClientVersion", nacosClientVersion); + + return objs; + } + + + + @Override + public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List allModels) { + OperationsMap results = super.postProcessOperationsWithModels(objs, allModels); + + if (results.getImports() != null) { + boolean hasJavaUtilImports = false; + Iterator> importIterator = results.getImports().iterator(); + while (importIterator.hasNext()) { + Map importMap = importIterator.next(); + String importName = importMap.get("import"); + if (importName != null && importName.startsWith("java.util.") && + !importName.equals("java.util.*") && + !importName.equals("java.util.UUID")) { + importIterator.remove(); + hasJavaUtilImports = true; + } + } + + if (hasJavaUtilImports) { + Map utilImport = new HashMap<>(); + utilImport.put("import", "java.util.*"); + utilImport.put("classname", "*"); + results.getImports().add(utilImport); + } + } + + OperationMap operations = results.getOperations(); + if (operations != null) { + String baseName = (String) operations.get("baseName"); + String originalClassName = (String) operations.get("classname"); + + if (baseName == null) { + baseName = originalClassName; + if (baseName != null && baseName.endsWith("Service")) { + baseName = baseName.substring(0, baseName.length() - 7).toLowerCase(java.util.Locale.ROOT); + } else if (baseName != null && baseName.endsWith("Api")) { + baseName = baseName.substring(0, baseName.length() - 3).toLowerCase(java.util.Locale.ROOT); + } + } + + if (baseName != null) { + if ("ashares".equals(baseName)) { + operations.put("baseName", "a"); + } else if ("usdata".equals(baseName)) { + operations.put("baseName", "us"); + } else if ("kline".equals(baseName)) { + operations.put("baseName", "kline"); + } + } + + if (originalClassName != null) { + String serviceName = originalClassName; + if (serviceName.endsWith("Api")) { + serviceName = serviceName.replace("Api", "Service"); + } else if (serviceName.endsWith("Service")) { + serviceName = originalClassName; + } + operations.put("serviceName", serviceName); + operations.put("serviceVarName", camelize(serviceName, LOWERCASE_FIRST_LETTER)); + + operations.put("servicePackage", apiPackage + ".interfaces"); + operations.put("serviceImport", apiPackage + ".interfaces." + serviceName); + operations.put("interfacePackage", apiPackage + ".interfaces"); + operations.put("consumerPackage", apiPackage + ".consumer"); + operations.put("providerPackage", apiPackage + ".provider"); + } + + List ops = operations.getOperation(); + for (CodegenOperation operation : ops) { + if (useGenericResponse) { + operation.vendorExtensions.put("x-generic-response", true); + } + } + } + + results.put("interfacePackage", apiPackage + ".interfaces"); + results.put("consumerPackage", apiPackage + ".consumer"); + results.put("providerPackage", apiPackage + ".provider"); + + return results; + } + + @Override + public String apiFileFolder() { + if (isOutputFolderPointingToSourceDirectory()) { + return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar); + } else { + return outputFolder + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator + apiPackage().replace('.', File.separatorChar); + } + } + + public String getFileFolderForTemplate(String templateName) { + String baseFolder; + if (isOutputFolderPointingToSourceDirectory()) { + baseFolder = outputFolder + File.separator + apiPackage().replace('.', File.separatorChar); + } else { + baseFolder = outputFolder + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator + apiPackage().replace('.', File.separatorChar); + } + + if ("api.mustache".equals(templateName)) { + return baseFolder + File.separator + "interfaces"; + } else if ("apiController.mustache".equals(templateName)) { + return baseFolder + File.separator + "consumer"; + } else if ("apiDubbo.mustache".equals(templateName)) { + return baseFolder + File.separator + "provider"; + } + + return baseFolder; + } + + public String getPackageForTemplate(String templateName) { + if ("api.mustache".equals(templateName)) { + return apiPackage() + ".interfaces"; + } else if ("apiController.mustache".equals(templateName)) { + return apiPackage() + ".consumer"; + } else if ("apiDubbo.mustache".equals(templateName)) { + return apiPackage() + ".provider"; + } + return apiPackage(); + } + + @Override + public String modelFileFolder() { + if (isOutputFolderPointingToSourceDirectory()) { + return outputFolder + File.separator + modelPackage().replace('.', File.separatorChar); + } else { + return outputFolder + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator + modelPackage().replace('.', File.separatorChar); + } + } + + + + @Override + public String apiFilename(String templateName, String tag) { + String suffix = apiTemplateFiles().get(templateName); + if (suffix == null) { + return null; + } + + String folder = getFileFolderForTemplate(templateName); + String filename; + + String apiName = toApiName(tag); + + if ("api.mustache".equals(templateName)) { + filename = apiName; + } else if ("apiDubbo.mustache".equals(templateName)) { + filename = apiName + "Impl"; + } else if ("apiController.mustache".equals(templateName)) { + filename = apiName + "Controller"; + } else { + filename = toApiFilename(tag); + } + + return folder + File.separator + filename + suffix; + } + + @Override + public String toApiName(String name) { + if (name.length() == 0) { + return "DefaultService"; + } + name = sanitizeName(name); + String apiName = camelize(name, CamelizeOption.UPPERCASE_FIRST_CHAR); + + if (!apiName.endsWith("Service")) { + apiName = apiName + "Service"; + } + + return apiName; + } + + @Override + public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations) { + if (useTags) { + String basePath = resourcePath; + if (basePath.startsWith("/")) { + basePath = basePath.substring(1); + } + int pos = basePath.indexOf("/"); + if (pos > 0) { + basePath = basePath.substring(0, pos); + } + + if (basePath.length() == 0) { + basePath = "default"; + } else { + String subPath = resourcePath; + if (subPath.startsWith("/" + basePath)) { + subPath = subPath.substring(("/" + basePath).length()); + } + if (subPath.isEmpty()) { + subPath = "/"; + } + co.vendorExtensions.put("x-sub-path", subPath); + co.subresourceOperation = !subPath.equals("/"); + + co.vendorExtensions.put("x-base-path", "/" + basePath); + + if ("a".equals(basePath)) { + basePath = "ashares"; + } else if ("us".equals(basePath)) { + basePath = "usdata"; + } + } + List opList = operations.computeIfAbsent(basePath, k -> new ArrayList<>()); + opList.add(co); + co.baseName = basePath; + } else { + super.addOperationToGroup(tag, resourcePath, operation, co, operations); + } + } + + @Override + public boolean isDataTypeString(String dataType) { + return "String".equals(dataType); + } + + @Override + public String getTypeDeclaration(Schema p) { + if (ModelUtils.isArraySchema(p)) { + Schema inner = ModelUtils.getSchemaItems(p); + String innerType = getTypeDeclaration(inner); + return "List<" + innerType + ">"; + } else if (ModelUtils.isMapSchema(p)) { + Schema inner = ModelUtils.getAdditionalProperties(p); + String innerType = getTypeDeclaration(inner); + return "Map"; + } + return super.getTypeDeclaration(p); + } + + @Override + public String getSchemaType(Schema p) { + String openAPIType = super.getSchemaType(p); + if (typeMapping.containsKey(openAPIType)) { + return typeMapping.get(openAPIType); + } + return openAPIType; + } + + + + @Override + public Set defaultIncludes() { + return new HashSet( + Arrays.asList( + "double", + "int", + "long", + "short", + "char", + "float", + "String", + "boolean", + "Boolean", + "Double", + "Void", + "Integer", + "Long", + "Float") + ); + } + + @Override + public String toModelImport(String name) { + if ("ApiModel".equals(name) || "ApiModelProperty".equals(name)) { + return null; + } + if ("".equals(modelPackage())) { + return name; + } else { + return modelPackage() + "." + name; + } + } + + @Override + public String getTypeDeclaration(String name) { + if ("ApiModel".equals(name) || "ApiModelProperty".equals(name)) { + return null; + } + return super.getTypeDeclaration(name); + } + + @Override + public boolean needToImport(String type) { + if ("ApiModel".equals(type) || + "ApiModelProperty".equals(type) || + "io.swagger.annotations.ApiModel".equals(type) || + "io.swagger.annotations.ApiModelProperty".equals(type) || + "Schema".equals(type) || + "io.swagger.v3.oas.annotations.media.Schema".equals(type)) { + return false; + } + + if ("LocalDate".equals(type) || + "LocalDateTime".equals(type) || + "LocalTime".equals(type) || + "OffsetDateTime".equals(type) || + "BigDecimal".equals(type) || + "BigInteger".equals(type) || + "UUID".equals(type)) { + return true; + } + + return super.needToImport(type); + } + + + + @Override + public ModelsMap postProcessModels(ModelsMap objs) { + objs = super.postProcessModels(objs); + + for (ModelMap modelMap : objs.getModels()) { + CodegenModel model = modelMap.getModel(); + model.imports.remove("ApiModel"); + model.imports.remove("ApiModelProperty"); + model.imports.remove("io.swagger.annotations.ApiModel"); + model.imports.remove("io.swagger.annotations.ApiModelProperty"); + model.imports.remove("Schema"); + model.imports.remove("io.swagger.v3.oas.annotations.media.Schema"); + + boolean hasJavaUtilImports = false; + Set javaUtilImports = new HashSet<>(); + Iterator iterator = model.imports.iterator(); + while (iterator.hasNext()) { + String importName = iterator.next(); + if (importName.startsWith("java.util.") && + !importName.equals("java.util.*") && + !importName.equals("java.util.UUID")) { + javaUtilImports.add(importName); + iterator.remove(); + hasJavaUtilImports = true; + } + } + + if (hasJavaUtilImports) { + model.imports.add("java.util.*"); + } + + for (CodegenProperty var : model.vars) { + if (var.allowableValues != null && var.allowableValues.get("imports") != null) { + ((Set) var.allowableValues.get("imports")).remove("ApiModel"); + ((Set) var.allowableValues.get("imports")).remove("ApiModelProperty"); + ((Set) var.allowableValues.get("imports")).remove("io.swagger.annotations.ApiModel"); + ((Set) var.allowableValues.get("imports")).remove("io.swagger.annotations.ApiModelProperty"); + } + } + } + + if (objs.getImports() != null) { + objs.getImports().removeIf(importMap -> { + String className = importMap.get("classname"); + return "ApiModel".equals(className) || "ApiModelProperty".equals(className); + }); + + boolean hasJavaUtilImports = false; + Iterator> importIterator = objs.getImports().iterator(); + while (importIterator.hasNext()) { + Map importMap = importIterator.next(); + String importName = importMap.get("import"); + if (importName != null && importName.startsWith("java.util.") && + !importName.equals("java.util.*") && + !importName.equals("java.util.UUID")) { + importIterator.remove(); + hasJavaUtilImports = true; + } + } + + if (hasJavaUtilImports) { + Map utilImport = new HashMap<>(); + utilImport.put("import", "java.util.*"); + utilImport.put("classname", "*"); + objs.getImports().add(utilImport); + } + } + + return objs; + } + + @Override + public String toModelDocFilename(String name) { + return null; + } + + @Override + public String toApiDocFilename(String name) { + return null; + } +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index fe481e526af1..9f7857ceeb78 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -27,6 +27,7 @@ org.openapitools.codegen.languages.CSharpClientCodegen org.openapitools.codegen.languages.CSharpFunctionsServerCodegen org.openapitools.codegen.languages.DartClientCodegen org.openapitools.codegen.languages.DartDioClientCodegen +org.openapitools.codegen.languages.DubboCodegen org.openapitools.codegen.languages.EiffelClientCodegen org.openapitools.codegen.languages.ElixirClientCodegen org.openapitools.codegen.languages.ElmClientCodegen diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/README.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/README.mustache new file mode 100644 index 000000000000..9a13b1c185a1 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/README.mustache @@ -0,0 +1,347 @@ +# {{appName}} + +{{appDescription}} + +This is a microservice project based on Apache Dubbo, generated by [OpenAPI Generator](https://openapi-generator.tech). + +- API version: {{appVersion}} +- Package version: {{packageVersion}} +{{^hideGenerationTimestamp}} +- Generator version: {{generatorVersion}} +- Build date: {{generatedDate}} +{{/hideGenerationTimestamp}} +- Generator: {{generatorClass}} +{{#externalDocumentationDescription}} +For more information, please visit: [{{{externalDocumentationDescription}}}]({{{externalDocumentationURL}}}) +{{/externalDocumentationDescription}} + +## Technology Stack + +- **Framework**: Apache Dubbo {{dubboVersion}} +{{#useSpringBoot}} +- **Spring Boot**: {{#useSpringBoot3}}3.x{{/useSpringBoot3}}{{^useSpringBoot3}}2.x{{/useSpringBoot3}} +{{/useSpringBoot}} +- **Java**: {{#java8}}8+{{/java8}}{{^java8}}11+{{/java8}} +- **Build Tool**: Maven 3.6+ +- **Registry**: {{registryAddress}} +- **Serialization**: Jackson JSON + +## System Requirements + +Building and running this project requires: +1. Java {{#java8}}8{{/java8}}{{^java8}}11{{/java8}}+ +2. Maven 3.6+ +3. Registry Center (Nacos or Zookeeper) + +## Quick Start + +### 1. Clone and Build Project + +```bash +git clone +cd {{artifactId}} +mvn clean compile +``` + +### 2. Configure Registry Center + +#### Using Nacos (Recommended) +```bash +# Download and start Nacos +wget https://github.com/alibaba/nacos/releases/download/2.2.4/nacos-server-2.2.4.tar.gz +tar -xzf nacos-server-2.2.4.tar.gz +cd nacos/bin +# Linux/Mac +./startup.sh -m standalone +# Windows +startup.cmd -m standalone +``` + +#### Using Zookeeper (Alternative) +```bash +# Download and start Zookeeper +wget https://downloads.apache.org/zookeeper/zookeeper-3.8.2/apache-zookeeper-3.8.2-bin.tar.gz +tar -xzf apache-zookeeper-3.8.2-bin.tar.gz +cd apache-zookeeper-3.8.2-bin +cp conf/zoo_sample.cfg conf/zoo.cfg +bin/zkServer.sh start +``` + +### 3. Configure Application + +Edit the `src/main/resources/application.yml` file: + +```yaml +# Dubbo Configuration +dubbo: + application: + name: {{artifactId}} + registry: + # Using Nacos + address: nacos://127.0.0.1:8848 + # Or using Zookeeper + # address: zookeeper://127.0.0.1:2181 + protocol: + name: dubbo + port: 20880 + provider: + timeout: 10000 + +{{#useSpringBoot}} +# Spring Boot Configuration +server: + port: 8080 + +spring: + application: + name: {{artifactId}} + +# Logging Configuration +logging: + level: + com.alibaba.nacos: WARN + org.apache.dubbo: INFO + root: INFO +{{/useSpringBoot}} +``` + +### 4. Start Application + +{{#useSpringBoot}} +```bash +# Using Spring Boot Maven plugin +mvn spring-boot:run + +# Or build JAR and run +mvn clean package +java -jar target/{{artifactId}}-{{appVersion}}.jar +``` +{{/useSpringBoot}} +{{^useSpringBoot}} +```bash +# Build project +mvn clean compile + +# Run main class +mvn exec:java -Dexec.mainClass="{{package}}.Application" +``` +{{/useSpringBoot}} + +## Project Structure + +``` +{{artifactId}}/ +├── src/main/java/{{package}}/ +{{#operations}} +│ ├── api/ +│ │ ├── {{classname}}.java # Service Interface +│ │ └── {{classname}}DubboImpl.java # Dubbo Service Implementation +{{/operations}} +{{#hasModel}} +│ ├── model/ # Data Models +{{#models}} +{{#model}} +│ │ └── {{classname}}.java +{{/model}} +{{/models}} +{{/hasModel}} +│ └── Application.java # Main Application Class +├── src/main/resources/ +│ └── application.yml # Application Configuration +├── pom.xml # Maven Configuration +└── README.md # Project Documentation +``` + +## API Interfaces + +{{#apiDocumentationUrl}} +For complete API documentation, please visit: [{{apiDocumentationUrl}}]({{apiDocumentationUrl}}) +{{/apiDocumentationUrl}} + +### Service Interfaces + +{{#operations}} +#### {{classname}} +{{#operation}} +- **{{nickname}}**: {{summary}} + {{#notes}} + - Description: {{.}} + {{/notes}} +{{/operation}} + +{{/operations}} + +## Development Guide + +### Implement Business Logic + +1. Implement specific business logic in the generated `*DubboImpl.java` classes +2. Inject necessary business service dependencies +3. Handle exceptions and error scenarios + +### Custom Configuration + +1. **Timeout Configuration**: Adjust `dubbo.provider.timeout` in `application.yml` +2. **Thread Pool Configuration**: Configure `dubbo.provider.threads` and other parameters +3. **Serialization Configuration**: Choose appropriate serialization method + +### Monitoring and Operations + +1. **Health Checks**: Dubbo provides built-in health check endpoints +2. **Metrics Monitoring**: Integrate with Prometheus or other monitoring systems +3. **Log Management**: Configure appropriate log levels and output formats + +## Testing + +```bash +# Run unit tests +mvn test + +# Run integration tests +mvn integration-test +``` + +## Deployment + +### Development Environment +```bash +mvn spring-boot:run +``` + +### Production Environment +```bash +# Build production package +mvn clean package -Pprod + +# Deploy using Docker +docker build -t {{artifactId}}:{{appVersion}} . +docker run -p 8080:8080 -p 20880:20880 {{artifactId}}:{{appVersion}} +``` + +## Generator Configuration Options + +This project supports the following OpenAPI Generator configuration options: + +### Basic Configuration +- `title`: API service title name (Default: "OpenAPI Dubbo") +- `basePackage`: Base package name (Default: "org.openapitools") +- `configPackage`: Configuration class package name (Default: "org.openapitools.configuration") +- `dubboVersion`: Dubbo version (Default: "3.2.0") + +### Generation Control +- `interfaceOnly`: Generate interfaces only, no implementation classes (Default: false) +- `serviceInterface`: Generate service interfaces (Default: true) +- `serviceImplementation`: Generate service implementations (Default: true) +- `async`: Use asynchronous methods (Default: false) +- `useTags`: Use tags to create class names (Default: true) +- `useGenericResponse`: Use generic response wrapper (Default: false) + +### Registry Configuration +- `registry-address`: Registry address, supports full address format (Default: "zookeeper://127.0.0.1:2181") + - Zookeeper example: `zookeeper://127.0.0.1:2181` + - Nacos example: `nacos://127.0.0.1:8848` + +#### 📋 Automatic Dependency Adaptation by Version +The generator automatically selects the correct dependencies based on Dubbo version: + +**Dubbo 3.2 and earlier versions**: +- Zookeeper: `dubbo-dependencies-zookeeper` (Aggregation POM) +- Nacos: `dubbo-registry-nacos` + `nacos-client:2.2.4` + +**Dubbo 3.3+ versions**: +- Zookeeper: `dubbo-registry-zookeeper` + `dubbo-remoting-zookeeper-curator5` +- Nacos: `dubbo-registry-nacos` + `nacos-client:2.5.0` + +### Date-Time Library Configuration +- `dateLibrary`: Date-time library selection (Default: "java8") + - `java8`: Java 8 native JSR310 (Recommended, for JDK 1.8+) + - `java8-localdatetime`: Java 8 using LocalDateTime (For legacy applications only) + - `joda`: Joda time library (For legacy applications only) + - `legacy`: Traditional java.util.Date + +### Usage Examples + +#### 🔧 Dubbo 3.2 Version Example +```bash +# Using Zookeeper (3.2 version automatically uses dubbo-dependencies-zookeeper) +java -jar openapi-generator-cli.jar generate \ +-i /Users/redoom/IdeaProjects/openapi.yaml \ +-g dubbo \ +-o /Users/redoom/IdeaProjects/openapi-test \ +--additional-properties=registry-address=zookeeper://127.0.0.1:2181 \ +--additional-properties=dubboVersion=3.2.0 \ +--additional-properties=dateLibrary=java8 + +# Using Nacos (3.2 version uses nacos-client:2.2.4) +java -jar openapi-generator-cli.jar generate \ +-i /Users/redoom/IdeaProjects/openapi.yaml \ +-g dubbo \ +-o /Users/redoom/IdeaProjects/openapi-test \ +--additional-properties=registry-address=nacos://127.0.0.1:8848 \ +--additional-properties=dubboVersion=3.2.0 \ +--additional-properties=dateLibrary=java8 +``` + +#### 🚀 Dubbo 3.3+ Version Example +```bash +# Using Zookeeper (3.3+ version automatically uses new modular dependencies) +java -jar openapi-generator-cli.jar generate \ +-i /Users/redoom/IdeaProjects/openapi.yaml \ +-g dubbo \ +-o /Users/redoom/IdeaProjects/openapi-test \ +--additional-properties=registry-address=zookeeper://127.0.0.1:2181 \ +--additional-properties=dubboVersion=3.3.0 \ +--additional-properties=dateLibrary=java8 + +# Using Nacos (3.3+ version uses nacos-client:2.5.0) +java -jar openapi-generator-cli.jar generate \ +-i /Users/redoom/IdeaProjects/openapi.yaml \ +-g dubbo \ +-o /Users/redoom/IdeaProjects/openapi-test \ +--additional-properties=registry-address=nacos://127.0.0.1:8848 \ +--additional-properties=dubboVersion=3.3.0 \ +--additional-properties=dateLibrary=java8 +``` + +## Troubleshooting + +### Common Issues + +1. **Registry Connection Failed** + - Check if the registry center is started + - Verify network connection and port configuration + +2. **Service Call Timeout** + - Adjust `dubbo.provider.timeout` settings + - Check network latency and service performance + +3. **Serialization Exception** + - Ensure all model classes implement `Serializable` interface + - Check Jackson configuration + +### Debug Logging + +Enable debug mode to see detailed logs: + +```yaml +logging: + level: + org.apache.dubbo: DEBUG + {{package}}: DEBUG +``` + +## License + +This project is licensed under the [Apache License 2.0](LICENSE). + +## Contributing + +Issues and Pull Requests are welcome! + +## Contact + +{{#apiDocumentationUrl}}{{infoEmail}}{{/apiDocumentationUrl}} + +--- + +> This project is automatically generated by OpenAPI Generator, based on Apache Dubbo microservice architecture. diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/api.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/api.mustache new file mode 100644 index 000000000000..e5c25ec9e80e --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/api.mustache @@ -0,0 +1,45 @@ +package {{interfacePackage}}; + +{{#imports}}import {{import}}; +{{/imports}} +{{#hasModel}} +import {{modelPackage}}.*; +{{/hasModel}} +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +{{#async}} +import java.util.concurrent.CompletableFuture; +{{/async}} +import javax.annotation.Generated; + + +{{>generatedAnnotation}} +{{#operations}} +public interface {{serviceName}} { +{{#operation}} + + /** + * {{summary}} + * {{notes}} + * +{{#allParams}} + * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}} +{{/allParams}} + * @return {{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}void{{/returnType}} + */ +{{#async}} + CompletableFuture<{{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{nickname}}( +{{/async}} +{{^async}} + {{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{nickname}}( +{{/async}} +{{#allParams}} + {{{dataType}}} {{paramName}}{{^-last}},{{/-last}} +{{/allParams}} + ); +{{/operation}} +} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/apiController.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/apiController.mustache new file mode 100644 index 000000000000..6a7bdf751aea --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/apiController.mustache @@ -0,0 +1,57 @@ +package {{consumerPackage}}; + +{{#imports}}import {{import}}; +{{/imports}} +{{#hasModel}} +import {{modelPackage}}.*; +{{/hasModel}} +{{#operations}} +import {{interfacePackage}}.{{serviceName}}; +{{/operations}} +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import org.apache.dubbo.config.annotation.DubboReference; +import org.springframework.web.bind.annotation.*; +{{#async}} +import java.util.concurrent.CompletableFuture; +{{/async}} +import javax.annotation.Generated; + + +{{>generatedAnnotation}} +{{#operations}} +@RestController +@RequestMapping("/{{baseName}}") +public class {{classname}}Controller { + + @DubboReference + private {{serviceName}} {{serviceVarName}}; + +{{#operation}} + @RequestMapping(method = RequestMethod.{{httpMethod}}, value = "{{#vendorExtensions.x-sub-path}}{{{vendorExtensions.x-sub-path}}}{{/vendorExtensions.x-sub-path}}{{^vendorExtensions.x-sub-path}}/{{/vendorExtensions.x-sub-path}}") +{{#async}} + public CompletableFuture<{{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{nickname}}( +{{/async}} +{{^async}} + public {{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{nickname}}( +{{/async}} +{{#allParams}} + @RequestParam(name = "{{paramName}}"{{#defaultValue}}, defaultValue = "{{.}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{^-last}},{{/-last}} +{{/allParams}} + ) { +{{#async}} + return {{serviceVarName}}.{{nickname}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); +{{/async}} +{{^async}} + {{#returnType}}return {{/returnType}}{{serviceVarName}}.{{nickname}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); +{{/async}} + } +{{^-last}} + +{{/-last}} +{{/operation}} +} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/apiDubbo.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/apiDubbo.mustache new file mode 100644 index 000000000000..f826310854c6 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/apiDubbo.mustache @@ -0,0 +1,71 @@ +package {{providerPackage}}; + +{{#imports}}import {{import}}; +{{/imports}} +{{#hasModel}} +import {{modelPackage}}.*; +{{/hasModel}} +{{#operations}} +import {{interfacePackage}}.{{serviceName}}; +{{/operations}} +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import org.apache.dubbo.config.annotation.DubboService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +{{#async}} +import java.util.concurrent.CompletableFuture; +{{/async}} +import javax.annotation.Generated; + + +{{>generatedAnnotation}} +{{#operations}} +@DubboService +public class {{serviceName}}Impl implements {{serviceName}} { + + private static final Logger logger = LoggerFactory.getLogger({{serviceName}}Impl.class); + +{{#operation}} + @Override +{{#async}} + public CompletableFuture<{{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{nickname}}( +{{/async}} +{{^async}} + public {{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{nickname}}( +{{/async}} +{{#allParams}} + {{{dataType}}} {{paramName}}{{^-last}},{{/-last}} +{{/allParams}} + ) { + logger.info("Dubbo service method {{nickname}} called with parameters: {{#allParams}}{{paramName}}={}{{^-last}}, {{/-last}}{{/allParams}}"{{#allParams}}, {{paramName}}{{/allParams}}); + +{{#async}} + return CompletableFuture.supplyAsync(() -> { + // TODO: Implement your business logic here +{{#returnType}} + // Replace this with actual implementation + return {{>returnValueExample}}; +{{/returnType}} +{{^returnType}} + return null; +{{/returnType}} + }); +{{/async}} +{{^async}} + // TODO: Implement your business logic here +{{#returnType}} + // Replace this with actual implementation + return {{>returnValueExample}}; +{{/returnType}} +{{/async}} + } +{{^-last}} + +{{/-last}} +{{/operation}} +} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/application.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/application.mustache new file mode 100644 index 000000000000..17c5ff5c0316 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/application.mustache @@ -0,0 +1,20 @@ +spring: + application: + name: {{artifactId}}-provider + +dubbo: + application: + name: {{artifactId}} + logger: slf4j + registry: + address: {{registryAddress}} + # 协议配置 + protocol: + name: tri + port: -1 # auto-increment port + +logging: + level: + root: INFO + org.apache.dubbo: INFO + {{invokerPackage}}: DEBUG diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/applicationTest.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/applicationTest.mustache new file mode 100644 index 000000000000..49b3e1270601 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/applicationTest.mustache @@ -0,0 +1,13 @@ +package {{invokerPackage}}; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class {{testClassName}} { + + @Test + void contextLoads() { + } + +} diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/beanValidation.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/beanValidation.mustache new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/generatedAnnotation.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/generatedAnnotation.mustache new file mode 100644 index 000000000000..4fc54c11ac08 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/generatedAnnotation.mustache @@ -0,0 +1,6 @@ +@Generated(value = "{{generatorClass}}"{{^hideGenerationTimestamp}}, date = "{{generatedDate}}"{{/hideGenerationTimestamp}}, comments = "Generator version: {{generatorVersion}}") +{{^hideGenerationTimestamp}}/** + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */{{/hideGenerationTimestamp}} diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/mainApplication.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/mainApplication.mustache new file mode 100644 index 000000000000..d5ebe5af2f4b --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/mainApplication.mustache @@ -0,0 +1,15 @@ +package {{invokerPackage}}; + +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@EnableDubbo(scanBasePackages = "{{invokerPackage}}") +public class {{mainClassName}} { + + public static void main(String[] args) { + SpringApplication.run({{mainClassName}}.class, args); + } + +} diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/model.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/model.mustache new file mode 100644 index 000000000000..751a1a0a21ff --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/model.mustache @@ -0,0 +1,92 @@ +package {{package}}; + +{{#imports}}import {{import}}; +{{/imports}} +import java.util.Objects; +{{#serializableModel}} +import java.io.Serializable; +{{/serializableModel}} +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.Generated; +import java.time.*; +import java.math.*; +{{#models}} +{{#model}} +{{>generatedAnnotation}} +{{#description}} +/** + * {{.}} + */ +{{/description}} +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}}{{^parent}}{{#serializableModel}}implements Serializable{{/serializableModel}}{{/parent}} { +{{#serializableModel}} + private static final long serialVersionUID = 1L; +{{/serializableModel}} + +{{#vars}} +{{#description}} + /** + * {{.}} + */ +{{/description}} + @JsonProperty("{{baseName}}") + private {{{dataType}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}}; + +{{/vars}} +{{#vars}} + /** + * {{description}} + * @return {{name}} + */ + public {{{dataType}}} {{getter}}() { + return {{name}}; + } + + public void {{setter}}({{{dataType}}} {{name}}) { + this.{{name}} = {{name}}; + } + +{{/vars}} + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + }{{#hasVars}} + {{classname}} {{classVarName}} = ({{classname}}) o; + return {{#vars}}Objects.equals(this.{{name}}, {{classVarName}}.{{name}}){{^-last}} && + {{/-last}}{{/vars}}{{#parent}} && super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}} + return true;{{/hasVars}} + } + + @Override + public int hashCode() { + return Objects.hash({{#vars}}{{name}}{{^-last}}, {{/-last}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}}); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class {{classname}} {\n"); + {{#parent}}sb.append(" ").append(toIndentedString(super.toString())).append("\n");{{/parent}} + {{#vars}}sb.append(" {{name}}: ").append(toIndentedString({{name}})).append("\n"); + {{/vars}}sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} +{{/model}} +{{/models}} diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/pom.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/pom.mustache new file mode 100644 index 000000000000..dbc9d340f536 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/pom.mustache @@ -0,0 +1,141 @@ + + + 4.0.0 + + {{groupId}} + {{artifactId}} + {{appVersion}} + jar + + {{appName}} + {{appDescription}} + + + org.springframework.boot + spring-boot-starter-parent + 2.7.18 + + + + + {{javaVersion}} + UTF-8 + UTF-8 + {{dubboVersion}} + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.apache.dubbo + dubbo-spring-boot-starter + ${dubbo.version} + + + + + org.apache.dubbo + dubbo + ${dubbo.version} + + +{{#isZookeeperRegistry}} + +{{#isDubbo33Plus}} + + + org.apache.dubbo + dubbo-registry-zookeeper + ${dubbo.version} + + + org.apache.dubbo + dubbo-remoting-zookeeper-curator5 + ${dubbo.version} + +{{/isDubbo33Plus}} +{{^isDubbo33Plus}} + + + org.apache.dubbo + dubbo-dependencies-zookeeper + ${dubbo.version} + pom + +{{/isDubbo33Plus}} +{{/isZookeeperRegistry}} + +{{#isNacosRegistry}} + + + org.apache.dubbo + dubbo-registry-nacos + ${dubbo.version} + + + com.alibaba.nacos + nacos-client + {{nacosClientVersion}} + +{{/isNacosRegistry}} + +{{^isZookeeperRegistry}}{{^isNacosRegistry}} + +{{#isDubbo33Plus}} + + + org.apache.dubbo + dubbo-registry-zookeeper + ${dubbo.version} + + + org.apache.dubbo + dubbo-remoting-zookeeper-curator5 + ${dubbo.version} + +{{/isDubbo33Plus}} +{{^isDubbo33Plus}} + + + org.apache.dubbo + dubbo-dependencies-zookeeper + ${dubbo.version} + pom + +{{/isDubbo33Plus}} +{{/isNacosRegistry}}{{/isZookeeperRegistry}} + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + + + diff --git a/modules/openapi-generator/src/main/resources/java-dubbo/returnValueExample.mustache b/modules/openapi-generator/src/main/resources/java-dubbo/returnValueExample.mustache new file mode 100644 index 000000000000..7ba3df8ba1dd --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-dubbo/returnValueExample.mustache @@ -0,0 +1 @@ +{{#isString}}"示例字符串"{{/isString}}{{#isBoolean}}true{{/isBoolean}}{{#isInteger}}1{{/isInteger}}{{#isLong}}1L{{/isLong}}{{#isFloat}}1.0f{{/isFloat}}{{#isDouble}}1.0{{/isDouble}}{{#isBinary}}null{{/isBinary}}{{#isByteArray}}null{{/isByteArray}}{{#isDate}}null{{/isDate}}{{#isDateTime}}null{{/isDateTime}}{{#isArray}}null{{/isArray}}{{#isMap}}null{{/isMap}}{{#returnContainer}}null{{/returnContainer}}{{#isContainer}}null{{/isContainer}}{{^isPrimitiveType}}null{{/isPrimitiveType}} diff --git a/samples/server/petstore/java-dubbo/.openapi-generator-ignore b/samples/server/petstore/java-dubbo/.openapi-generator-ignore new file mode 100644 index 000000000000..0ace8df85972 --- /dev/null +++ b/samples/server/petstore/java-dubbo/.openapi-generator-ignore @@ -0,0 +1,33 @@ +# IMPORTANT: this file is generated with the option `openapiGeneratorIgnoreList` enabled +# (--openapi-generator-ignore-list in CLI for example) so the entries below are pre-populated based +# on the input provided by the users and this file will be overwritten every time when the option is +# enabled (which is the exact opposite of the default behaviour to not overwrite +# .openapi-generator-ignore if the file exists). + +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md + +# The following entries are pre-populated based on the input obtained via +# the option `openapiGeneratorIgnoreList` (--openapi-generator-ignore-list in CLI for example). +# Dubbo generator explicitly disables .openapi-generator-ignore diff --git a/samples/server/petstore/java-dubbo/.openapi-generator/FILES b/samples/server/petstore/java-dubbo/.openapi-generator/FILES new file mode 100644 index 000000000000..f996622c82ea --- /dev/null +++ b/samples/server/petstore/java-dubbo/.openapi-generator/FILES @@ -0,0 +1,20 @@ +README.md +pom.xml +src/main/java/org/openapitools/example/OpenAPI PetstoreApplication.java +src/main/java/org/openapitools/example/api/consumer/PetServiceController.java +src/main/java/org/openapitools/example/api/consumer/StoreServiceController.java +src/main/java/org/openapitools/example/api/consumer/UserServiceController.java +src/main/java/org/openapitools/example/api/interfaces/PetService.java +src/main/java/org/openapitools/example/api/interfaces/StoreService.java +src/main/java/org/openapitools/example/api/interfaces/UserService.java +src/main/java/org/openapitools/example/api/provider/PetServiceImpl.java +src/main/java/org/openapitools/example/api/provider/StoreServiceImpl.java +src/main/java/org/openapitools/example/api/provider/UserServiceImpl.java +src/main/java/org/openapitools/example/model/Category.java +src/main/java/org/openapitools/example/model/ModelApiResponse.java +src/main/java/org/openapitools/example/model/Order.java +src/main/java/org/openapitools/example/model/Pet.java +src/main/java/org/openapitools/example/model/Tag.java +src/main/java/org/openapitools/example/model/User.java +src/main/resources/application.yml +src/test/java/org/openapitools/example/OpenAPI PetstoreApplicationTests.java diff --git a/samples/server/petstore/java-dubbo/.openapi-generator/VERSION b/samples/server/petstore/java-dubbo/.openapi-generator/VERSION new file mode 100644 index 000000000000..5e5282953086 --- /dev/null +++ b/samples/server/petstore/java-dubbo/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.16.0-SNAPSHOT diff --git a/samples/server/petstore/java-dubbo/README.md b/samples/server/petstore/java-dubbo/README.md new file mode 100644 index 000000000000..f2a2a61dc082 --- /dev/null +++ b/samples/server/petstore/java-dubbo/README.md @@ -0,0 +1,283 @@ +# OpenAPI Petstore + +This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + +This is a microservice project based on Apache Dubbo, generated by [OpenAPI Generator](https://openapi-generator.tech). + +- API version: 1.0.0 +- Package version: +- Generator: org.openapitools.codegen.languages.DubboCodegen + +## Technology Stack + +- **Framework**: Apache Dubbo 3.2.18 +- **Java**: 8+ +- **Build Tool**: Maven 3.6+ +- **Registry**: zookeeper://127.0.0.1:2181 +- **Serialization**: Jackson JSON + +## System Requirements + +Building and running this project requires: +1. Java 8+ +2. Maven 3.6+ +3. Registry Center (Nacos or Zookeeper) + +## Quick Start + +### 1. Clone and Build Project + +```bash +git clone +cd openapi-dubbo-server-petstore +mvn clean compile +``` + +### 2. Configure Registry Center + +#### Using Nacos (Recommended) +```bash +# Download and start Nacos +wget https://github.com/alibaba/nacos/releases/download/2.2.4/nacos-server-2.2.4.tar.gz +tar -xzf nacos-server-2.2.4.tar.gz +cd nacos/bin +# Linux/Mac +./startup.sh -m standalone +# Windows +startup.cmd -m standalone +``` + +#### Using Zookeeper (Alternative) +```bash +# Download and start Zookeeper +wget https://downloads.apache.org/zookeeper/zookeeper-3.8.2/apache-zookeeper-3.8.2-bin.tar.gz +tar -xzf apache-zookeeper-3.8.2-bin.tar.gz +cd apache-zookeeper-3.8.2-bin +cp conf/zoo_sample.cfg conf/zoo.cfg +bin/zkServer.sh start +``` + +### 3. Configure Application + +Edit the `src/main/resources/application.yml` file: + +```yaml +# Dubbo Configuration +dubbo: + application: + name: openapi-dubbo-server-petstore + registry: + # Using Nacos + address: nacos://127.0.0.1:8848 + # Or using Zookeeper + # address: zookeeper://127.0.0.1:2181 + protocol: + name: dubbo + port: 20880 + provider: + timeout: 10000 + +``` + +### 4. Start Application + +```bash +# Build project +mvn clean compile + +# Run main class +mvn exec:java -Dexec.mainClass=".Application" +``` + +## Project Structure + +``` +openapi-dubbo-server-petstore/ +├── src/main/java// +│ └── Application.java # Main Application Class +├── src/main/resources/ +│ └── application.yml # Application Configuration +├── pom.xml # Maven Configuration +└── README.md # Project Documentation +``` + +## API Interfaces + + +### Service Interfaces + + +## Development Guide + +### Implement Business Logic + +1. Implement specific business logic in the generated `*DubboImpl.java` classes +2. Inject necessary business service dependencies +3. Handle exceptions and error scenarios + +### Custom Configuration + +1. **Timeout Configuration**: Adjust `dubbo.provider.timeout` in `application.yml` +2. **Thread Pool Configuration**: Configure `dubbo.provider.threads` and other parameters +3. **Serialization Configuration**: Choose appropriate serialization method + +### Monitoring and Operations + +1. **Health Checks**: Dubbo provides built-in health check endpoints +2. **Metrics Monitoring**: Integrate with Prometheus or other monitoring systems +3. **Log Management**: Configure appropriate log levels and output formats + +## Testing + +```bash +# Run unit tests +mvn test + +# Run integration tests +mvn integration-test +``` + +## Deployment + +### Development Environment +```bash +mvn spring-boot:run +``` + +### Production Environment +```bash +# Build production package +mvn clean package -Pprod + +# Deploy using Docker +docker build -t openapi-dubbo-server-petstore:1.0.0 . +docker run -p 8080:8080 -p 20880:20880 openapi-dubbo-server-petstore:1.0.0 +``` + +## Generator Configuration Options + +This project supports the following OpenAPI Generator configuration options: + +### Basic Configuration +- `title`: API service title name (Default: "OpenAPI Dubbo") +- `basePackage`: Base package name (Default: "org.openapitools") +- `configPackage`: Configuration class package name (Default: "org.openapitools.configuration") +- `dubboVersion`: Dubbo version (Default: "3.2.0") + +### Generation Control +- `interfaceOnly`: Generate interfaces only, no implementation classes (Default: false) +- `serviceInterface`: Generate service interfaces (Default: true) +- `serviceImplementation`: Generate service implementations (Default: true) +- `async`: Use asynchronous methods (Default: false) +- `useTags`: Use tags to create class names (Default: true) +- `useGenericResponse`: Use generic response wrapper (Default: false) + +### Registry Configuration +- `registry-address`: Registry address, supports full address format (Default: "zookeeper://127.0.0.1:2181") + - Zookeeper example: `zookeeper://127.0.0.1:2181` + - Nacos example: `nacos://127.0.0.1:8848` + +#### 📋 Automatic Dependency Adaptation by Version +The generator automatically selects the correct dependencies based on Dubbo version: + +**Dubbo 3.2 and earlier versions**: +- Zookeeper: `dubbo-dependencies-zookeeper` (Aggregation POM) +- Nacos: `dubbo-registry-nacos` + `nacos-client:2.2.4` + +**Dubbo 3.3+ versions**: +- Zookeeper: `dubbo-registry-zookeeper` + `dubbo-remoting-zookeeper-curator5` +- Nacos: `dubbo-registry-nacos` + `nacos-client:2.5.0` + +### Date-Time Library Configuration +- `dateLibrary`: Date-time library selection (Default: "java8") + - `java8`: Java 8 native JSR310 (Recommended, for JDK 1.8+) + - `java8-localdatetime`: Java 8 using LocalDateTime (For legacy applications only) + - `joda`: Joda time library (For legacy applications only) + - `legacy`: Traditional java.util.Date + +### Usage Examples + +#### 🔧 Dubbo 3.2 Version Example +```bash +# Using Zookeeper (3.2 version automatically uses dubbo-dependencies-zookeeper) +java -jar openapi-generator-cli.jar generate \ +-i /Users/redoom/IdeaProjects/openapi.yaml \ +-g dubbo \ +-o /Users/redoom/IdeaProjects/openapi-test \ +--additional-properties=registry-address=zookeeper://127.0.0.1:2181 \ +--additional-properties=dubboVersion=3.2.0 \ +--additional-properties=dateLibrary=java8 + +# Using Nacos (3.2 version uses nacos-client:2.2.4) +java -jar openapi-generator-cli.jar generate \ +-i /Users/redoom/IdeaProjects/openapi.yaml \ +-g dubbo \ +-o /Users/redoom/IdeaProjects/openapi-test \ +--additional-properties=registry-address=nacos://127.0.0.1:8848 \ +--additional-properties=dubboVersion=3.2.0 \ +--additional-properties=dateLibrary=java8 +``` + +#### 🚀 Dubbo 3.3+ Version Example +```bash +# Using Zookeeper (3.3+ version automatically uses new modular dependencies) +java -jar openapi-generator-cli.jar generate \ +-i /Users/redoom/IdeaProjects/openapi.yaml \ +-g dubbo \ +-o /Users/redoom/IdeaProjects/openapi-test \ +--additional-properties=registry-address=zookeeper://127.0.0.1:2181 \ +--additional-properties=dubboVersion=3.3.0 \ +--additional-properties=dateLibrary=java8 + +# Using Nacos (3.3+ version uses nacos-client:2.5.0) +java -jar openapi-generator-cli.jar generate \ +-i /Users/redoom/IdeaProjects/openapi.yaml \ +-g dubbo \ +-o /Users/redoom/IdeaProjects/openapi-test \ +--additional-properties=registry-address=nacos://127.0.0.1:8848 \ +--additional-properties=dubboVersion=3.3.0 \ +--additional-properties=dateLibrary=java8 +``` + +## Troubleshooting + +### Common Issues + +1. **Registry Connection Failed** + - Check if the registry center is started + - Verify network connection and port configuration + +2. **Service Call Timeout** + - Adjust `dubbo.provider.timeout` settings + - Check network latency and service performance + +3. **Serialization Exception** + - Ensure all model classes implement `Serializable` interface + - Check Jackson configuration + +### Debug Logging + +Enable debug mode to see detailed logs: + +```yaml +logging: + level: + org.apache.dubbo: DEBUG + : DEBUG +``` + +## License + +This project is licensed under the [Apache License 2.0](LICENSE). + +## Contributing + +Issues and Pull Requests are welcome! + +## Contact + + + +--- + +> This project is automatically generated by OpenAPI Generator, based on Apache Dubbo microservice architecture. diff --git a/samples/server/petstore/java-dubbo/pom.xml b/samples/server/petstore/java-dubbo/pom.xml new file mode 100644 index 000000000000..53e4702b4628 --- /dev/null +++ b/samples/server/petstore/java-dubbo/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + org.openapitools + openapi-dubbo + 1.0.0 + jar + + Financial Data API + API for retrieving historical and real-time financial data for various products like A-Shares, US Stocks, Funds, and more. + + + org.springframework.boot + spring-boot-starter-parent + 2.7.18 + + + + + 17 + UTF-8 + UTF-8 + 3.2.18 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.apache.dubbo + dubbo-spring-boot-starter + ${dubbo.version} + + + + + org.apache.dubbo + dubbo + ${dubbo.version} + + + + + + + + org.apache.dubbo + dubbo-dependencies-zookeeper + ${dubbo.version} + pom + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + + + diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/OpenAPIPetstoreApplication.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/OpenAPIPetstoreApplication.java new file mode 100644 index 000000000000..239ebf52bf3e --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/OpenAPIPetstoreApplication.java @@ -0,0 +1,15 @@ +package org.openapitools.example; + +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@EnableDubbo(scanBasePackages = "org.openapitools.example") +public class OpenAPIPetstoreApplication { + + public static void main(String[] args) { + SpringApplication.run(OpenAPIPetstoreApplication.class, args); + } + +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/consumer/PetServiceController.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/consumer/PetServiceController.java new file mode 100644 index 000000000000..1283f2fd61c3 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/consumer/PetServiceController.java @@ -0,0 +1,86 @@ +package org.openapitools.example.api.consumer; + +import org.openapitools.example.model.ModelApiResponse; +import org.openapitools.example.model.Pet; +import org.openapitools.example.model.*; +import org.openapitools.example.api.interfaces.PetService; +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import org.apache.dubbo.config.annotation.DubboReference; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Generated; + + +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +@RestController +@RequestMapping("/pet") +public class PetServiceController { + + @DubboReference + private PetService petService; + + @RequestMapping(method = RequestMethod.POST, value = "/") + public Pet addPet( + @RequestParam(name = "pet") Pet pet + ) { + return petService.addPet(pet); + } + + @RequestMapping(method = RequestMethod.DELETE, value = "/{petId}") + public void deletePet( + @RequestParam(name = "petId") Long petId, + @RequestParam(name = "apiKey") String apiKey + ) { + petService.deletePet(petId, apiKey); + } + + @RequestMapping(method = RequestMethod.GET, value = "/findByStatus") + public List findPetsByStatus( + @RequestParam(name = "status") List status + ) { + return petService.findPetsByStatus(status); + } + + @RequestMapping(method = RequestMethod.GET, value = "/findByTags") + public List findPetsByTags( + @RequestParam(name = "tags") List tags + ) { + return petService.findPetsByTags(tags); + } + + @RequestMapping(method = RequestMethod.GET, value = "/{petId}") + public Pet getPetById( + @RequestParam(name = "petId") Long petId + ) { + return petService.getPetById(petId); + } + + @RequestMapping(method = RequestMethod.PUT, value = "/") + public Pet updatePet( + @RequestParam(name = "pet") Pet pet + ) { + return petService.updatePet(pet); + } + + @RequestMapping(method = RequestMethod.POST, value = "/{petId}") + public void updatePetWithForm( + @RequestParam(name = "petId") Long petId, + @RequestParam(name = "name") String name, + @RequestParam(name = "status") String status + ) { + petService.updatePetWithForm(petId, name, status); + } + + @RequestMapping(method = RequestMethod.POST, value = "/{petId}/uploadImage") + public ModelApiResponse uploadFile( + @RequestParam(name = "petId") Long petId, + @RequestParam(name = "additionalMetadata") String additionalMetadata, + @RequestParam(name = "_file") org.springframework.web.multipart.MultipartFile _file + ) { + return petService.uploadFile(petId, additionalMetadata, _file); + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/consumer/StoreServiceController.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/consumer/StoreServiceController.java new file mode 100644 index 000000000000..cf4342e25447 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/consumer/StoreServiceController.java @@ -0,0 +1,51 @@ +package org.openapitools.example.api.consumer; + +import org.openapitools.example.model.Order; +import org.openapitools.example.model.*; +import org.openapitools.example.api.interfaces.StoreService; +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import org.apache.dubbo.config.annotation.DubboReference; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Generated; + + +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +@RestController +@RequestMapping("/store") +public class StoreServiceController { + + @DubboReference + private StoreService storeService; + + @RequestMapping(method = RequestMethod.DELETE, value = "/order/{orderId}") + public void deleteOrder( + @RequestParam(name = "orderId") String orderId + ) { + storeService.deleteOrder(orderId); + } + + @RequestMapping(method = RequestMethod.GET, value = "/inventory") + public Map getInventory( + ) { + return storeService.getInventory(); + } + + @RequestMapping(method = RequestMethod.GET, value = "/order/{orderId}") + public Order getOrderById( + @RequestParam(name = "orderId") Long orderId + ) { + return storeService.getOrderById(orderId); + } + + @RequestMapping(method = RequestMethod.POST, value = "/order") + public Order placeOrder( + @RequestParam(name = "order") Order order + ) { + return storeService.placeOrder(order); + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/consumer/UserServiceController.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/consumer/UserServiceController.java new file mode 100644 index 000000000000..269b336401a6 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/consumer/UserServiceController.java @@ -0,0 +1,82 @@ +package org.openapitools.example.api.consumer; + +import java.time.OffsetDateTime; +import org.openapitools.example.model.User; +import org.openapitools.example.model.*; +import org.openapitools.example.api.interfaces.UserService; +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import org.apache.dubbo.config.annotation.DubboReference; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Generated; + + +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +@RestController +@RequestMapping("/user") +public class UserServiceController { + + @DubboReference + private UserService userService; + + @RequestMapping(method = RequestMethod.POST, value = "/") + public void createUser( + @RequestParam(name = "user") User user + ) { + userService.createUser(user); + } + + @RequestMapping(method = RequestMethod.POST, value = "/createWithArray") + public void createUsersWithArrayInput( + @RequestParam(name = "user") List user + ) { + userService.createUsersWithArrayInput(user); + } + + @RequestMapping(method = RequestMethod.POST, value = "/createWithList") + public void createUsersWithListInput( + @RequestParam(name = "user") List user + ) { + userService.createUsersWithListInput(user); + } + + @RequestMapping(method = RequestMethod.DELETE, value = "/{username}") + public void deleteUser( + @RequestParam(name = "username") String username + ) { + userService.deleteUser(username); + } + + @RequestMapping(method = RequestMethod.GET, value = "/{username}") + public User getUserByName( + @RequestParam(name = "username") String username + ) { + return userService.getUserByName(username); + } + + @RequestMapping(method = RequestMethod.GET, value = "/login") + public String loginUser( + @RequestParam(name = "username") String username, + @RequestParam(name = "password") String password + ) { + return userService.loginUser(username, password); + } + + @RequestMapping(method = RequestMethod.GET, value = "/logout") + public void logoutUser( + ) { + userService.logoutUser(); + } + + @RequestMapping(method = RequestMethod.PUT, value = "/{username}") + public void updateUser( + @RequestParam(name = "username") String username, + @RequestParam(name = "user") User user + ) { + userService.updateUser(username, user); + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/interfaces/PetService.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/interfaces/PetService.java new file mode 100644 index 000000000000..6fdbe26e2806 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/interfaces/PetService.java @@ -0,0 +1,115 @@ +package org.openapitools.example.api.interfaces; + +import org.openapitools.example.model.ModelApiResponse; +import org.openapitools.example.model.Pet; +import org.openapitools.example.model.*; +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import javax.annotation.Generated; + + +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +public interface PetService { + + /** + * Add a new pet to the store + * + * + * @param pet Pet object that needs to be added to the store (required) + * @return Pet + */ + Pet addPet( + Pet pet + ); + + /** + * Deletes a pet + * + * + * @param petId Pet id to delete (required) + * @param apiKey (optional) + * @return void + */ + void deletePet( + Long petId, + String apiKey + ); + + /** + * Finds Pets by status + * Multiple status values can be provided with comma separated strings + * + * @param status Status values that need to be considered for filter (required) + * @return List + */ + List findPetsByStatus( + List status + ); + + /** + * Finds Pets by tags + * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. + * + * @param tags Tags to filter by (required) + * @return List + */ + List findPetsByTags( + List tags + ); + + /** + * Find pet by ID + * Returns a single pet + * + * @param petId ID of pet to return (required) + * @return Pet + */ + Pet getPetById( + Long petId + ); + + /** + * Update an existing pet + * + * + * @param pet Pet object that needs to be added to the store (required) + * @return Pet + */ + Pet updatePet( + Pet pet + ); + + /** + * Updates a pet in the store with form data + * + * + * @param petId ID of pet that needs to be updated (required) + * @param name Updated name of the pet (optional) + * @param status Updated status of the pet (optional) + * @return void + */ + void updatePetWithForm( + Long petId, + String name, + String status + ); + + /** + * uploads an image + * + * + * @param petId ID of pet to update (required) + * @param additionalMetadata Additional data to pass to server (optional) + * @param _file file to upload (optional) + * @return ModelApiResponse + */ + ModelApiResponse uploadFile( + Long petId, + String additionalMetadata, + org.springframework.web.multipart.MultipartFile _file + ); +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/interfaces/StoreService.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/interfaces/StoreService.java new file mode 100644 index 000000000000..0c8a1e742d37 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/interfaces/StoreService.java @@ -0,0 +1,58 @@ +package org.openapitools.example.api.interfaces; + +import org.openapitools.example.model.Order; +import org.openapitools.example.model.*; +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import javax.annotation.Generated; + + +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +public interface StoreService { + + /** + * Delete purchase order by ID + * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + * + * @param orderId ID of the order that needs to be deleted (required) + * @return void + */ + void deleteOrder( + String orderId + ); + + /** + * Returns pet inventories by status + * Returns a map of status codes to quantities + * + * @return Map + */ + Map getInventory( + ); + + /** + * Find purchase order by ID + * For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions + * + * @param orderId ID of pet that needs to be fetched (required) + * @return Order + */ + Order getOrderById( + Long orderId + ); + + /** + * Place an order for a pet + * + * + * @param order order placed for purchasing the pet (required) + * @return Order + */ + Order placeOrder( + Order order + ); +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/interfaces/UserService.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/interfaces/UserService.java new file mode 100644 index 000000000000..88b117ca4635 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/interfaces/UserService.java @@ -0,0 +1,107 @@ +package org.openapitools.example.api.interfaces; + +import java.time.OffsetDateTime; +import org.openapitools.example.model.User; +import org.openapitools.example.model.*; +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import javax.annotation.Generated; + + +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +public interface UserService { + + /** + * Create user + * This can only be done by the logged in user. + * + * @param user Created user object (required) + * @return void + */ + void createUser( + User user + ); + + /** + * Creates list of users with given input array + * + * + * @param user List of user object (required) + * @return void + */ + void createUsersWithArrayInput( + List user + ); + + /** + * Creates list of users with given input array + * + * + * @param user List of user object (required) + * @return void + */ + void createUsersWithListInput( + List user + ); + + /** + * Delete user + * This can only be done by the logged in user. + * + * @param username The name that needs to be deleted (required) + * @return void + */ + void deleteUser( + String username + ); + + /** + * Get user by user name + * + * + * @param username The name that needs to be fetched. Use user1 for testing. (required) + * @return User + */ + User getUserByName( + String username + ); + + /** + * Logs user into the system + * + * + * @param username The user name for login (required) + * @param password The password for login in clear text (required) + * @return String + */ + String loginUser( + String username, + String password + ); + + /** + * Logs out current logged in user session + * + * + * @return void + */ + void logoutUser( + ); + + /** + * Updated user + * This can only be done by the logged in user. + * + * @param username name that need to be deleted (required) + * @param user Updated user object (required) + * @return void + */ + void updateUser( + String username, + User user + ); +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/provider/PetServiceImpl.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/provider/PetServiceImpl.java new file mode 100644 index 000000000000..1b32c9a68a2e --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/provider/PetServiceImpl.java @@ -0,0 +1,117 @@ +package org.openapitools.example.api.provider; + +import org.openapitools.example.model.ModelApiResponse; +import org.openapitools.example.model.Pet; +import org.openapitools.example.model.*; +import org.openapitools.example.api.interfaces.PetService; +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import org.apache.dubbo.config.annotation.DubboService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.Generated; + + +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +@DubboService +public class PetServiceImpl implements PetService { + + private static final Logger logger = LoggerFactory.getLogger(PetServiceImpl.class); + + @Override + public Pet addPet( + Pet pet + ) { + logger.info("Dubbo service method addPet called with parameters: pet={}", pet); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null +; + } + + @Override + public void deletePet( + Long petId, + String apiKey + ) { + logger.info("Dubbo service method deletePet called with parameters: petId={}, apiKey={}", petId, apiKey); + + // TODO: Implement your business logic here + } + + @Override + public List findPetsByStatus( + List status + ) { + logger.info("Dubbo service method findPetsByStatus called with parameters: status={}", status); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null; + } + + @Override + public List findPetsByTags( + List tags + ) { + logger.info("Dubbo service method findPetsByTags called with parameters: tags={}", tags); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null; + } + + @Override + public Pet getPetById( + Long petId + ) { + logger.info("Dubbo service method getPetById called with parameters: petId={}", petId); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null +; + } + + @Override + public Pet updatePet( + Pet pet + ) { + logger.info("Dubbo service method updatePet called with parameters: pet={}", pet); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null +; + } + + @Override + public void updatePetWithForm( + Long petId, + String name, + String status + ) { + logger.info("Dubbo service method updatePetWithForm called with parameters: petId={}, name={}, status={}", petId, name, status); + + // TODO: Implement your business logic here + } + + @Override + public ModelApiResponse uploadFile( + Long petId, + String additionalMetadata, + org.springframework.web.multipart.MultipartFile _file + ) { + logger.info("Dubbo service method uploadFile called with parameters: petId={}, additionalMetadata={}, _file={}", petId, additionalMetadata, _file); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null +; + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/provider/StoreServiceImpl.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/provider/StoreServiceImpl.java new file mode 100644 index 000000000000..2b9cc198467e --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/provider/StoreServiceImpl.java @@ -0,0 +1,66 @@ +package org.openapitools.example.api.provider; + +import org.openapitools.example.model.Order; +import org.openapitools.example.model.*; +import org.openapitools.example.api.interfaces.StoreService; +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import org.apache.dubbo.config.annotation.DubboService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.Generated; + + +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +@DubboService +public class StoreServiceImpl implements StoreService { + + private static final Logger logger = LoggerFactory.getLogger(StoreServiceImpl.class); + + @Override + public void deleteOrder( + String orderId + ) { + logger.info("Dubbo service method deleteOrder called with parameters: orderId={}", orderId); + + // TODO: Implement your business logic here + } + + @Override + public Map getInventory( + ) { + logger.info("Dubbo service method getInventory called with parameters: "); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null; + } + + @Override + public Order getOrderById( + Long orderId + ) { + logger.info("Dubbo service method getOrderById called with parameters: orderId={}", orderId); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null +; + } + + @Override + public Order placeOrder( + Order order + ) { + logger.info("Dubbo service method placeOrder called with parameters: order={}", order); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null +; + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/provider/UserServiceImpl.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/provider/UserServiceImpl.java new file mode 100644 index 000000000000..387372ea3953 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/api/provider/UserServiceImpl.java @@ -0,0 +1,103 @@ +package org.openapitools.example.api.provider; + +import java.time.OffsetDateTime; +import org.openapitools.example.model.User; +import org.openapitools.example.model.*; +import org.openapitools.example.api.interfaces.UserService; +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.LocalDate; +import java.time.LocalDateTime; +import org.apache.dubbo.config.annotation.DubboService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.Generated; + + +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +@DubboService +public class UserServiceImpl implements UserService { + + private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); + + @Override + public void createUser( + User user + ) { + logger.info("Dubbo service method createUser called with parameters: user={}", user); + + // TODO: Implement your business logic here + } + + @Override + public void createUsersWithArrayInput( + List user + ) { + logger.info("Dubbo service method createUsersWithArrayInput called with parameters: user={}", user); + + // TODO: Implement your business logic here + } + + @Override + public void createUsersWithListInput( + List user + ) { + logger.info("Dubbo service method createUsersWithListInput called with parameters: user={}", user); + + // TODO: Implement your business logic here + } + + @Override + public void deleteUser( + String username + ) { + logger.info("Dubbo service method deleteUser called with parameters: username={}", username); + + // TODO: Implement your business logic here + } + + @Override + public User getUserByName( + String username + ) { + logger.info("Dubbo service method getUserByName called with parameters: username={}", username); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null +; + } + + @Override + public String loginUser( + String username, + String password + ) { + logger.info("Dubbo service method loginUser called with parameters: username={}, password={}", username, password); + + // TODO: Implement your business logic here + // Replace this with actual implementation + return null +; + } + + @Override + public void logoutUser( + ) { + logger.info("Dubbo service method logoutUser called with parameters: "); + + // TODO: Implement your business logic here + } + + @Override + public void updateUser( + String username, + User user + ) { + logger.info("Dubbo service method updateUser called with parameters: username={}, user={}", username, user); + + // TODO: Implement your business logic here + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Category.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Category.java new file mode 100644 index 000000000000..f49454c366c6 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Category.java @@ -0,0 +1,87 @@ +package org.openapitools.example.model; + +import java.util.Objects; +import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.Generated; +import java.time.*; +import java.math.*; +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +/** + * A category for a pet + */ +public class Category implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("id") + private Long id; + + @JsonProperty("name") + private String name; + + /** + * + * @return id + */ + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + /** + * + * @return name + */ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Category category = (Category) o; + return Objects.equals(this.id, category.id) && + Objects.equals(this.name, category.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Category {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/ModelApiResponse.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/ModelApiResponse.java new file mode 100644 index 000000000000..9445a372092e --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/ModelApiResponse.java @@ -0,0 +1,104 @@ +package org.openapitools.example.model; + +import java.util.Objects; +import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.Generated; +import java.time.*; +import java.math.*; +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +/** + * Describes the result of uploading an image resource + */ +public class ModelApiResponse implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("code") + private Integer code; + + @JsonProperty("type") + private String type; + + @JsonProperty("message") + private String message; + + /** + * + * @return code + */ + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + /** + * + * @return type + */ + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + /** + * + * @return message + */ + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ModelApiResponse _apiResponse = (ModelApiResponse) o; + return Objects.equals(this.code, _apiResponse.code) && + Objects.equals(this.type, _apiResponse.type) && + Objects.equals(this.message, _apiResponse.message); + } + + @Override + public int hashCode() { + return Objects.hash(code, type, message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ModelApiResponse {\n"); + + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Order.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Order.java new file mode 100644 index 000000000000..ce19d3a22876 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Order.java @@ -0,0 +1,159 @@ +package org.openapitools.example.model; + +import java.time.OffsetDateTime; +import java.util.Objects; +import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.Generated; +import java.time.*; +import java.math.*; +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +/** + * An order for a pets from the pet store + */ +public class Order implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("id") + private Long id; + + @JsonProperty("petId") + private Long petId; + + @JsonProperty("quantity") + private Integer quantity; + + @JsonProperty("shipDate") + private OffsetDateTime shipDate; + + /** + * Order Status + */ + @JsonProperty("status") + private String status; + + @JsonProperty("complete") + private Boolean complete = false; + + /** + * + * @return id + */ + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + /** + * + * @return petId + */ + public Long getPetId() { + return petId; + } + + public void setPetId(Long petId) { + this.petId = petId; + } + + /** + * + * @return quantity + */ + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + /** + * + * @return shipDate + */ + public OffsetDateTime getShipDate() { + return shipDate; + } + + public void setShipDate(OffsetDateTime shipDate) { + this.shipDate = shipDate; + } + + /** + * Order Status + * @return status + */ + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + /** + * + * @return complete + */ + public Boolean getComplete() { + return complete; + } + + public void setComplete(Boolean complete) { + this.complete = complete; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Order order = (Order) o; + return Objects.equals(this.id, order.id) && + Objects.equals(this.petId, order.petId) && + Objects.equals(this.quantity, order.quantity) && + Objects.equals(this.shipDate, order.shipDate) && + Objects.equals(this.status, order.status) && + Objects.equals(this.complete, order.complete); + } + + @Override + public int hashCode() { + return Objects.hash(id, petId, quantity, shipDate, status, complete); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Order {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" petId: ").append(toIndentedString(petId)).append("\n"); + sb.append(" quantity: ").append(toIndentedString(quantity)).append("\n"); + sb.append(" shipDate: ").append(toIndentedString(shipDate)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" complete: ").append(toIndentedString(complete)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Pet.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Pet.java new file mode 100644 index 000000000000..c7e9e87c728e --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Pet.java @@ -0,0 +1,161 @@ +package org.openapitools.example.model; + +import org.openapitools.example.model.Category; +import org.openapitools.example.model.Tag; +import java.util.*; +import java.util.Objects; +import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.Generated; +import java.time.*; +import java.math.*; +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +/** + * A pet for sale in the pet store + */ +public class Pet implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("id") + private Long id; + + @JsonProperty("category") + private Category category; + + @JsonProperty("name") + private String name; + + @JsonProperty("photoUrls") + private List photoUrls = new ArrayList<>(); + + @JsonProperty("tags") + private List tags = new ArrayList<>(); + + /** + * pet status in the store + */ + @JsonProperty("status") + private String status; + + /** + * + * @return id + */ + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + /** + * + * @return category + */ + public Category getCategory() { + return category; + } + + public void setCategory(Category category) { + this.category = category; + } + + /** + * + * @return name + */ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * + * @return photoUrls + */ + public List getPhotoUrls() { + return photoUrls; + } + + public void setPhotoUrls(List photoUrls) { + this.photoUrls = photoUrls; + } + + /** + * + * @return tags + */ + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + /** + * pet status in the store + * @return status + */ + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pet pet = (Pet) o; + return Objects.equals(this.id, pet.id) && + Objects.equals(this.category, pet.category) && + Objects.equals(this.name, pet.name) && + Objects.equals(this.photoUrls, pet.photoUrls) && + Objects.equals(this.tags, pet.tags) && + Objects.equals(this.status, pet.status); + } + + @Override + public int hashCode() { + return Objects.hash(id, category, name, photoUrls, tags, status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Pet {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" category: ").append(toIndentedString(category)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); + sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Tag.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Tag.java new file mode 100644 index 000000000000..55d988bfbc30 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/Tag.java @@ -0,0 +1,87 @@ +package org.openapitools.example.model; + +import java.util.Objects; +import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.Generated; +import java.time.*; +import java.math.*; +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +/** + * A tag for a pet + */ +public class Tag implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("id") + private Long id; + + @JsonProperty("name") + private String name; + + /** + * + * @return id + */ + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + /** + * + * @return name + */ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tag tag = (Tag) o; + return Objects.equals(this.id, tag.id) && + Objects.equals(this.name, tag.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Tag {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/User.java b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/User.java new file mode 100644 index 000000000000..3df4a16859f8 --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/java/org/openapitools/example/model/User.java @@ -0,0 +1,192 @@ +package org.openapitools.example.model; + +import java.util.Objects; +import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.Generated; +import java.time.*; +import java.math.*; +@Generated(value = "org.openapitools.codegen.languages.DubboCodegen", comments = "Generator version: 7.16.0-SNAPSHOT") + +/** + * A User who is purchasing from the pet store + */ +public class User implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("id") + private Long id; + + @JsonProperty("username") + private String username; + + @JsonProperty("firstName") + private String firstName; + + @JsonProperty("lastName") + private String lastName; + + @JsonProperty("email") + private String email; + + @JsonProperty("password") + private String password; + + @JsonProperty("phone") + private String phone; + + /** + * User Status + */ + @JsonProperty("userStatus") + private Integer userStatus; + + /** + * + * @return id + */ + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + /** + * + * @return username + */ + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + /** + * + * @return firstName + */ + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + /** + * + * @return lastName + */ + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + /** + * + * @return email + */ + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + /** + * + * @return password + */ + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + /** + * + * @return phone + */ + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + /** + * User Status + * @return userStatus + */ + public Integer getUserStatus() { + return userStatus; + } + + public void setUserStatus(Integer userStatus) { + this.userStatus = userStatus; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + User user = (User) o; + return Objects.equals(this.id, user.id) && + Objects.equals(this.username, user.username) && + Objects.equals(this.firstName, user.firstName) && + Objects.equals(this.lastName, user.lastName) && + Objects.equals(this.email, user.email) && + Objects.equals(this.password, user.password) && + Objects.equals(this.phone, user.phone) && + Objects.equals(this.userStatus, user.userStatus); + } + + @Override + public int hashCode() { + return Objects.hash(id, username, firstName, lastName, email, password, phone, userStatus); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class User {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" username: ").append(toIndentedString(username)).append("\n"); + sb.append(" firstName: ").append(toIndentedString(firstName)).append("\n"); + sb.append(" lastName: ").append(toIndentedString(lastName)).append("\n"); + sb.append(" email: ").append(toIndentedString(email)).append("\n"); + sb.append(" password: ").append(toIndentedString(password)).append("\n"); + sb.append(" phone: ").append(toIndentedString(phone)).append("\n"); + sb.append(" userStatus: ").append(toIndentedString(userStatus)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/samples/server/petstore/java-dubbo/src/main/resources/application.yml b/samples/server/petstore/java-dubbo/src/main/resources/application.yml new file mode 100644 index 000000000000..3a46465ce92c --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/main/resources/application.yml @@ -0,0 +1,20 @@ +spring: + application: + name: openapi-dubbo-server-petstore-provider + +dubbo: + application: + name: openapi-dubbo-server-petstore + logger: slf4j + registry: + address: N/A + protocol: + name: tri + port: -1 # auto-increment port + +# 日志配置 +logging: + level: + root: INFO + org.apache.dubbo: INFO + org.openapitools.example: DEBUG diff --git a/samples/server/petstore/java-dubbo/src/test/java/org/openapitools/example/OpenAPIPetstoreApplicationTests.java b/samples/server/petstore/java-dubbo/src/test/java/org/openapitools/example/OpenAPIPetstoreApplicationTests.java new file mode 100644 index 000000000000..6d1fc667b8cf --- /dev/null +++ b/samples/server/petstore/java-dubbo/src/test/java/org/openapitools/example/OpenAPIPetstoreApplicationTests.java @@ -0,0 +1,13 @@ +package org.openapitools.example; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class OpenAPIPetstoreApplicationTests { + + @Test + void contextLoads() { + } + +}