Skip to content

Commit b78a66b

Browse files
author
gcornacchia
committed
Merge branch 'release/1.0.1'
Conflicts: pom.xml
2 parents 5d76b0c + a17a62c commit b78a66b

13 files changed

Lines changed: 2195 additions & 30 deletions

File tree

.github/workflows/maven.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3+
4+
name: Java CI with Maven
5+
6+
on:
7+
push:
8+
branches: [ develop ]
9+
pull_request:
10+
branches: [ develop ]
11+
12+
jobs:
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v3
19+
- name: Set up JDK 8
20+
uses: actions/setup-java@v3
21+
with:
22+
java-version: '8'
23+
distribution: 'temurin'
24+
cache: maven
25+
- name: Build with Maven
26+
run: mvn -B package --file pom.xml

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
# CHANGELOG
2+
3+
1.0.1 - 28/04/2022
4+
5+
- removed unused definition in json schema file for each request/response
6+
- issues/4 - fixed npe

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
# OpenAPI2JsonSchema4J
22

33
Maven plugin that converts swagger 2.0 models into self contained json schema files for every request or response.
4+
5+
[![Java CI with Maven](https://github.com/imolainformatica/OpenAPI2JsonSchema4J/actions/workflows/maven.yml/badge.svg?branch=develop)](https://github.com/imolainformatica/OpenAPI2JsonSchema4J/actions/workflows/maven.yml)

pom.xml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns="http://maven.apache.org/POM/4.0.0"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
53
<modelVersion>4.0.0</modelVersion>
64
<groupId>it.imolinfo.maven.plugins</groupId>
75
<artifactId>openapi2jsonschema4j</artifactId>
8-
<version>1.0.0</version>
6+
<version>1.0.1</version>
97
<packaging>maven-plugin</packaging>
108

119
<name>OpenAPI2JsonSchema4J</name>
@@ -308,7 +306,7 @@
308306
<dependency>
309307
<groupId>junit</groupId>
310308
<artifactId>junit</artifactId>
311-
<version>4.12</version>
309+
<version>4.13.1</version>
312310
<scope>test</scope>
313311
</dependency>
314312
<dependency>
@@ -364,7 +362,7 @@
364362
<dependency>
365363
<groupId>com.fasterxml.jackson.core</groupId>
366364
<artifactId>jackson-databind</artifactId>
367-
<version>2.10.3</version>
365+
<version>2.10.5.1</version>
368366
</dependency>
369367

370368
<dependency>
@@ -383,7 +381,7 @@
383381
<dependency>
384382
<groupId>io.swagger</groupId>
385383
<artifactId>swagger-parser</artifactId>
386-
<version>1.0.50</version>
384+
<version>1.0.54</version>
387385
</dependency>
388386

389387
<dependency>

src/main/java/it/imolainformatica/openapi2jsonschema4j/base/BaseJsonSchemaGenerator.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ protected Swagger readFromInterface20(File interfaceFile) {
5353
Path v = entry.getValue();
5454
log.info(k + "=" + v);
5555
for (Operation op : v.getOperations()) {
56-
log.info(" {}", op.getOperationId());
56+
log.info("Operation={}", op.getOperationId());
5757
Optional<Parameter> body = op.getParameters().stream().filter(c -> "body".equalsIgnoreCase(c.getIn()))
5858
.findFirst();
5959
if (body.isPresent()) {
@@ -66,8 +66,13 @@ protected Swagger readFromInterface20(File interfaceFile) {
6666
String rk = entry2.getKey();
6767
Response r = entry2.getValue();
6868
if (r.getResponseSchema() != null) {
69-
messageObjects.add(r.getResponseSchema().getReference());
70-
log.info("code={} responseSchema={}", rk, r.getResponseSchema().getReference());
69+
if (r.getResponseSchema().getReference()!=null) {
70+
messageObjects.add(r.getResponseSchema().getReference());
71+
log.info("code={} responseSchema={}", rk, r.getResponseSchema().getReference());
72+
} else {
73+
log.warn("code={} response schema is not a referenced definition! type={}",rk,r.getResponseSchema().getClass());
74+
}
75+
7176
}
7277
}
7378
}

src/main/java/it/imolainformatica/openapi2jsonschema4j/impl/DraftV4JsonSchemaGenerator.java

Lines changed: 93 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package it.imolainformatica.openapi2jsonschema4j.impl;
22

33
import java.io.File;
4-
import java.util.HashMap;
5-
import java.util.Iterator;
6-
import java.util.Map;
4+
import java.util.*;
75

86
import com.fasterxml.jackson.annotation.JsonInclude.Include;
97
import com.fasterxml.jackson.databind.JsonNode;
@@ -14,15 +12,13 @@
1412
import com.fasterxml.jackson.databind.ser.FilterProvider;
1513
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
1614
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
15+
import com.fasterxml.jackson.databind.ser.std.NullSerializer;
1716
import com.github.fge.jsonschema.core.report.ProcessingReport;
1817
import com.github.fge.jsonschema.main.JsonSchemaFactory;
1918
import com.github.fge.jsonschema.processors.syntax.SyntaxValidator;
2019

21-
import io.swagger.models.AbstractModel;
22-
import io.swagger.models.ArrayModel;
23-
import io.swagger.models.Model;
24-
import io.swagger.models.ModelImpl;
25-
import io.swagger.models.Swagger;
20+
import io.swagger.models.*;
21+
import io.swagger.models.properties.*;
2622
import it.imolainformatica.openapi2jsonschema4j.base.BaseJsonSchemaGenerator;
2723
import it.imolainformatica.openapi2jsonschema4j.base.IJsonSchemaGenerator;
2824
import lombok.extern.slf4j.Slf4j;
@@ -39,14 +35,13 @@ public DraftV4JsonSchemaGenerator(boolean strict) {
3935
private Map<String, JsonNode> generateForObjects() throws Exception {
4036
for (String ref : getMessageObjects()) {
4137
String title = ref.replace(DEFINITIONS2, "");
42-
log.info("title={}", title);
4338
Map<String, Object> defs = (Map<String, Object>) ((HashMap<String, Model>) getObjectsDefinitions()).clone();
4439
AbstractModel ob = (AbstractModel) defs.get(title);
4540
defs.remove(title);
4641
Map<String, Object> res = new HashMap<String, Object>();
4742
res.put(DEFINITIONS, defs);
4843
res.put(TITLE2, title);
49-
44+
log.info("Generating json schema for object '{}' of type {}", title,ob.getClass());
5045
if (ob instanceof ModelImpl) {
5146
res.put(TYPE, ((ModelImpl) ob).getType());
5247
res.put(PROPERTIES, ob.getProperties());
@@ -65,12 +60,100 @@ private Map<String, JsonNode> generateForObjects() throws Exception {
6560
res.put(MAX_ITEMS, ((ArrayModel) ob).getMaxItems());
6661
}
6762
res.put($SCHEMA, HTTP_JSON_SCHEMA_ORG_DRAFT_04_SCHEMA);
63+
removeUnusedObject(res,ob);
6864
getGeneratedObjects().put(title, postprocess(res));
6965
}
7066
return getGeneratedObjects();
7167

7268
}
7369

70+
private void removeUnusedObject(Map<String, Object> res, AbstractModel ob) {
71+
log.info("Removing unused definition for '{}'",res.get(TITLE2));
72+
List<String> usedDefinition = new ArrayList<>();
73+
navigateModel((String)res.get(TITLE2),usedDefinition,res,ob);
74+
log.info("Used Object = {}",usedDefinition);
75+
List<String> tbdeleted = new ArrayList<>();
76+
for (String key : ((Map<String,Object>)res.get(DEFINITIONS)).keySet()) {
77+
if (!usedDefinition.contains(key)){
78+
log.debug("Removing definition for object {}",key);
79+
tbdeleted.add(key);
80+
} else {
81+
log.debug("Object {} is used!",key);
82+
}
83+
}
84+
for (String del : tbdeleted){
85+
((Map<String,Object>)res.get(DEFINITIONS)).remove(del);
86+
}
87+
}
88+
89+
private void navigateModel(String originalRef, List<String> usedDefinition, Map<String, Object> res, Object ob) {
90+
log.debug("Analyzing ref {} object={}",originalRef,ob);
91+
String objectName=originalRef.replace(DEFINITIONS2,"");
92+
if (ob==null){
93+
ob = ((Map) res.get(DEFINITIONS)).get(objectName);
94+
}
95+
log.debug("Analyzing object {} {}",ob,originalRef);
96+
if (usedDefinition.contains(objectName)){
97+
log.info("Found circular reference for object {}!",objectName);
98+
return;
99+
}
100+
usedDefinition.add(objectName);
101+
if (ob instanceof ModelImpl) {
102+
ModelImpl mi = (ModelImpl)ob;
103+
Map<String, Property> m = mi.getProperties();
104+
log.debug("properties={}",m);
105+
if (m!=null) {
106+
for (String name : m.keySet()) {
107+
navigateProperty(name, m.get(name), usedDefinition, res);
108+
}
109+
}
110+
} else if (ob instanceof ArrayModel) {
111+
log.debug("array model={}",res.get(ITEMS));
112+
if (res.get(ITEMS) instanceof RefProperty) {
113+
navigateModel(((RefProperty)((RefProperty)res.get(ITEMS))).getOriginalRef(),usedDefinition,res,null);
114+
}
115+
} else if (ob instanceof ComposedModel) {
116+
ComposedModel cm = (ComposedModel)ob;
117+
for (Model m : cm.getAllOf()) {
118+
navigateModel(m.getReference(), usedDefinition,res,null);
119+
}
120+
121+
} else if (ob instanceof RefModel) {
122+
RefModel rm = (RefModel)ob;
123+
Map<String, Property> m = rm.getProperties();
124+
log.debug("properties={}",m);
125+
if (m!=null) {
126+
for (String name : m.keySet()) {
127+
navigateProperty(name, m.get(name), usedDefinition, res);
128+
}
129+
}
130+
131+
} else {
132+
throw new RuntimeException(ob.getClass()+" not handled!");
133+
}
134+
}
135+
136+
private void navigateProperty(String propertyName, Property p,List<String> usedDefinition,Map<String, Object> res){
137+
log.debug("property name '{}' of type {}",propertyName,p);
138+
if (p instanceof RefProperty) {
139+
navigateModel(((RefProperty)((RefProperty) p)).getOriginalRef(),usedDefinition,res,null);
140+
} else if (p instanceof ArrayProperty) {
141+
ArrayProperty ap = (ArrayProperty) p;
142+
log.debug("Array property={} items={}",ap,ap.getItems());
143+
navigateProperty("items",ap.getItems(),usedDefinition,res);
144+
} else if (p instanceof ObjectProperty){
145+
ObjectProperty op = (ObjectProperty) p;
146+
for (String name : op.getProperties().keySet()){
147+
navigateProperty(name,op.getProperties().get(name),usedDefinition,res);
148+
}
149+
} else if (p instanceof MapProperty) {
150+
MapProperty mp = (MapProperty)p;
151+
navigateProperty(mp.getName(),mp.getAdditionalProperties(),usedDefinition,res);
152+
} else {
153+
log.debug(p.getClass() + " - nothing to do!");
154+
}
155+
}
156+
74157
private JsonNode postprocess(Map<String, Object> res) throws Exception {
75158
ObjectMapper mapper = new ObjectMapper();
76159
mapper.setSerializationInclusion(Include.NON_NULL);

src/test/java/it/imolainformatica/openapi2jsonschema4j/test/TestGeneration.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,33 @@ public class TestGeneration extends AbstractIT{
4141
public void testPetStoreWithStrict() {
4242
testForSwagger("petstore.json");
4343
}
44+
45+
@Test
46+
public void testPetStoreWithStrictAndDateFormatAndPattern() {
47+
testForSwagger("petstoreDateFormat.json");
48+
}
4449

45-
/*@Test
46-
public void testDefaultSwaggerYamlWithStrict() {
47-
testForSwagger("APIAC_AnagrafeClientiAPI_v1.0.yaml");
48-
}*/
50+
@Test
51+
public void testSwaggerWithoutBody() {
52+
testForSwagger("petstoreNoBody.json");
53+
}
4954

5055
private void testForSwagger(String swaggerFile) {
51-
log.info("Test for swagger {}",swaggerFile);
56+
log.info("Test for swagger {}", swaggerFile);
5257
File f = loadFromResourceFile(swaggerFile);
5358
IJsonSchemaGenerator jsg = new JsonSchemaGeneratorBuilder().withOutputSchemaVersion(JsonSchemaVersion.DRAFT_V4).withStrictGeneration(true).build();
5459
try {
5560
Map<String, JsonNode> gen = jsg.generate(f);
56-
new JsonSchemaOutputWriter().saveJsonSchemaFiles(gen,new File("target/generatedJsonSchema"));
57-
testGeneratedJsonSchema(f,gen);
61+
new JsonSchemaOutputWriter().saveJsonSchemaFiles(gen, new File("target/generatedJsonSchema/"+swaggerFile));
62+
testGeneratedJsonSchema(f, gen);
5863
} catch (Exception e) {
64+
log.error("Unexpected exception" + e.getMessage(), e);
5965
fail("Unexpected exception");
60-
log.error("Unexpected exception"+e.getMessage(),e);
66+
6167
}
6268
}
6369

70+
6471
private void testGeneratedJsonSchema(File f, Map<String, JsonNode> gen) throws ProcessingException, IOException {
6572
Swagger swagger = new SwaggerParser().read(f.getAbsolutePath());
6673
Map<String, Model> definitions = swagger.getDefinitions();

0 commit comments

Comments
 (0)