Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.zuunr.openapi.OpenApiUnionMaker Maven / Gradle / Ivy
/*
* Copyright 2020 Zuunr AB
*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law 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 com.zuunr.openapi;
import java.util.Iterator;
import com.zuunr.forms.Form;
import com.zuunr.forms.FormFields;
import com.zuunr.forms.util.JsonValuePathsFinder;
import com.zuunr.json.JsonArray;
import com.zuunr.json.JsonArrayBuilder;
import com.zuunr.json.JsonObject;
import com.zuunr.json.JsonObjectBuilder;
import com.zuunr.json.JsonValue;
import com.zuunr.jsonschema.JsonSchemaMerger;
/**
* @author Niklas Eldberger
*/
public class OpenApiUnionMaker {
private final JsonSchemaMerger jsonSchemaMerger = JsonSchemaMerger.OPENAPI_3_0_STYLE;
private final JsonValuePathsFinder pathsFinder = new JsonValuePathsFinder();
private final OpenApiSchemaConverter openApiSchemaConverter = new OpenApiSchemaConverter();
private final OpenApiUtil openApiUtil = new OpenApiUtil();
private JsonArray openApiParameters(JsonValue parametersJsonSchema, JsonArray parameters) {
JsonArrayBuilder builder = JsonArray.EMPTY.builder();
for (JsonValue parameterJsonValue : parameters) {
JsonObject parameter = parameterJsonValue.getValue(JsonObject.class);
String in = parameter.get("in").getString();
String parameterName = parameter.get("name").getString();
JsonValue parameterTypeSchema = parametersJsonSchema.get("properties").get(in);
if (!parameterTypeSchema.is(Boolean.class) &&
!parameterTypeSchema.get("properties").get(parameterName).is(Boolean.class)) {
boolean required = parameterTypeSchema.get("required", JsonArray.EMPTY).getValue(JsonArray.class).contains(parameterName);
builder.add(parameter
.put("schema", parameterTypeSchema.get("properties").get(parameterName))
.put("required", required));
}
}
return builder.build();
}
public JsonObject getRequestBodySchemaPaths(JsonObject jsonSchemaDoc) {
JsonArray pathsPattern = JsonArray.EMPTY
.add("paths")
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
.add("requestBody")
.add("content")
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
.add("schema");
return getPathsAndValuesPerPath(pathsPattern, jsonSchemaDoc);
}
public JsonObject getPathsAndValuesPerPath(JsonArray pathsPattern, JsonObject jsonSchemaDoc) {
JsonObjectBuilder schemaPerPath = JsonObject.EMPTY.builder();
JsonArray paths = pathsFinder.getPaths(jsonSchemaDoc.jsonValue(), pathsPattern, true);
for (JsonValue path : paths) {
schemaPerPath.put(path.getValue(JsonArray.class).allButLast().asJson(), path.getValue(JsonArray.class));
}
return schemaPerPath.build();
}
public JsonObject getResponseBodySchemaPaths(JsonObject jsonSchemaDoc) {
JsonObjectBuilder schemaPerPath = JsonObject.EMPTY.builder();
JsonArray pathsPattern = JsonArray.EMPTY
.add("paths")
// path template
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
// method
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
.add("responses")
// status code
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
.add("content")
// content type
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
.add("schema");
JsonArray paths = pathsFinder.getPaths(jsonSchemaDoc.jsonValue(), pathsPattern, true);
for (JsonValue path : paths) {
schemaPerPath.put(path.getValue(JsonArray.class).allButLast().asJson(), path.getValue(JsonArray.class));
}
return schemaPerPath.build();
}
public JsonArray pathAndMethodPlusValue(JsonObject jsonSchemaDoc) {
JsonArray pathsPattern = JsonArray.EMPTY
.add("paths")
// path template
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
// method
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()));
JsonArray paths = pathsFinder.getPaths(jsonSchemaDoc.jsonValue(), pathsPattern, true);
return paths;
}
public JsonObject pathAndMethodAndValuePerPathAndMethod(JsonObject jsonSchemaDoc) {
JsonObject result = JsonObject.EMPTY;
for (JsonValue jsonValue : pathAndMethodPlusValue(jsonSchemaDoc)) {
result = result.put(jsonValue.getValue(JsonArray.class).subArray(0, 3).asJson(), jsonValue);
}
return result;
}
public JsonObject unionOf(JsonObject jsonSchemaDoc1, JsonObject jsonSchemaDoc2) {
JsonObject result = jsonSchemaDoc1.put("paths", JsonObject.EMPTY); // defaults to empty
JsonObject pathsObject1 = pathAndMethodAndValuePerPathAndMethod(jsonSchemaDoc1);
JsonObject pathsObject2 = pathAndMethodAndValuePerPathAndMethod(jsonSchemaDoc2);
Iterator valuesIter = pathsObject1.values().iterator();
for (String path : pathsObject1.keys().asList(String.class)) {
JsonArray pathAndValue2 = pathsObject2.get(path, JsonValue.NULL).getValue(JsonArray.class);
if (pathAndValue2 == null) {
// continue;
}
JsonArray pathAndValue1 = valuesIter.next().getValue(JsonArray.class);
JsonObject resultOfUpdate = updatePath(pathAndValue1, pathAndValue2, result);
if (resultOfUpdate != null) {
result = resultOfUpdate;
}
}
return result;
}
private JsonObject updatePath(JsonArray pathAndValue1, JsonArray pathAndValue2, JsonObject resultSoFar) {
String method = pathAndValue1.get(2).getString();
JsonObject originalPerMethodSpec1 = pathAndValue1.last().getValue(JsonObject.class);
JsonObject originalPerMethodSpec2 = pathAndValue2.last().getValue(JsonObject.class);
JsonObject perMethodSpec = originalPerMethodSpec1
.remove("parameters")
.remove("requestBody")
.remove("responses");
//merge parameters
JsonArray parameters1 = originalPerMethodSpec1.get("parameters", JsonArray.EMPTY).getValue(JsonArray.class);
JsonArray parameters2 = originalPerMethodSpec2.get("parameters", JsonArray.EMPTY).getValue(JsonArray.class);
JsonArray allParameters = null;
JsonObjectBuilder builder = JsonObject.EMPTY.builder();
for (JsonValue param: parameters1) {
builder.put(param.get("in").getString()+"."+param.get("name"), param);
}
for (JsonValue param: parameters2) {
builder.put(param.get("in").getString()+"."+param.get("name"), param);
}
allParameters = builder.build().values();
JsonValue mergedSchema = null;
if (parameters1.isEmpty()) {
mergedSchema = openApiUtil.openApiParametersAsJsonObjectSchema(parameters2).jsonValue();
} else if (parameters2.isEmpty()) {
mergedSchema = openApiUtil.openApiParametersAsJsonObjectSchema(parameters1).jsonValue();
} else {
JsonObject parametersJsonSchema1 = openApiUtil.openApiParametersAsJsonObjectSchema(parameters1);
JsonObject parametersJsonSchema2 = openApiUtil.openApiParametersAsJsonObjectSchema(parameters2);
mergedSchema = jsonSchemaMerger.unionOf(parametersJsonSchema1.jsonValue(), parametersJsonSchema2.jsonValue());
}
perMethodSpec = perMethodSpec.put("parameters", openApiParameters(mergedSchema, allParameters));
// Request body
if (mayHaveRequestBody(method)) {
JsonArray requestBodyPathsAndSchemas = requestBodies(originalPerMethodSpec1, pathAndValue2.last().getValue(JsonObject.class));
for (JsonValue pathAndSchemaJsonValue : requestBodyPathsAndSchemas) {
perMethodSpec = perMethodSpec.put(pathAndSchemaJsonValue.getValue(JsonArray.class).allButLast(), pathAndSchemaJsonValue.getValue(JsonArray.class).last());
}
if (perMethodSpec.get("requestBody") == null) {
// return null; // This method for this URL path is not possible to call
}
}
// Responses
for (JsonValue pathAndSchemaJsonValue : responses(originalPerMethodSpec1, pathAndValue2.last().getValue(JsonObject.class))) {
JsonArray pathToDescriptionOfStatusCode = pathAndSchemaJsonValue.getValue(JsonArray.class).subArray(0, 2).add("description");
perMethodSpec = perMethodSpec
.put(pathAndSchemaJsonValue.getValue(JsonArray.class).allButLast(), pathAndSchemaJsonValue.getValue(JsonArray.class).last());
JsonValue description = originalPerMethodSpec1.get(pathToDescriptionOfStatusCode);
if (description != null) {
perMethodSpec = perMethodSpec.put(pathToDescriptionOfStatusCode, description);
}
}
JsonObject defaultResponses = perMethodSpec.get(JsonArray.of("responses", "default"), JsonObject.EMPTY.put("description", "")).getValue(JsonObject.class);
perMethodSpec = perMethodSpec.put(JsonArray.of("responses", "default"), defaultResponses);
resultSoFar = resultSoFar.put(pathAndValue1.allButLast(), perMethodSpec);
return resultSoFar;
}
private boolean mayHaveRequestBody(String method) {
return method.equals("post") || method.equals("patch") || method.equals("put");
}
private JsonArray requestBodies(JsonObject perMethodSpec1, JsonObject perMethodSpec2) {
JsonArray responsesBodyPathsPattern = JsonArray.EMPTY
.add("requestBody")
.add("content")
// content type
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
.add("schema");
return methodSpecPathsAndSchemas(perMethodSpec1, perMethodSpec2, responsesBodyPathsPattern, true);
}
private JsonArray responses(JsonObject perMethodSpec1, JsonObject perMethodSpec2) {
JsonArray responsesBodyPathsPattern = JsonArray.EMPTY
.add("responses")
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
.add("content")
// content type
.add(JsonObject.EMPTY
.put("objectFormat", Form.EMPTY.builder()
.exclusive(false)
.value(FormFields.EMPTY)
.build()))
.add("schema");
return methodSpecPathsAndSchemas(perMethodSpec1, perMethodSpec2, responsesBodyPathsPattern, false);
}
private JsonArray methodSpecPathsAndSchemas(JsonObject perMethodSpec1, JsonObject perMethodSpec2, JsonArray perMethodPathPattern, boolean simplifyAlwaysFailingSchema) {
JsonArrayBuilder perMethodSpecPathAndValues = JsonArray.EMPTY.builder(); // ['responses', '200', 'content', 'application/json', 'schema', {jsonSchema}]
JsonArray responsesSchemaPaths1 = pathsFinder.getPaths(perMethodSpec1.jsonValue(), perMethodPathPattern, true);
JsonArray responsesSchemaPaths2 = pathsFinder.getPaths(perMethodSpec2.jsonValue(), perMethodPathPattern, true);
JsonObjectBuilder perResponseContentPathBuilder2 = JsonObject.EMPTY.builder();
for (JsonValue schemaPath2 : responsesSchemaPaths2) {
perResponseContentPathBuilder2.put(schemaPath2.getValue(JsonArray.class).allButLast().asJson(), schemaPath2);
}
JsonObject perResponseContentPath2 = perResponseContentPathBuilder2.build();
for (JsonValue schemaPath1 : responsesSchemaPaths1) {
JsonArray responsesContentPath = schemaPath1.getValue(JsonArray.class).allButLast();
JsonValue schemaPath2 = perResponseContentPath2.get(responsesContentPath.asJson());
if (schemaPath2 == null) {
// FIXME Why was continue removed?
//continue;
throw new IllegalStateException("schemaPath is null");
}
JsonObject openApiSchema1 = schemaPath1.getValue(JsonArray.class).last().getValue(JsonObject.class);
JsonObject openApiSchema2 = schemaPath2.getValue(JsonArray.class).last().getValue(JsonObject.class);
JsonValue schema1 = openApiSchemaConverter.toJsonSchema(openApiSchema1);
JsonValue schema2 = openApiSchemaConverter.toJsonSchema(openApiSchema2);
JsonValue mergedJsonSchema = jsonSchemaMerger.unionOf(schema1, schema2);
perMethodSpecPathAndValues.add(responsesContentPath.add(mergedJsonSchema));
}
return perMethodSpecPathAndValues.build();
}
}