Vendor Mime-type support in retrofit2

This commit is contained in:
raj k 2016-10-19 13:40:16 -07:00
parent c3a12cb3f9
commit 23fee386f2
7 changed files with 1418 additions and 10 deletions

View File

@ -19,7 +19,7 @@ public class CodegenOperation {
isRestful;
public String path, operationId, returnType, httpMethod, returnBaseType,
returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse, discriminator;
public List<Map<String, String>> consumes, produces;
public List<Map<String, String>> consumes, produces, prioritizedContentTypes;
public CodegenParameter bodyParam;
public List<CodegenParameter> allParams = new ArrayList<CodegenParameter>();
public List<CodegenParameter> bodyParams = new ArrayList<CodegenParameter>();
@ -275,6 +275,8 @@ public class CodegenOperation {
return false;
if (nickname != null ? !nickname.equals(that.nickname) : that.nickname != null)
return false;
if ( prioritizedContentTypes != null ? !prioritizedContentTypes.equals(that.prioritizedContentTypes) : that.prioritizedContentTypes != null )
return false;
return operationIdLowerCase != null ? operationIdLowerCase.equals(that.operationIdLowerCase) : that.operationIdLowerCase == null;
}
@ -325,6 +327,7 @@ public class CodegenOperation {
result = 31 * result + (externalDocs != null ? externalDocs.hashCode() : 0);
result = 31 * result + (vendorExtensions != null ? vendorExtensions.hashCode() : 0);
result = 31 * result + (nickname != null ? nickname.hashCode() : 0);
result = 31 * result + (prioritizedContentTypes != null ? prioritizedContentTypes.hashCode() : 0);
result = 31 * result + (operationIdLowerCase != null ? operationIdLowerCase.hashCode() : 0);
return result;
}

View File

@ -8,9 +8,12 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
import java.util.regex.Pattern;
public class JavaClientCodegen extends AbstractJavaCodegen {
@SuppressWarnings("hiding")
static final String MEDIA_TYPE = "mediaType";
@SuppressWarnings("hiding")
private static final Logger LOGGER = LoggerFactory.getLogger(JavaClientCodegen.class);
public static final String USE_RX_JAVA = "useRxJava";
@ -173,24 +176,73 @@ public class JavaClientCodegen extends AbstractJavaCodegen {
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation operation : ops) {
if (operation.hasConsumes == Boolean.TRUE) {
Map<String, String> firstType = operation.consumes.get(0);
if (firstType != null) {
if ("multipart/form-data".equals(firstType.get("mediaType"))) {
operation.isMultipart = Boolean.TRUE;
}
if ( isMultipartType(operation.consumes) ) {
operation.isMultipart = Boolean.TRUE;
}
else {
operation.prioritizedContentTypes = prioritizeContentTypes(operation.consumes);
}
}
if (operation.returnType == null) {
operation.returnType = "Void";
}
if (usesRetrofit2Library() && StringUtils.isNotEmpty(operation.path) && operation.path.startsWith("/"))
operation.path = operation.path.substring(1);
operation.path = operation.path.substring(1);
}
}
}
return objs;
}
/**
* Prioritizes consumes mime-type list by moving json-vendor and json mime-types up front, but
* otherwise preserves original consumes definition order.
* [application/vnd...+json,... application/json, ..as is..]
*
* @param consumes consumes mime-type list
* @return
*/
static List<Map<String, String>> prioritizeContentTypes(List<Map<String, String>> consumes) {
if ( consumes.size() <= 1 )
return consumes;
List<Map<String, String>> prioritizedContentTypes = new ArrayList<>(consumes.size());
List<Map<String, String>> jsonVendorMimeTypes = new ArrayList<>(consumes.size());
List<Map<String, String>> jsonMimeTypes = new ArrayList<>(consumes.size());
for ( Map<String, String> consume : consumes) {
if ( isJsonVendorMimeType(consume.get(MEDIA_TYPE))) {
jsonVendorMimeTypes.add(consume);
}
else if ( isJsonMimeType(consume.get(MEDIA_TYPE))) {
jsonMimeTypes.add(consume);
}
else
prioritizedContentTypes.add(consume);
consume.put("hasMore", "true");
}
prioritizedContentTypes.addAll(0, jsonMimeTypes);
prioritizedContentTypes.addAll(0, jsonVendorMimeTypes);
prioritizedContentTypes.get(prioritizedContentTypes.size()-1).put("hasMore", null);
return prioritizedContentTypes;
}
private static boolean isMultipartType(List<Map<String, String>> consumes) {
Map<String, String> firstType = consumes.get(0);
if (firstType != null) {
if ("multipart/form-data".equals(firstType.get(MEDIA_TYPE))) {
return true;
}
}
return false;
}
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
super.postProcessModelProperty(model, property);
@ -245,4 +297,28 @@ public class JavaClientCodegen extends AbstractJavaCodegen {
this.supportJava6 = value;
}
final private static Pattern JSON_MIME_PATTERN = Pattern.compile("(?i)application\\/json(;.*)?");
final private static Pattern JSON_VENDOR_MIME_PATTERN = Pattern.compile("(?i)application\\/vnd.(.*)+json(;.*)?");
/**
* Check if the given MIME is a JSON MIME.
* JSON MIME examples:
* application/json
* application/json; charset=UTF8
* APPLICATION/JSON
*/
static boolean isJsonMimeType(String mime) {
return mime != null && ( JSON_MIME_PATTERN.matcher(mime).matches());
}
/**
* Check if the given MIME is a JSON Vendor MIME.
* JSON MIME examples:
* application/vnd.mycompany+json
* application/vnd.mycompany.resourceA.version1+json
*/
static boolean isJsonVendorMimeType(String mime) {
return mime != null && JSON_VENDOR_MIME_PATTERN.matcher(mime).matches();
}
}

