diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java index ab85cf0c4fe..80033e12699 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java @@ -708,6 +708,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator { return files; } + private File processTemplateToFile(Map templateData, String templateName, String outputFilename) throws IOException { String adjustedOutputFilename = outputFilename.replaceAll("//", "/").replace('/', File.separatorChar); if (ignoreProcessor.allowsFile(new File(adjustedOutputFilename))) { diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java index 84aa2fbee54..33066ebeb92 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java @@ -1,5 +1,6 @@ package io.swagger.codegen.languages; +import com.google.common.collect.LinkedListMultimap; import io.swagger.codegen.*; import io.swagger.codegen.languages.features.BeanValidationFeatures; import io.swagger.codegen.languages.features.GzipFeatures; @@ -432,6 +433,24 @@ public class JavaClientCodegen extends AbstractJavaCodegen } @SuppressWarnings("unchecked") + @Override + public Map postProcessAllModels(Map objs) { + Map allProcessedModels = super.postProcessAllModels(objs); + if(!additionalProperties.containsKey("gsonFactoryMethod")) { + List allModels = new ArrayList(); + for (String name: allProcessedModels.keySet()) { + Map models = (Map)allProcessedModels.get(name); + try { + allModels.add(((List) models.get("models")).get(0)); + } catch (Exception e){ + e.printStackTrace(); + } + } + additionalProperties.put("parent", modelInheritanceSupportInGson(allModels)); + } + return allProcessedModels; + } + @Override public Map postProcessModelsEnum(Map objs) { objs = super.postProcessModelsEnum(objs); @@ -454,6 +473,34 @@ public class JavaClientCodegen extends AbstractJavaCodegen return objs; } + private List> modelInheritanceSupportInGson(List allModels) { + LinkedListMultimap byParent = LinkedListMultimap.create(); + for (Object m : allModels) { + Map entry = (Map) m; + CodegenModel parent = ((CodegenModel)entry.get("model")).parentModel; + if(null!= parent) { + byParent.put(parent, ((CodegenModel)entry.get("model"))); + } + } + List> parentsList = new ArrayList<>(); + for (CodegenModel parentModel : byParent.keySet()) { + List> childrenList = new ArrayList<>(); + Map parent = new HashMap<>(); + parent.put("classname", parentModel.classname); + List childrenModels = byParent.get(parentModel); + for (CodegenModel model : childrenModels) { + Map child = new HashMap<>(); + child.put("name", model.name); + child.put("classname", model.classname); + childrenList.add(child); + } + parent.put("children", childrenList); + parent.put("discriminator", parentModel.discriminator); + parentsList.add(parent); + } + return parentsList; + } + public void setUseRxJava(boolean useRxJava) { this.useRxJava = useRxJava; doNotUseRx = false; diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/ApiClient.mustache index f0b5f5c8b8a..66d3056e540 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/ApiClient.mustache @@ -2,6 +2,7 @@ package {{invokerPackage}}; import com.google.gson.Gson; import com.google.gson.JsonParseException; +import com.google.gson.JsonElement; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.RequestBody; @@ -39,6 +40,7 @@ import java.time.format.DateTimeFormatter; {{/java8}} import java.util.LinkedHashMap; import java.util.Map; +import java.util.HashMap; public class ApiClient { diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/JSON.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/JSON.mustache index 9acd505b763..abab9159d79 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/JSON.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/JSON.mustache @@ -9,6 +9,9 @@ import com.google.gson.TypeAdapter; import com.google.gson.internal.bind.util.ISO8601Utils; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; +import com.google.gson.JsonElement; +import io.gsonfire.GsonFireBuilder; +import io.gsonfire.TypeSelector; {{#joda}} import org.joda.time.DateTime; import org.joda.time.LocalDate; @@ -22,6 +25,8 @@ import org.threeten.bp.OffsetDateTime; import org.threeten.bp.format.DateTimeFormatter; {{/threetenbp}} +import {{modelPackage}}.*; + import java.io.IOException; import java.io.StringReader; import java.lang.reflect.Type; @@ -34,6 +39,8 @@ import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; {{/java8}} import java.util.Date; +import java.util.Map; +import java.util.HashMap; public class JSON { private Gson gson; @@ -48,8 +55,45 @@ public class JSON { private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); {{/jsr310}} + public static GsonBuilder createGson() { + GsonFireBuilder fireBuilder = new GsonFireBuilder() + {{#parent}} + .registerTypeSelector({{classname}}.class, new TypeSelector() { + @Override + public Class getClassForElement(JsonElement readElement) { + Map classByDiscriminatorValue = new HashMap(); + {{#children}} + classByDiscriminatorValue.put("{{name}}".toUpperCase(), {{classname}}.class); + {{/children}} + classByDiscriminatorValue.put("{{classname}}".toUpperCase(), {{classname}}.class); + return getClassByDiscriminator( + classByDiscriminatorValue, + getDiscriminatorValue(readElement, "{{discriminator}}")); + } + }) + {{/parent}} + ; + return fireBuilder.createGsonBuilder(); + } + + private static String getDiscriminatorValue(JsonElement readElement, String discriminatorField) { + JsonElement element = readElement.getAsJsonObject().get(discriminatorField); + if(null == element) { + throw new IllegalArgumentException("missing discriminator field: <" + discriminatorField + ">"); + } + return element.getAsString(); + } + + private static Class getClassByDiscriminator(Map classByDiscriminatorValue, String discriminatorValue) { + Class clazz = (Class) classByDiscriminatorValue.get(discriminatorValue.toUpperCase()); + if(null == clazz) { + throw new IllegalArgumentException("cannot determine model class of name: <" + discriminatorValue + ">"); + } + return clazz; + } + public JSON() { - gson = new GsonBuilder() + gson = createGson() .registerTypeAdapter(Date.class, dateTypeAdapter) .registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter) {{#joda}} diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/build.gradle.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/build.gradle.mustache index aa27f711b02..bc92925ac00 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/build.gradle.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/build.gradle.mustache @@ -126,6 +126,7 @@ ext { {{#threetenbp}} threetenbp_version = "1.3.5" {{/threetenbp}} + json_fire_version = "1.8.0" } dependencies { @@ -142,6 +143,7 @@ dependencies { {{/useRxJava2}} compile "io.swagger:swagger-annotations:$swagger_annotations_version" compile "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version" + compile "io.gsonfire:gson-fire:$json_fire_version" {{#joda}} compile "joda-time:joda-time:$jodatime_version" {{/joda}} diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/build.sbt.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/build.sbt.mustache index c070f3a31e3..5d43e1619d3 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/build.sbt.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/build.sbt.mustache @@ -45,6 +45,7 @@ lazy val root = (project in file(".")). {{#threetenbp}} "org.threeten" % "threetenbp" % "1.3.5" % "compile", {{/threetenbp}} + "io.gsonfire" % "gson-fire" % "1.8.0" % "compile", "junit" % "junit" % "4.12" % "test", "com.novocode" % "junit-interface" % "0.11" % "test" ) diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/pom.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/pom.mustache index 6cdce584508..e0e4cddd31c 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/pom.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/pom.mustache @@ -194,6 +194,11 @@ org.apache.oltu.oauth2.client ${oltu-version} + + io.gsonfire + gson-fire + ${gson-fire-version} + {{#joda}} joda-time @@ -300,6 +305,7 @@ {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} ${java.version} ${java.version} + 1.8.0 1.5.15 {{#usePlayWS}} {{#play24}} diff --git a/samples/client/petstore/java/retrofit2/build.gradle b/samples/client/petstore/java/retrofit2/build.gradle index 9c7f627e48c..be4a7349272 100644 --- a/samples/client/petstore/java/retrofit2/build.gradle +++ b/samples/client/petstore/java/retrofit2/build.gradle @@ -99,6 +99,7 @@ ext { swagger_annotations_version = "1.5.15" junit_version = "4.12" threetenbp_version = "1.3.5" + json_fire_version = "1.8.0" } dependencies { @@ -107,6 +108,7 @@ dependencies { compile "com.squareup.retrofit2:converter-gson:$retrofit_version" compile "io.swagger:swagger-annotations:$swagger_annotations_version" compile "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version" + compile "io.gsonfire:gson-fire:$json_fire_version" compile "org.threeten:threetenbp:$threetenbp_version" testCompile "junit:junit:$junit_version" diff --git a/samples/client/petstore/java/retrofit2/build.sbt b/samples/client/petstore/java/retrofit2/build.sbt index de55c31451b..c7b77d03cb8 100644 --- a/samples/client/petstore/java/retrofit2/build.sbt +++ b/samples/client/petstore/java/retrofit2/build.sbt @@ -15,6 +15,7 @@ lazy val root = (project in file(".")). "io.swagger" % "swagger-annotations" % "1.5.15" % "compile", "org.apache.oltu.oauth2" % "org.apache.oltu.oauth2.client" % "1.0.1" % "compile", "org.threeten" % "threetenbp" % "1.3.5" % "compile", + "io.gsonfire" % "gson-fire" % "1.8.0" % "compile", "junit" % "junit" % "4.12" % "test", "com.novocode" % "junit-interface" % "0.11" % "test" ) diff --git a/samples/client/petstore/java/retrofit2/pom.xml b/samples/client/petstore/java/retrofit2/pom.xml index c620f9ff6f9..1f8c0e66234 100644 --- a/samples/client/petstore/java/retrofit2/pom.xml +++ b/samples/client/petstore/java/retrofit2/pom.xml @@ -194,6 +194,11 @@ org.apache.oltu.oauth2.client ${oltu-version} + + io.gsonfire + gson-fire + ${gson-fire-version} + org.threeten threetenbp @@ -215,6 +220,7 @@ 1.7 ${java.version} ${java.version} + 1.8.0 1.5.15 2.3.0 1.3.5 diff --git a/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/ApiClient.java index 9de69dde1e8..d1a5c2102a8 100644 --- a/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/ApiClient.java @@ -2,6 +2,7 @@ package io.swagger.client; import com.google.gson.Gson; import com.google.gson.JsonParseException; +import com.google.gson.JsonElement; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.RequestBody; @@ -25,6 +26,7 @@ import java.lang.reflect.Type; import java.text.DateFormat; import java.util.LinkedHashMap; import java.util.Map; +import java.util.HashMap; public class ApiClient { diff --git a/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/JSON.java b/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/JSON.java index 590495331b6..aa07fc781cc 100644 --- a/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/JSON.java +++ b/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/JSON.java @@ -20,10 +20,15 @@ import com.google.gson.TypeAdapter; import com.google.gson.internal.bind.util.ISO8601Utils; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; +import com.google.gson.JsonElement; +import io.gsonfire.GsonFireBuilder; +import io.gsonfire.TypeSelector; import org.threeten.bp.LocalDate; import org.threeten.bp.OffsetDateTime; import org.threeten.bp.format.DateTimeFormatter; +import io.swagger.client.model.*; + import java.io.IOException; import java.io.StringReader; import java.lang.reflect.Type; @@ -31,6 +36,8 @@ import java.text.DateFormat; import java.text.ParseException; import java.text.ParsePosition; import java.util.Date; +import java.util.Map; +import java.util.HashMap; public class JSON { private Gson gson; @@ -39,8 +46,42 @@ public class JSON { private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter(); private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); + public static GsonBuilder createGson() { + GsonFireBuilder fireBuilder = new GsonFireBuilder() + .registerTypeSelector(Animal.class, new TypeSelector() { + @Override + public Class getClassForElement(JsonElement readElement) { + Map classByDiscriminatorValue = new HashMap(); + classByDiscriminatorValue.put("Cat".toUpperCase(), Cat.class); + classByDiscriminatorValue.put("Dog".toUpperCase(), Dog.class); + classByDiscriminatorValue.put("Animal".toUpperCase(), Animal.class); + return getClassByDiscriminator( + classByDiscriminatorValue, + getDiscriminatorValue(readElement, "className")); + } + }) + ; + return fireBuilder.createGsonBuilder(); + } + + private static String getDiscriminatorValue(JsonElement readElement, String discriminatorField) { + JsonElement element = readElement.getAsJsonObject().get(discriminatorField); + if(null == element) { + throw new IllegalArgumentException("missing discriminator field: <" + discriminatorField + ">"); + } + return element.getAsString(); + } + + private static Class getClassByDiscriminator(Map classByDiscriminatorValue, String discriminatorValue) { + Class clazz = (Class) classByDiscriminatorValue.get(discriminatorValue.toUpperCase()); + if(null == clazz) { + throw new IllegalArgumentException("cannot determine model class of name: <" + discriminatorValue + ">"); + } + return clazz; + } + public JSON() { - gson = new GsonBuilder() + gson = createGson() .registerTypeAdapter(Date.class, dateTypeAdapter) .registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter) .registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter)