Skip to content
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ buildNumber.properties
.classpath
.project
/bin/
/.idea
41 changes: 33 additions & 8 deletions src/main/java/com/github/davidmoten/oas3/internal/Common.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,15 @@ static Model toModelClass(String name, Schema<?> schema, Names names, ClassType
associationType, names);
}
}
fields.add(createFieldWithInfo(entry.getKey(), property, property.endsWith("]"),
required.contains(entry.getKey()), entry.getValue()));
} else if (sch.get$ref() != null) {
String ref = sch.get$ref();
String otherClassName = names.refToClassName(ref).className();
addToOne(relationships, name, otherClassName, property,
required.contains(entry.getKey()), false);
fields.add(createFieldWithInfo(entry.getKey(), otherClassName, otherClassName.endsWith("]"),
required.contains(entry.getKey()), entry.getValue()));
} else {
Optional<String> t = getUmlTypeName(sch, names);
if (t.isPresent()) {
Expand Down Expand Up @@ -146,13 +150,15 @@ static Model toModelClass(String name, Schema<?> schema, Names names, ClassType
String valueClassName = names.refToClassName(valueSchema.get$ref()).className();
addToOne(relationships, keyClassName, valueClassName, "value", true, false);
} else {
fields.add(new Field(entry.getKey(), "string -> string", type.endsWith("]"),
true));
type = "string -> string";
// fields.add(new Field(entry.getKey(), "string -> string", type.endsWith("]"),
// true));
}
} else {
fields.add(new Field(entry.getKey(), type, type.endsWith("]"),
required.contains(entry.getKey())));
}
//else {
fields.add(createFieldWithInfo(entry.getKey(), type, type.endsWith("]"),
required.contains(entry.getKey()), entry.getValue()));
//}
}
}
});
Expand Down Expand Up @@ -180,10 +186,10 @@ static Model toModelClass(String name, Schema<?> schema, Names names, ClassType
&& !isEmpty(schema.getEnum())) {
isEnum = true;
for (Object item: schema.getEnum()) {
fields.add(new Field(item.toString(), type, false, false));
fields.add(createFieldWithInfo(item.toString(), type, false, false, schema));
}
} else {
fields.add(new Field("value", type, type.endsWith("]"), true));
fields.add(createFieldWithInfo("value", type, type.endsWith("]"), true, schema));
}
}
}
Expand Down Expand Up @@ -324,7 +330,7 @@ static Optional<String> getUmlTypeName(String ref, Schema<?> schema, Names names
} else if (schema instanceof ArraySchema) {
ArraySchema a = (ArraySchema) schema;
type = getUmlTypeName(a.getItems(), names) //
.orElseThrow(() -> new RuntimeException("unexpected")) + "[]";
.orElse("object") + "[]";
} else if (schema instanceof BinarySchema) {
type = "byte[]";
} else if (schema instanceof ByteArraySchema) {
Expand Down Expand Up @@ -356,4 +362,23 @@ static Optional<String> getUmlTypeName(String ref, Schema<?> schema, Names names
return Optional.ofNullable(type);
}

private static Field createFieldWithInfo(String name, String type, boolean isArray, boolean required,
Schema<?> schema) {
int maxLength = -1;
String description = null;
String example = null;
String format = null;
String extension = null;
if (schema != null) {
maxLength = Optional.ofNullable(schema.getMaxLength()).orElse(-1);
description = schema.getDescription();
example = schema.getExample() == null ? null : schema.getExample().toString();
format = schema.getFormat();
if (schema.getExtensions() != null) {
extension = schema.getExtensions().toString();
}
}
return new Field(name, type, isArray, required, maxLength, description, example, format, extension);
}

}
39 changes: 39 additions & 0 deletions src/main/java/com/github/davidmoten/oas3/internal/model/Field.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ public final class Field {
private final String type;
private final boolean isArray;
private final boolean required;
private int maxLength;
private String description;
private String example;
private String format;
private String extension;


public Field(String name, String type, boolean isArray, boolean required) {
this.name = name;
Expand All @@ -15,6 +21,19 @@ public Field(String name, String type, boolean isArray, boolean required) {
this.required = required;
}

public Field(String name, String type, boolean isArray, boolean required, int maxLength,
String description, String example, String format, String extension) {
this.name = name;
this.type = type;
this.isArray = isArray;
this.required = required;
this.maxLength = maxLength;
this.description = description;
this.example = example;
this.format = format;
this.extension = extension;
}

public String name() {
return name;
}
Expand All @@ -31,6 +50,26 @@ public boolean isRequired() {
return required;
}

public int maxLength() {
return maxLength;
}

public String description() {
return description;
}

public String example() {
return example;
}

public String format() {
return format;
}

public String extension() {
return extension;
}

@Override
public String toString() {
StringBuilder b = new StringBuilder();
Expand Down
64 changes: 46 additions & 18 deletions src/main/java/com/github/davidmoten/oas3/puml/Converter.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,25 @@ private Converter() {
// prevent instantiation
}

public static String openApiToPuml(InputStream in) throws IOException {
return openApiToPuml(IOUtils.toString(in, StandardCharsets.UTF_8));
public static String openApiToPuml(InputStream in, boolean showNote) throws IOException {
return openApiToPuml(IOUtils.toString(in, StandardCharsets.UTF_8), showNote);
}

public static String openApiToPuml(File file) throws IOException {
public static String openApiToPuml(File file, boolean showNote) throws IOException {
try (InputStream in = new BufferedInputStream(new FileInputStream(file))) {
return openApiToPuml(in);
return openApiToPuml(in, showNote);
}
}

public static String openApiToPuml(String openApi) {
public static String openApiToPuml(String openApi, boolean showNote) {
SwaggerParseResult result = new OpenAPIParser().readContents(openApi, null, null);
if (result.getOpenAPI() == null) {
throw new IllegalArgumentException("Not an OpenAPI definition");
}
return openApiToPuml(result.getOpenAPI());
return openApiToPuml(result.getOpenAPI(), showNote);
}

private static String openApiToPuml(OpenAPI a) {
private static String openApiToPuml(OpenAPI a, boolean showNote) {

Names names = new Names(a);
Model model = ComponentsHelper //
Expand All @@ -73,11 +73,12 @@ private static String openApiToPuml(OpenAPI a) {
// make sure that periods in class names aren't interpreted as namespace
// separators (which results in recursive boxing)
+ "\nset namespaceSeparator none" //
+ toPlantUml(model) //
+ toPlantUml(model, showNote) //
+ "\n\n@enduml";
}

private static String toPlantUml(Model model) {
private static String toPlantUml(Model model, boolean showNote) {
final String regexForFixBugOnNote = "\\s|\\{|\\}|\\+";
int anonNumber = 0;
StringBuilder b = new StringBuilder();
for (Class cls : model.classes()) {
Expand All @@ -89,12 +90,39 @@ private static String toPlantUml(Model model) {
});
b.append("\n}");
} else {
b.append("\n\nclass " + Util.quote(cls.name())
StringBuilder infoSb = new StringBuilder();
b.append("\n\nclass " + Util.quote(cls.name()) + " as " + cls.name().replaceAll(regexForFixBugOnNote, "_")
+ toStereotype(cls.type()).map(x -> " <<" + x + ">>").orElse("") + " {");
cls.fields().stream().forEach(f -> {
b.append("\n {field} " + f.name() + COLON + f.type() + (f.isRequired() ? "" : " {O}"));
b.append("\n {field} " + f.name() + COLON + f.type()
+ ((f.maxLength() > -1) ? "(" + String.valueOf(f.maxLength()) + ")" : "")
+ (f.isRequired() ? " {R}" : ""));

StringBuilder infoFieldSb = new StringBuilder();
if (showNote) {
if (f.description() != null) {
infoFieldSb.append("\n\t<size:8>" + f.description() + "</size>");
}
if (f.format() != null) {
infoFieldSb.append("\n\t<size:8>Format " + f.format() + "</size>");
}
if (f.extension() != null) {
infoFieldSb.append("\n\t<size:8>" + f.extension() + "</size>");
}
if (f.example() != null) {
infoFieldSb.append("\n\t<size:8><i>Ex: " + f.example() + "</i></size>");
}
if (infoFieldSb.length() > 0) {
infoSb.append("\nnote right of " + cls.name().replaceAll(regexForFixBugOnNote, "_") + "::" + Util.quote(f.name()));
infoSb.append(infoFieldSb);
infoSb.append("\nend note");
}
}
});
b.append("\n}");
if (infoSb.length() > 0) {
b.append(infoSb);
}
}
}
// add external ref classes
Expand All @@ -112,7 +140,7 @@ private static String toPlantUml(Model model) {
String[] items = to.split(Names.NAMESPACE_DELIMITER);
String namespace = items[0];
String clsName = items[1];
b.append("\n\nclass " + Util.quote(clsName) + " <<" + namespace + ">>" + " {");
b.append("\n\nclass " + clsName.replaceAll(regexForFixBugOnNote, "_") + " <<" + namespace + ">>" + " {");
b.append("\n}");
added.add(to);
}
Expand All @@ -139,8 +167,8 @@ private static String toPlantUml(Model model) {
if (to.contains(Names.NAMESPACE_DELIMITER)) {
to = to.split(Names.NAMESPACE_DELIMITER)[1];
}
b.append("\n\n" + quote(a.from()) + SPACE + arrow + SPACE + quote(mult) + SPACE
+ quote(to)
b.append("\n\n" + quote(a.from().replaceAll(regexForFixBugOnNote, "_")) + SPACE + arrow + SPACE + quote(mult) + SPACE
+ quote(to.replaceAll(regexForFixBugOnNote, "_"))
+ (label.equals("") ? "" : SPACE + COLON + SPACE + quote(label)));
} else {
Inheritance a = (Inheritance) r;
Expand All @@ -153,16 +181,16 @@ private static String toPlantUml(Model model) {
anonNumber++;
String diamond = "anon" + anonNumber;
b.append("\n\ndiamond " + diamond);
b.append("\n\n" + quote(from) + SPACE + "-->" + quote(mult) + SPACE
b.append("\n\n" + quote(from.replaceAll(regexForFixBugOnNote, "_")) + SPACE + "-->" + quote(mult) + SPACE
+ quote(diamond) + a.propertyName().map(x -> COLON + quote(x)).orElse(""));
for (String otherClassName : a.to()) {
b.append("\n\n" + quote(otherClassName) + SPACE + "--|>" + SPACE
b.append("\n\n" + quote(otherClassName.replaceAll(regexForFixBugOnNote, "_")) + SPACE + "--|>" + SPACE
+ quote(diamond));
}
} else {
for (String otherClassName : a.to()) {
b.append("\n\n" + quote(otherClassName) + SPACE + "--|>" + SPACE
+ quote(a.from()));
b.append("\n\n" + quote(otherClassName.replaceAll(regexForFixBugOnNote, "_")) + SPACE + "--|>" + SPACE
+ quote(a.from().replaceAll(regexForFixBugOnNote, "_")));
}
}
}
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/com/github/davidmoten/oas3/puml/ConverterMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,18 @@ static DiagramDescription writeFileFormatFromPuml(String puml, String filename,
}

public static void main(String[] args) throws IOException {
String usage = "Usage: java -jar openapi-to-plantuml-all.jar <OPENAPI_FILE> <FILE_FORMAT> <OUTPUT_FILE>"
String usage = "Usage: java -jar openapi-to-plantuml-all.jar <OPENAPI_FILE> <FILE_FORMAT> <OUTPUT_FILE> <SHOW_NOTE{0|1}>"
+ "\n File formats are:\n PUML\n" + Arrays.stream(FileFormat.values())
.map(x -> " " + x + "\n").collect(Collectors.joining());
if (args.length != 3) {
if ((args.length != 3) && (args.length != 4)) {
System.out.println(usage);
throw new IllegalArgumentException("must pass 3 arguments");
throw new IllegalArgumentException("must pass 3 or 4 arguments");
} else {
String puml = Converter.openApiToPuml(new File(args[0]));
boolean showNote = false;
if (args.length == 4) {
showNote = (args[4] == "1") ? true : false;
}
String puml = Converter.openApiToPuml(new File(args[0]), showNote);
String format = args[1];
File out = new File(args[2]);
if (format.equals("PUML")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static Collection<?> files() {
public void test() {
System.out.println("checking " + input);
try (InputStream in = new FileInputStream(input)) {
String puml = Converter.openApiToPuml(in).trim();
String puml = Converter.openApiToPuml(in, true).trim();
File pumlFile = new File("target/outputs",
input.getName().substring(0, input.getName().lastIndexOf('.')) + ".puml");
pumlFile.getParentFile().mkdirs();
Expand All @@ -58,7 +58,7 @@ public void test() {
System.out.println(puml);
}
String expected = com.github.davidmoten.junit.Files.readUtf8(output).trim();
ConverterTest.writeSvg(input, "target/outputs/" + output.getName() + ".svg");
ConverterTest.writeSvg(input, "target/outputs/" + output.getName() + ".svg", true);
assertEquals(expected, puml);
} catch (IOException e) {
throw new UncheckedIOException(e);
Expand Down
16 changes: 8 additions & 8 deletions src/test/java/com/github/davidmoten/oas3/puml/ConverterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,28 @@ public void testConvert() {
+ " type: array\n" + " items:\n"
+ " $ref: '#/components/schemas/Customer'\n" + " ";

Converter.openApiToPuml(openapi);
Converter.openApiToPuml(openapi, true);
}

@Test
public void testConvertExternalRef() throws IOException {
Converter.openApiToPuml(new File("src/test/resources/inputs/external-ref.yml"));
Converter.openApiToPuml(new File("src/test/resources/inputs/external-ref.yml"), true);
}

@Test(expected = IllegalArgumentException.class)
public void testConvertEmpty() {
Converter.openApiToPuml("");
Converter.openApiToPuml("", true);
}

@Test
public void testConvertPumlToSvg() throws IOException {
writeSvg(OPENAPI_EXAMPLE, "target/openapi-example.svg");
writeSvg(OPENAPI_EXAMPLE, "target/openapi-example.svg", true);
}

@Test
@Ignore
public void updateDocs() throws IOException {
writeSvg(OPENAPI_EXAMPLE, "src/docs/openapi-example.svg");
writeSvg(OPENAPI_EXAMPLE, "src/docs/openapi-example.svg", true);
}

@Test
Expand Down Expand Up @@ -92,9 +92,9 @@ private static String readString(String filename) throws IOException {
return new String(Files.readAllBytes(new File(filename).toPath()), StandardCharsets.UTF_8);
}

static void writeSvg(File openApiFile, String filename) throws IOException {
static void writeSvg(File openApiFile, String filename, boolean showNote) throws IOException {
try (InputStream in = new FileInputStream(openApiFile)) {
String puml = Converter.openApiToPuml(in);
String puml = Converter.openApiToPuml(in, showNote);
writeSvgFromPuml(puml, filename);
}
}
Expand All @@ -111,6 +111,6 @@ static void writeSvgFromPuml(String puml, String filename) throws IOException {
}

public static void main(String[] args) throws IOException {
writeSvg(new File(System.getProperty("user.home", "") + "/imdb.yml"), "target/imdb.svg");
writeSvg(new File(System.getProperty("user.home", "") + "/imdb.yml"), "target/imdb.svg", true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ public void testBatch() {
File svg = new File(demos, input.getName().substring(0, input.getName().lastIndexOf('.')) + ".svg");
String puml;
try (InputStream def = new FileInputStream(input)) {
puml = com.github.davidmoten.oas3.puml.Converter.openApiToPuml(def);
puml = com.github.davidmoten.oas3.puml.Converter.openApiToPuml(def, true);
}
File pumlFile = new File(demos, input.getName().substring(0, input.getName().lastIndexOf('.')) + ".puml");
pumlFile.delete();
Files.write(pumlFile.toPath(), puml.getBytes(StandardCharsets.UTF_8));
svg.delete();
ConverterTest.writeSvg(input, svg.getPath());
ConverterTest.writeSvg(input, svg.getPath(), true);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Expand Down
Loading