View File

@ -29,6 +29,15 @@ public interface {{classname}} {
*/
{{#formParams}}{{#-first}}
{{#isMultipart}}@retrofit2.http.Multipart{{/isMultipart}}{{^isMultipart}}@retrofit2.http.FormUrlEncoded{{/isMultipart}}{{/-first}}{{/formParams}}
{{^formParams}}
{{#prioritizedContentTypes}}
{{#-first}}
@Headers({
"Content-Type:{{mediaType}}"
})
{{/-first}}
{{/prioritizedContentTypes}}
{{/formParams}}
@{{httpMethod}}("{{path}}")
{{#useRxJava}}Observable{{/useRxJava}}{{^useRxJava}}Call{{/useRxJava}}<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}({{^allParams}});{{/allParams}}
{{#allParams}}{{>libraries/retrofit2/queryParams}}{{>libraries/retrofit2/pathParams}}{{>libraries/retrofit2/headerParams}}{{>libraries/retrofit2/bodyParams}}{{>libraries/retrofit2/formParams}}{{#hasMore}}, {{/hasMore}}{{^hasMore}}

View File

@ -0,0 +1,79 @@
package io.swagger.codegen.languages;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.Test;
public class JavaClientCodegenTest {
private static final String VENDOR_MIME_TYPE = "application/vnd.company.v1+json";
private static final String XML_MIME_TYPE = "application/xml";
private static final String JSON_MIME_TYPE = "application/json";
private static final String TEXT_MIME_TYPE = "text/plain";
@Test
public void testJsonMime() {
Assert.assertTrue(JavaClientCodegen.isJsonMimeType(JSON_MIME_TYPE));
Assert.assertFalse(JavaClientCodegen.isJsonMimeType(XML_MIME_TYPE));
Assert.assertFalse(JavaClientCodegen.isJsonMimeType(TEXT_MIME_TYPE));
Assert.assertTrue(JavaClientCodegen.isJsonVendorMimeType("application/vnd.mycompany+json"));
Assert.assertTrue(JavaClientCodegen.isJsonVendorMimeType("application/vnd.mycompany.v1+json"));
Assert.assertTrue(JavaClientCodegen.isJsonVendorMimeType("application/vnd.mycompany.resourceTypeA.version1+json"));
Assert.assertTrue(JavaClientCodegen.isJsonVendorMimeType("application/vnd.mycompany.resourceTypeB.version2+json"));
Assert.assertFalse(JavaClientCodegen.isJsonVendorMimeType("application/v.json"));
}
@Test
public void testContentTypePrioritization() {
Map<String, String> jsonMimeType = new HashMap<>();
jsonMimeType.put(JavaClientCodegen.MEDIA_TYPE, JSON_MIME_TYPE);
Map<String, String> xmlMimeType = new HashMap<>();
xmlMimeType.put(JavaClientCodegen.MEDIA_TYPE, XML_MIME_TYPE);
Map<String, String> vendorMimeType = new HashMap<>();
vendorMimeType.put(JavaClientCodegen.MEDIA_TYPE, VENDOR_MIME_TYPE);
Map<String, String> textMimeType = new HashMap<>();
textMimeType.put(JavaClientCodegen.MEDIA_TYPE, TEXT_MIME_TYPE);
Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(
Collections.<Map<String,String>>emptyList()), Collections.emptyList());
Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(xmlMimeType)), Arrays.asList(xmlMimeType));
Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(jsonMimeType)), Arrays.asList(jsonMimeType));
Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(vendorMimeType)), Arrays.asList(vendorMimeType));
Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(xmlMimeType, jsonMimeType)),
Arrays.asList(jsonMimeType, xmlMimeType));
Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(jsonMimeType, xmlMimeType)),
Arrays.asList(jsonMimeType, xmlMimeType));
Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(jsonMimeType, vendorMimeType)),
Arrays.asList(vendorMimeType, jsonMimeType));
Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(textMimeType, xmlMimeType)),
Arrays.asList(textMimeType, xmlMimeType));
Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(xmlMimeType, textMimeType)),
Arrays.asList(xmlMimeType, textMimeType));
System.out.println(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(
xmlMimeType,textMimeType, jsonMimeType, vendorMimeType)));
List<Map<String,String>> priContentTypes = JavaClientCodegen.prioritizeContentTypes(Arrays.asList(
xmlMimeType, textMimeType, jsonMimeType, vendorMimeType));
Assert.assertEquals(priContentTypes, Arrays.asList(vendorMimeType, jsonMimeType, xmlMimeType, textMimeType));
for ( int i = 0; i < 3; i++ )
Assert.assertNotNull(priContentTypes.get(i).get("hasMore"));
Assert.assertNull(priContentTypes.get(3).get("hasMore"));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,8 @@ import okhttp3.RequestBody;
import io.swagger.client.model.Client;
import org.joda.time.LocalDate;
import org.joda.time.DateTime;
import java.math.BigDecimal;
import org.joda.time.DateTime;
import java.util.ArrayList;
import java.util.HashMap;
@ -26,6 +26,9 @@ public interface FakeApi {
* @return Call&lt;Client&gt;
*/
@Headers({
"Content-Type:application/json"
})
@PATCH("fake")
Call<Client> testClientModel(
@retrofit2.http.Body Client body

View File

@ -9,8 +9,8 @@ import retrofit2.http.*;
import okhttp3.RequestBody;
import io.swagger.client.model.Pet;
import java.io.File;
import io.swagger.client.model.ModelApiResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
@ -25,6 +25,9 @@ public interface PetApi {
* @return Call&lt;Void&gt;
*/
@Headers({
"Content-Type:application/json"
})
@POST("pet")
Call<Void> addPet(
@retrofit2.http.Body Pet body
@ -86,6 +89,9 @@ public interface PetApi {
* @return Call&lt;Void&gt;
*/
@Headers({
"Content-Type:application/json"
})
@PUT("pet")
Call<Void> updatePet(
@retrofit2.http.Body Pet body