Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/typeobject #13

Merged
merged 13 commits into from
Dec 4, 2024
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
2 changes: 1 addition & 1 deletion .github/badges/branches.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion .github/badges/jacoco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ target
.classpath
.project
.settings
/log
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,48 @@ protected void readFromInterface(File interfaceFile) {
SwaggerParseResult result = new OpenAPIParser().readLocation(interfaceFile.getAbsolutePath(),null,po);
OpenAPI swagger = result.getOpenAPI();
Validate.notNull(swagger,"Error during parsing of interface file "+interfaceFile.getAbsolutePath());

if (swagger.getComponents() != null && swagger.getComponents().getSchemas() != null) {
objectsDefinitions = swagger.getComponents().getSchemas();
}
for (Map.Entry<String, PathItem> entry : swagger.getPaths().entrySet()) {
for (Map.Entry<String, Schema> entry : objectsDefinitions.entrySet()){
if ( entry.getValue().getClass().equals(io.swagger.v3.oas.models.media.Schema.class)
&& entry.getValue().getType()==null && entry.getValue().getProperties()!=null ){ // va generato un ObjectSchema dove qui c'è invece uno Schema
ObjectSchema newObjectSchema = createObjectSchemaFromSchema(entry.getValue());
log.info("Conversion to ObjectSchema for type {}", entry.getKey());
objectsDefinitions.put(entry.getKey(), newObjectSchema); // man mano che scorre le key, sovrascrive il value
}
}
for (Map.Entry<String, PathItem> entry : swagger.getPaths().entrySet()) { // todo qui se type object è assente occorre gestire come sopra
String k = entry.getKey();
PathItem v = entry.getValue();
analyzeOperation(v);
}
}

private ObjectSchema createObjectSchemaFromSchema(Schema schema) {
ObjectSchema objectSchema = new ObjectSchema();
// Copia delle proprietà generali
objectSchema.setTitle(schema.getTitle());
objectSchema.setDescription(schema.getDescription());
objectSchema.setDefault(schema.getDefault());
objectSchema.setExample(schema.getExample());
objectSchema.setNullable(schema.getNullable());
objectSchema.setDeprecated(schema.getDeprecated());
objectSchema.setReadOnly(schema.getReadOnly());
objectSchema.setWriteOnly(schema.getWriteOnly());
objectSchema.setRequired(schema.getRequired());
objectSchema.setFormat(schema.getFormat());
objectSchema.setExtensions(schema.getExtensions());
objectSchema.setAdditionalProperties(schema.getAdditionalProperties());

// Copia delle proprietà specifiche per ObjectSchema
objectSchema.setProperties(schema.getProperties());
objectSchema.setDiscriminator(schema.getDiscriminator());
objectSchema.setAdditionalProperties(schema.getAdditionalProperties());
return objectSchema;
}

private void analyzeOperation(PathItem v) {
for (Operation op : v.readOperations()) {
log.info("Operation={}", op.getOperationId());
Expand All @@ -80,7 +112,12 @@ private void analyzeOperation(PathItem v) {
log.warn("code={} response schema is not a referenced definition! type={}", key, r.getContent().get("application/json").getClass());
log.debug("Reference not found, creating it manually");
String inlineObjectKey = createInlineResponseObjectKey(op,key);
objectsDefinitions.put(inlineObjectKey, sc);
if (sc.getType() == null && sc.getProperties()!=null) {
ObjectSchema newObjectSchema = createObjectSchemaFromSchema(sc);
r.getContent().get(APPLICATION_JSON).setSchema(newObjectSchema);
objectsDefinitions.put(inlineObjectKey, newObjectSchema);
} else
objectsDefinitions.put(inlineObjectKey, sc);
messageObjects.add(inlineObjectKey);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ private void navigateModel(String originalRef, List<String> usedDefinition, Map<
Schema s = (Schema) res.get(ITEMS);
if (s.get$ref()!=null) {
navigateModel(s.get$ref(), usedDefinition, res, null);
} else if (s instanceof ComposedSchema) {
ComposedSchema cm = (ComposedSchema)s;
lookComposedModel(cm.getAllOf(),usedDefinition,res);
lookComposedModel(cm.getAnyOf(),usedDefinition,res);
lookComposedModel(cm.getOneOf(),usedDefinition,res);
if (cm.getNot()!=null) {
navigateModel(cm.getNot().get$ref(), usedDefinition, res, null);
}
}
}
} else if (ob instanceof ComposedSchema) {
Expand Down Expand Up @@ -239,6 +247,15 @@ private void navigateSchema(String propertyName, Schema p, List<String> usedDefi
if (mp.getAdditionalProperties() instanceof Schema ) {
navigateSchema(mp.getName(), (Schema)mp.getAdditionalProperties(), usedDefinition, res);
}
} else if (p instanceof ComposedSchema){
ComposedSchema cm = (ComposedSchema)p;
lookComposedModel(cm.getAllOf(),usedDefinition,res);
lookComposedModel(cm.getAnyOf(),usedDefinition,res);
lookComposedModel(cm.getOneOf(),usedDefinition,res);
if (cm.getNot()!=null) {
navigateModel(cm.getNot().get$ref(), usedDefinition, res, null);
}

} else {
log.debug(p.getClass() + " - nothing to do!");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package it.imolainformatica.openapi2jsonschema4j.base;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
Expand Down Expand Up @@ -32,37 +33,37 @@
import org.json.JSONException;
import org.json.JSONObject;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;

@Slf4j
public class AbstractIT {


protected File loadFromResourceFile(String resourceName) {
log.debug("loading resource {}",resourceName);
File file = new File(
return new File(
getClass().getClassLoader().getResource(resourceName).getFile()
);
return file;

}

protected void testForSwagger(String swaggerFile) {
log.info("Test for swagger {}", swaggerFile);
File f = loadFromResourceFile(swaggerFile);
IJsonSchemaGenerator jsg = new JsonSchemaGeneratorBuilder().withOutputSchemaVersion(JsonSchemaVersion.DRAFT_V4).withStrictGeneration(true).build();
log.info("Test for swagger {}", swaggerFile);
File resourceFile = loadFromResourceFile(swaggerFile);
log.info("Test for resourcefile appenacaricatodalloswagger {}", resourceFile);
try {
Map<String, JsonNode> gen = jsg.generate(f);
Map<String, JsonNode> generatedSchema = jsg.generate(resourceFile);
log.info("Confronto file generatedSchema QUELLOAPPENAGENERATOEDAFIXARE : {}", generatedSchema);
// salva e valida il jsonschema prodotto
File outputJsonSchemaFolder = new File("target/generatedJsonSchema/"+swaggerFile);
new JsonSchemaOutputWriter().saveJsonSchemaFiles(gen,outputJsonSchemaFolder);
testGeneratedJsonSchema(f, gen);
new JsonSchemaOutputWriter().saveJsonSchemaFiles(generatedSchema,outputJsonSchemaFolder);
testGeneratedJsonSchema(resourceFile, generatedSchema);
// confronta i json generato con atteso
File expectedJsonSchemaFolder = loadFromResourceFile("expectedJsonSchemas/"+swaggerFile);
compareJsonFolders(outputJsonSchemaFolder, expectedJsonSchemaFolder);
} catch (Exception e) {
log.error("Unexpected exception" + e.getMessage(), e);
fail("Unexpected exception");

}
}

Expand Down Expand Up @@ -96,14 +97,14 @@ private void testGeneratedJsonSchema(File f, Map<String, JsonNode> gen) throws P
//Validation on example is possible only if components are defined inside the swagger file
ProcessingReport rep = jsonSchema.validate(new ObjectMapper().readTree(jsonExample));
log.info("processing report for model {} = {}",objName,rep);
Assert.assertTrue("Il json generato non è valido in base al json schema per l'oggetto "+objName, rep.isSuccess());
assertTrue("Il json generato non è valido in base al json schema per l'oggetto "+objName, rep.isSuccess());
}
}
}

private void validateJsonSchemaSyntax(SyntaxValidator syntaxValidator, JsonNode node) {
ProcessingReport rep = syntaxValidator.validateSchema(node);
Assert.assertTrue(rep.isSuccess());
assertTrue(rep.isSuccess());
}

// Ottiene una mappa di file JSON (nome file -> percorso) in una cartella
Expand All @@ -121,7 +122,7 @@ private static boolean areJsonObjectsEqual(JSONObject json1, JSONObject json2) {
}

private static void compareJsonFolders(File outputJsonSchemaFolder, File expectedJsonSchemaFolder) throws IOException, JSONException {
log.info("Confronto tra cartelle {} e {}",outputJsonSchemaFolder,expectedJsonSchemaFolder);
log.info("Confronto tra cartelle output {} e expected {}",outputJsonSchemaFolder,expectedJsonSchemaFolder);
// Verifica che entrambi i percorsi siano effettivamente cartelle
if (!outputJsonSchemaFolder.isDirectory() || !expectedJsonSchemaFolder.isDirectory()) {
throw new IllegalArgumentException("Entrambi i percorsi devono essere delle cartelle.");
Expand All @@ -130,16 +131,25 @@ private static void compareJsonFolders(File outputJsonSchemaFolder, File expecte
// Ottieni i file JSON in entrambe le cartelle
Map<String, Path> filesInFolder1 = getJsonFilesMap(outputJsonSchemaFolder);
Map<String, Path> filesInFolder2 = getJsonFilesMap(expectedJsonSchemaFolder);
assertTrue(filesInFolder1.size() == filesInFolder2.size());
assertTrue(filesInFolder1.keySet().equals(filesInFolder2.keySet()));
log.info("loooog filesInFolder1.size() "+ filesInFolder1.size());
log.info("loooog filesInFolder2.size() "+ filesInFolder2.size());

assertEquals(filesInFolder1.size() , filesInFolder2.size());
assertEquals(filesInFolder1.keySet(),filesInFolder2.keySet());
// Confronta il contenuto di ogni file
for (String fileName : filesInFolder1.keySet()) {
log.info("Confronto file {}", fileName);
JSONObject json1 = new JSONObject(Files.readString(filesInFolder1.get(fileName)));
JSONObject json2 = new JSONObject(Files.readString(filesInFolder2.get(fileName)));
JSONObject json1 = new JSONObject(readString(filesInFolder1.get(fileName)));
JSONObject json2 = new JSONObject(readString(filesInFolder2.get(fileName)));
log.debug("loooog file1 "+json1);
log.debug("loooog file2 "+json2);
assertTrue("I file "+fileName+" non sono uguali",areJsonObjectsEqual(json1, json2));
}

assertTrue(true);
}

private static String readString(Path path) throws IOException {
return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,16 @@ public class TestGenerationFromOAS3 extends AbstractIT {

@Test
public void testOAS3WithAllOf() { testForSwagger("petstoreoas3Allof.json"); }
@Test
public void testOAS3WithAllOfNoTypeObject() { testForSwagger("petstoreoas3AllofNoTypeObject.json"); }

@Test
public void testOAS3WithInlineArray() { testForSwagger("petstoreoas3ArrayInline.json"); }
@Test
public void testOAS3WithNoTypeObject() { testForSwagger("petstoreoas3NoTypeObject.json"); }

@Test
public void testOAS3WithNoArrayInlineAndAllOf() { testForSwagger("petstoreoas3ArrayAllofInline.json"); }


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"components" : {
"schemas" : { }
},
"$schema" : "http://json-schema.org/draft-04/schema#",
"additionalProperties" : false,
"title" : "ApiResponse",
"type" : "object",
"properties" : {
"code" : {
"type" : "integer",
"format" : "int32"
},
"type" : {
"type" : "string"
},
"message" : {
"type" : "string"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"allOf" : [ {
"$ref" : "#/components/schemas/CatNotFound"
}, {
"type" : "object",
"properties" : {
"name" : {
"maxLength" : 8,
"type" : "string",
"types" : [ "string" ]
}
},
"additionalProperties" : false,
"types" : [ "object" ]
} ],
"components" : {
"schemas" : {
"CatNotFound" : {
"required" : [ "code", "message" ],
"type" : "object",
"properties" : {
"code" : {
"type" : "string",
"enum" : [ "CatNotFound" ]
},
"message" : {
"type" : "string",
"enum" : [ "Resource has not been found" ]
}
},
"additionalProperties" : false
}
}
},
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "CatOrDogNotFound"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"components" : {
"schemas" : {
"User" : {
"type" : "object",
"properties" : {
"id" : {
"type" : "integer",
"format" : "int64"
},
"username" : {
"type" : "string"
},
"firstName" : {
"type" : [ "string", "null" ]
},
"lastName" : {
"type" : "string"
},
"email" : {
"type" : "string"
},
"password" : {
"type" : "string"
},
"phone" : {
"type" : "string"
},
"userStatus" : {
"type" : "integer",
"description" : "User Status",
"format" : "int32"
}
},
"additionalProperties" : false
}
}
},
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "createUsersWithListInputrequest",
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/User"
}
}
Loading