Skip to content

Commit 6909c88

Browse files
dtillerjimschubert
andauthored
[cli] Batch: support multiple/nested !include directive (#7354)
Co-authored-by: Jim Schubert <[email protected]>
1 parent bb00d88 commit 6909c88

File tree

11 files changed

+106
-26
lines changed

11 files changed

+106
-26
lines changed

docs/usage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ openapi-generator generate -i petstore.yaml -g typescript-fetch -o out \
602602
The `batch` command allows you to move all CLI arguments supported by the `generate` command into a YAML or JSON file.
603603
604604
*NOTE*: This command supports an additional `!include` property which may point to another "shared" file, the base path to which can be
605-
modified by `--includes-base-dir`.
605+
modified by `--includes-base-dir`. Starting with 5.0.0, the `!batch` command supports multiple `!include` properties, either sequential or nested. In order to support multiple `!include` properties in a JSON file, the property name can have a suffix, e.g. `!include1`, `!include2`, etc. The suffix have no meaning other than providing unique property names.
606606
607607
```bash
608608
openapi-generator help batch

modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/GenerateBatch.java

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,19 @@
1818

1919
import ch.qos.logback.classic.Level;
2020
import ch.qos.logback.classic.LoggerContext;
21+
22+
import com.fasterxml.jackson.core.JsonFactory;
23+
import com.fasterxml.jackson.core.JsonGenerator;
2124
import com.fasterxml.jackson.core.JsonParser;
25+
import com.fasterxml.jackson.core.JsonToken;
2226
import com.fasterxml.jackson.core.TreeNode;
2327
import com.fasterxml.jackson.databind.*;
2428
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
2529
import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer;
2630
import com.fasterxml.jackson.databind.module.SimpleModule;
2731
import com.fasterxml.jackson.databind.node.ObjectNode;
32+
import com.fasterxml.jackson.databind.util.TokenBuffer;
33+
2834
import io.airlift.airline.Arguments;
2935
import io.airlift.airline.Command;
3036
import io.airlift.airline.Option;
@@ -268,35 +274,51 @@ protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDeleg
268274

269275
@Override
270276
public Object deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
271-
TreeNode node = p.readValueAsTree();
272-
JsonNode include = (JsonNode) node.get(INCLUDE);
273277
ObjectMapper codec = (ObjectMapper) ctx.getParser().getCodec();
274-
275-
if (include != null) {
276-
String ref = include.textValue();
277-
if (ref != null) {
278-
File includeFile = scanDir != null ? new File(scanDir, ref) : new File(ref);
279-
if (includeFile.exists()) {
280-
// load the file into the tree node and continue parsing as normal
281-
((ObjectNode) node).remove(INCLUDE);
282-
283-
TreeNode includeNode;
284-
try (JsonParser includeParser = codec.getFactory().createParser(includeFile)) {
285-
includeNode = includeParser.readValueAsTree();
278+
TokenBuffer buffer = new TokenBuffer(p);
279+
280+
recurse(buffer, p, codec, false);
281+
282+
JsonParser newParser = buffer.asParser(codec);
283+
newParser.nextToken();
284+
285+
return super.deserialize(newParser, ctx);
286+
}
287+
288+
private void recurse(TokenBuffer buffer, JsonParser p, ObjectMapper codec, boolean skipOuterbraces) throws IOException {
289+
boolean firstToken = true;
290+
JsonToken token;
291+
292+
while ((token = p.nextToken()) != null) {
293+
String name = p.currentName();
294+
295+
if (skipOuterbraces && firstToken && JsonToken.START_OBJECT.equals(token)) {
296+
continue;
297+
}
298+
299+
if (skipOuterbraces && p.getParsingContext().inRoot() && JsonToken.END_OBJECT.equals(token)) {
300+
continue;
301+
}
302+
303+
if (JsonToken.VALUE_NULL.equals(token)) {
304+
continue;
305+
}
306+
307+
if (name != null && JsonToken.FIELD_NAME.equals(token) && name.startsWith(INCLUDE)) {
308+
p.nextToken();
309+
String fileName = p.getText();
310+
if (fileName != null) {
311+
File includeFile = scanDir != null ? new File(scanDir, fileName) : new File(fileName);
312+
if (includeFile.exists()) {
313+
recurse(buffer, codec.getFactory().createParser(includeFile), codec, true);
286314
}
287-
288-
ObjectReader reader = codec.readerForUpdating(node);
289-
TreeNode updated = reader.readValue(includeNode.traverse());
290-
JsonParser updatedParser = updated.traverse();
291-
updatedParser.nextToken();
292-
return super.deserialize(updatedParser, ctx);
293315
}
316+
} else {
317+
buffer.copyCurrentEvent(p);
294318
}
319+
320+
firstToken = false;
295321
}
296-
297-
JsonParser newParser = node.traverse();
298-
newParser.nextToken();
299-
return super.deserialize(newParser, ctx);
300322
}
301323
}
302324
}

modules/openapi-generator-cli/src/test/java/org/openapitools/codegen/cmd/GenerateBatchTest.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ public class GenerateBatchTest {
2828
private static final String JAXRS_DATELIB_J8_YAML = "jaxrs-datelib-j8.yaml";
2929
private static final String JAXRS_DATELIB_J8_YAML_INCLUDE_JSON = "jaxrs-datelib-j8-yaml-include.json";
3030
private static final String JAXRS_DATELIB_J8_JSON_INCLUDE_YAML = "jaxrs-datelib-j8-json-include.yaml";
31+
private static final String JAXRS_DATELIB_J8_DOUBLE_JSON = "jaxrs-datelib-j8-double.json";
32+
private static final String JAXRS_DATELIB_J8_DOUBLE_YAML = "jaxrs-datelib-j8-double.yaml";
33+
private static final String JAXRS_DATELIB_J8_NESTED_JSON = "jaxrs-datelib-j8-nested.json";
34+
private static final String JAXRS_DATELIB_J8_NESTED_YAML = "jaxrs-datelib-j8-nested.yaml";
35+
private static final String JAXRS_DATELIB_J8_NESTED_PROPERTY_MERGE_YAML = "jaxrs-datelib-j8-nested-property-merge.yaml";
36+
3137
Path workingDirectory;
3238

3339
@BeforeTest
@@ -40,7 +46,12 @@ public Object[][] customIncludeDeserializerFiles() {
4046
return new Object[][] {
4147
{JAXRS_DATELIB_J8_JSON},
4248
{JAXRS_DATELIB_J8_YAML},
43-
{JAXRS_DATELIB_J8_JSON_INCLUDE_YAML}
49+
{JAXRS_DATELIB_J8_JSON_INCLUDE_YAML},
50+
{JAXRS_DATELIB_J8_DOUBLE_JSON},
51+
{JAXRS_DATELIB_J8_DOUBLE_YAML},
52+
{JAXRS_DATELIB_J8_NESTED_JSON},
53+
{JAXRS_DATELIB_J8_NESTED_YAML},
54+
{JAXRS_DATELIB_J8_NESTED_PROPERTY_MERGE_YAML}
4455
};
4556
}
4657

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"!include": "jaxrs-datelib-j8.json",
3+
"!include1": "common/jaxrs-datelib-j8.json"
4+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"!include": jaxrs-datelib-j8.yaml
2+
"!include": common/jaxrs-datelib-j8.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"!include": common/jaxrs-datelib-j8.yaml
3+
generatorName: jaxrs-jersey
4+
# We expect this property to be ignored because it exists in the importing file
5+
outputDir: outputDir-should-be-ignored
6+
inputSpec: batch/specs/petstore.yaml
7+
# This map should be ignored since it exists in the importing file
8+
# We may want to consider merging additionalProperties, but that would depend on user need
9+
additionalProperties:
10+
hideGenerationTimestamp: true
11+
serverPort: 'should-be-ignored'
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"!include": "common/jaxrs-datelib-j8.json",
3+
"generatorName": "jaxrs-jersey",
4+
"outputDir": "outputDir",
5+
"additionalProperties": {
6+
"hideGenerationTimestamp": true,
7+
"serverPort": "8082"
8+
}
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"!include": common/jaxrs-datelib-j8.yaml
3+
generatorName: jaxrs-jersey
4+
outputDir: outputDir
5+
additionalProperties:
6+
hideGenerationTimestamp: true
7+
serverPort: '8082'
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"!include": jaxrs-datelib-j8-nested-include-property-merge.yaml
3+
# We expect this one to "win"
4+
outputDir: outputDir
5+
additionalProperties:
6+
hideGenerationTimestamp: true
7+
serverPort: '8082'
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"!include": "jaxrs-datelib-j8-nested-include.json",
3+
"inputSpec": "batch/specs/petstore.yaml"
4+
}

0 commit comments

Comments
 (0)