Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -473,23 +473,18 @@ private <T> Optional<T> getConfigKeyValues(final Config config, final Path openA
Class<T> propertyType) {

Optional<String> possibleConfigKey = getConfigKeyValue(config, openApiFilePath);
if (possibleConfigKey.isPresent()) {
return getValuesByConfigKey(config, CodegenConfig.getSpecConfigNameByConfigKey(possibleConfigKey.get(), configName),
propertyType, configName);
}
return possibleConfigKey
.flatMap(s -> getValuesByConfigKey(config, CodegenConfig.getSpecConfigNameByConfigKey(s, configName),
propertyType, configName));

return Optional.empty();
}

private <K, V> Optional<Map<K, V>> getConfigKeyValues(final SmallRyeConfig config, final Path openApiFilePath,
CodegenConfig.ConfigName configName,
Class<K> kClass, Class<V> vClass) {

Optional<String> possibleConfigKey = getConfigKeyValue(config, openApiFilePath);
if (possibleConfigKey.isPresent()) {
return getValuesByConfigKey(config, configName, kClass, vClass, possibleConfigKey.get());
}
return possibleConfigKey.flatMap(s -> getValuesByConfigKey(config, configName, kClass, vClass, s));

return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
Expand All @@ -12,7 +11,7 @@ public class OpenApiGeneratorOutputPaths {
public static final String OPENAPI_PATH = "open-api";
public static final String STREAM_PATH = "open-api-stream";

private static final Collection<String> rootPaths = Arrays.asList(STREAM_PATH);
private static final Collection<String> rootPaths = List.of(STREAM_PATH);

public static Path getRelativePath(Path path) {
List<String> paths = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,20 @@ public CodegenModel fromModel(String name, Schema model) {
return codegenModel;
}

@Override
public CodegenProperty fromProperty(String name, Schema p, boolean required, boolean schemaIsFromAdditionalProperties) {
if (p != null && p.getType() != null) {
// Property is a `type: object` without `additionalProperties: true`, without `properties`, but has `default` values set!
// In this peculiar situation, the template will try to initialize a Java Object with such values, and it will fail to compile.
// See https://github.com/quarkiverse/quarkus-openapi-generator/issues/1185 for more context.
if ("object".equals(p.getType()) && p.getDefault() != null && p.getAdditionalProperties() == null
&& p.getItems() == null) {
p.setAdditionalProperties(true);
}
}
return super.fromProperty(name, p, required, schemaIsFromAdditionalProperties);
}

private void warnIfDuplicated(CodegenModel m) {
Set<String> propertyNames = new TreeSet<>();
for (CodegenProperty element : m.allVars) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@

import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -718,6 +721,30 @@ void verifyDynamicUrlAnnotation() throws Exception {
}
}

@Test
void verifyAllowAdditionalPropertiesIfNotPresent() throws Exception {
List<File> generatedFiles = createGeneratorWrapperReactive("issue-1185.json")
.generate("org.issue1185")
.stream()
.filter(file -> file.getPath().endsWith("PictureDescriptionLocal.java")).toList();

assertThat(generatedFiles).isNotEmpty();
// generationConfig
for (File file : generatedFiles) {
try {
Optional<FieldDeclaration> var = StaticJavaParser.parse(file)
.findAll(FieldDeclaration.class).stream()
.filter(c -> c.getVariable(0)
.getNameAsString().equals("generationConfig"))
.findFirst();
assertThat(var).isPresent();
assertThat(var.get().getElementType().asString()).contains("Map<String,Object>");
} catch (FileNotFoundException e) {
throw new RuntimeException(e.getMessage());
}
}
}

private List<File> generateRestClientFiles() throws URISyntaxException {
OpenApiClientGeneratorWrapper generatorWrapper = createGeneratorWrapper("simple-openapi.json").withCircuitBreakerConfig(
Map.of("org.openapitools.client.api.DefaultApi", List.of("opThatDoesNotExist", "byeMethodGet")));
Expand All @@ -736,15 +763,34 @@ private OpenApiClientGeneratorWrapper createGeneratorWrapper(String specFileName
}

private Path getOpenApiSpecPath(String specFileName) throws URISyntaxException {
return Path.of(requireNonNull(this.getClass().getResource(String.format("/openapi/%s", specFileName))).toURI());
URL url = this.getClass().getResource("/openapi/" + specFileName);
Objects.requireNonNull(url, "Could not find /openapi/" + specFileName);

URI uri;
try {
uri = url.toURI();
} catch (URISyntaxException e) {
// this should never happen for a well-formed file URL
throw new RuntimeException("Invalid URI for " + url, e);
}

return Paths.get(uri);
}

private Path getOpenApiTargetPath(Path openApiSpec) throws URISyntaxException {
return Paths.get(getTargetDir(), "openapi-gen");
}

private String getTargetDir() throws URISyntaxException {
return Paths.get(requireNonNull(getClass().getResource("/")).toURI()).getParent().toString();
private String getTargetDir() {
URL url = requireNonNull(getClass().getResource("/"),
"Could not locate classpath root");
try {
return Paths.get(url.toURI())
.getParent()
.toString();
} catch (URISyntaxException e) {
throw new RuntimeException("Invalid URI for " + url, e);
}
}

private Optional<VariableDeclarator> findVariableByName(List<FieldDeclaration> fields, String name) {
Expand Down
89 changes: 89 additions & 0 deletions client/deployment/src/test/resources/openapi/issue-1185.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"openapi": "3.1.0",
"info": {
"title": "Docling Serve – PictureDescriptionLocal",
"version": "0.13.0"
},
"paths": {
"/v1alpha/convert/file": {
"post": {
"summary": "Process File with Local Picture Description",
"operationId": "processFileWithPictureDescriptionLocal",
"tags": ["Docling"],
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"files": {
"type": "array",
"items": {
"type": "string",
"format": "binary"
}
},
"picture_description_local": {
"$ref": "#/components/schemas/PictureDescriptionLocal"
}
},
"required": ["files", "picture_description_local"]
}
}
}
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"PictureDescriptionLocal": {
"type": "object",
"title": "PictureDescriptionLocal",
"description": "Options for running a local vision-language model in the picture description. Parameters refer to a model hosted on Hugging Face.",
"properties": {
"repo_id": {
"type": "string",
"title": "Repo Id",
"description": "Repository ID on the Hugging Face Hub."
},
"prompt": {
"type": "string",
"title": "Prompt",
"description": "Prompt used when calling the vision-language model.",
"default": "Describe this image in a few sentences."
},
"generation_config": {
"type": "object",
"title": "Generation Config",
"description": "Config from Transformers’ GenerationConfig (e.g. max_new_tokens, do_sample).",
"default": {
"max_new_tokens": 200,
"do_sample": false
},
"examples": [
{
"do_sample": false,
"max_new_tokens": 200
}
]
}
},
"required": ["repo_id"]
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ endif::add-copy-button-to-config-props[]

[.description]
--
Path to the Moqu (relative to the project).
Path to the Moqu OpenAPI files, relative to the `src/main/resources` directory.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcruzdev when sending PRs to server/moqu make sure to run the whole build, from the top, locally.



ifdef::add-copy-button-to-env-var[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ endif::add-copy-button-to-config-props[]

[.description]
--
Path to the Moqu (relative to the project).
Path to the Moqu OpenAPI files, relative to the `src/main/resources` directory.


ifdef::add-copy-button-to-env-var[]
Expand Down