Claned un used code, made configuration simple and more reusable. renamed some methods to make it more meaningful.

This commit is contained in:
rpidikiti 2011-08-04 17:10:08 -07:00
parent 288a58cd4f
commit 2f8262cba4
21 changed files with 328 additions and 357 deletions

View File

@ -46,14 +46,14 @@ public class $resource$ extends $extends$ {
$methods:{ method |
/**
* $method.description$
$method.arguments:{ argument |
* @param $argument.name$ $argument.description$
$if(argument.allowedValues)$
* Allowed values are - $argument.allowedValues$
$endif$
}$
* $method.title$
*
$if(method.description)$
* $method.description$
* $endif$
* $method.arguments:{ argument |@param $argument.name$ $argument.description$
* $if(argument.allowedValues)$
* Allowed values are - $argument.allowedValues$ $endif$ }$
$if(!method.responseVoid)$
* @return $method.returnValue$ {@link $method.returnClassName$} $endif$
* @throws APIException $method.exceptionDescription$
@ -62,7 +62,7 @@ $if(method.hasArguments)$
@MethodArgumentNames(value="$method.argumentNames; separator=", "$")
$endif$
public static $method.returnValue$ $method.name$($method.argumentDefinitions; separator=", "$) throws APIException {
public static $method.returnValue$ $method.name$($method.argumentDefinitions; separator=", "$) throws APIException {
//parse inputs
String resourcePath = "$method.resourcePath$";
@ -102,18 +102,17 @@ $if(!method.postObject)$
String response = APIInvoker.invokeAPI(resourcePath, method, queryParams, null);
$endif$
//create output objects if the response has more than one object
$if(!method.responseVoid)$
if(response == null || response.length() == 0){
return null;
}
$if(!method.returnValueList)$
//create output objects if the response has more than one object
$method.returnValue$ responseObject = ($method.returnValue$) APIInvoker.deserialize(response, $method.returnClassName$.class);
return responseObject;
$endif$
$if(method.returnValueList)$
TypeReference<ArrayList<$method.returnClassName$>> typeRef = new TypeReference<ArrayList<$method.returnClassName$>>() {
};
TypeReference<ArrayList<$method.returnClassName$>> typeRef = new TypeReference<ArrayList<$method.returnClassName$>>() {};
try {
List<$method.returnClassName$> responseObject = (List<$method.returnClassName$>) APIInvoker.mapper.readValue(response, typeRef);
return responseObject;
@ -123,7 +122,7 @@ $if(method.returnValueList)$
}
$endif$
$endif$
}
}
}$

View File

@ -28,7 +28,7 @@ public class VersionChecker {
private String compatibleVersion = "$apiVersion$";
/**
* Gets the version against which the driver code was written
* Gets the version against which the library code was written
*/
public String getCompatibleVersion() {
return compatibleVersion;

View File

@ -18,11 +18,15 @@ package com.wordnik.swagger.codegen;
import com.wordnik.swagger.codegen.api.SwaggerResourceDocReader;
import com.wordnik.swagger.codegen.config.*;
import com.wordnik.swagger.codegen.config.ApiConfiguration;
import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider;
import com.wordnik.swagger.codegen.config.java.JavaDataTypeMappingProvider;
import com.wordnik.swagger.codegen.resource.*;
import com.wordnik.swagger.codegen.util.FileUtil;
import com.wordnik.swagger.exception.CodeGenerationException;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import java.io.BufferedWriter;
import java.io.File;
@ -52,6 +56,20 @@ public class LibraryCodeGenerator {
protected RulesProvider codeGenRulesProvider;
protected NamingPolicyProvider nameGenerator;
public LibraryCodeGenerator(String configPath){
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final File configFile = new File(configPath);
this.setApiConfig(readApiConfiguration(configPath, mapper, configFile));
this.setCodeGenRulesProvider(readRulesProviderConfig(configPath, mapper, configFile));
this.setLanguageConfig( initializeLangConfig(readLanguageConfiguration(configPath, mapper, configFile)) );
this.setDataTypeMappingProvider(new JavaDataTypeMappingProvider());
this.setNameGenerator(new CamelCaseNamingPolicyProvider());
}
/**
* Generate classes needed for the model and API invocation
*/
@ -90,7 +108,7 @@ public class LibraryCodeGenerator {
List<String> generatedClassNames = new ArrayList();
//remove old generated files
FileUtil.cleanFiles(languageConfig.getModelClassLocation());
FileUtil.clearFolder(languageConfig.getModelClassLocation());
for(Resource resource: resources) {
for(Model model : resource.getModels()){
@ -108,7 +126,7 @@ public class LibraryCodeGenerator {
template.setAttribute("fields", model.getFields());
template.setAttribute("imports", imports);
template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
template.setAttribute("extends", config.getModelBaseClass());
template.setAttribute("extends", config.getDefaultModelBaseClass());
template.setAttribute("className", model.getGenratedClassName());
template.setAttribute(PACKAGE_NAME, config.getModelPackageName());
File aFile = new File(languageConfig.getModelClassLocation()+model.getGenratedClassName()+languageConfig.getClassFileExtension());
@ -151,7 +169,7 @@ public class LibraryCodeGenerator {
template.setAttribute("fields", model.getFields());
template.setAttribute("imports", imports);
template.setAttribute("extends", config.getModelBaseClass());
template.setAttribute("extends", config.getDefaultModelBaseClass());
template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
template.setAttribute("className", model.getGenratedClassName());
template.setAttribute(PACKAGE_NAME, config.getModelPackageName());
@ -196,7 +214,7 @@ public class LibraryCodeGenerator {
enumName = this.getNameGenerator().getEnumName(operationParam.getName());
template.setAttribute("className", enumName);
template.setAttribute("description", operationParam.getDescription());
template.setAttribute("enumValueType", this.getDataTypeMappingProvider().getObjectType(operationParam.getDataType(), true));
template.setAttribute("enumValueType", this.getDataTypeMappingProvider().getClassType(operationParam.getDataType(), true));
for (String allowableValue : operationParam.getAllowableValues()) {
if(operationParam.getDataType().equalsIgnoreCase("string")){
valuePrefix = valueSuffix = "\"";
@ -232,32 +250,37 @@ public class LibraryCodeGenerator {
private void generateAPIClasses(List<Resource> resources, StringTemplateGroup templateGroup) {
//delete previously generated files
FileUtil.cleanFiles(languageConfig.getResourceClassLocation());
FileUtil.clearFolder(languageConfig.getResourceClassLocation());
for(Resource resource : resources) {
List<ResourceMethod> methods = new ArrayList<ResourceMethod>();
List<String> imports = new ArrayList<String>();
imports.addAll(this.config.getDefaultServiceImports());
methods = resource.generateMethods(resource, dataTypeMappingProvider, nameGenerator);
StringTemplate template = templateGroup.getInstanceOf(API_OBJECT_TEMPLATE);
String className = resource.generateClassName(nameGenerator);
List<ResourceMethod> filteredMethods = new ArrayList<ResourceMethod>();
for(ResourceMethod method:methods){
if(!this.getCodeGenRulesProvider().isMethodIgnored(className, method.getName())){
filteredMethods.add(method);
try{
List<ResourceMethod> methods = new ArrayList<ResourceMethod>();
List<String> imports = new ArrayList<String>();
imports.addAll(this.config.getDefaultServiceImports());
methods = resource.generateMethods(resource, dataTypeMappingProvider, nameGenerator);
StringTemplate template = templateGroup.getInstanceOf(API_OBJECT_TEMPLATE);
String className = resource.generateClassName(nameGenerator);
List<ResourceMethod> filteredMethods = new ArrayList<ResourceMethod>();
for(ResourceMethod method:methods){
if(!this.getCodeGenRulesProvider().isMethodIgnored(className, method.getName())){
filteredMethods.add(method);
}
}
}
template.setAttribute("imports", imports);
template.setAttribute(PACKAGE_NAME, config.getApiPackageName());
template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
template.setAttribute("modelPackageName", config.getModelPackageName());
template.setAttribute("exceptionPackageName", languageConfig.getExceptionPackageName());
template.setAttribute("resource", className);
template.setAttribute("methods", filteredMethods);
template.setAttribute("extends", config.getServiceBaseClass(className));
template.setAttribute("imports", imports);
template.setAttribute(PACKAGE_NAME, config.getApiPackageName());
template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
template.setAttribute("modelPackageName", config.getModelPackageName());
template.setAttribute("exceptionPackageName", languageConfig.getExceptionPackageName());
template.setAttribute("resource", className);
template.setAttribute("methods", filteredMethods);
template.setAttribute("extends", config.getServiceBaseClass(className));
File aFile = new File(languageConfig.getResourceClassLocation()+ resource.generateClassName(nameGenerator) +languageConfig.getClassFileExtension());
writeFile(aFile, template.toString(), "API CLasses");
File aFile = new File(languageConfig.getResourceClassLocation()+ resource.generateClassName(nameGenerator) +languageConfig.getClassFileExtension());
writeFile(aFile, template.toString(), "API CLasses");
}catch(RuntimeException t){
System.out.println("Failed generating api class for the resource : " + resource.getResourcePath());
throw t;
}
}
}
@ -280,7 +303,7 @@ public class LibraryCodeGenerator {
List<String> imports = new ArrayList<String>();
imports.addAll(this.config.getDefaultModelImports());
imports.addAll(this.getDataTypeMappingProvider().getListImportPackages());
imports.addAll(this.getDataTypeMappingProvider().getListIncludes());
for(ModelField param : model.getFields()){
for(String importDef : param.getFieldDefinition(this.getDataTypeMappingProvider()).getImportDefinitions()){
if(!imports.contains(importDef)){
@ -292,7 +315,7 @@ public class LibraryCodeGenerator {
template.setAttribute("fields", model.getFields());
template.setAttribute("imports", imports);
template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
template.setAttribute("extends", config.getModelBaseClass());
template.setAttribute("extends", config.getDefaultModelBaseClass());
template.setAttribute(PACKAGE_NAME, config.getModelPackageName());
template.setAttribute("className", model.getGenratedClassName());
File aFile = new File(languageConfig.getModelClassLocation()+model.getGenratedClassName()+languageConfig.getClassFileExtension());
@ -349,4 +372,43 @@ public class LibraryCodeGenerator {
public NamingPolicyProvider getNameGenerator() {
return nameGenerator;
}
protected CodeGenRulesProvider readRulesProviderConfig(String rulesProviderLocation, ObjectMapper mapper, File configFile) {
CodeGenRulesProvider codeGenRules = null;
try {
codeGenRules = mapper.readValue(configFile, CodeGenRulesProvider.class);
} catch (IOException e) {
throw new CodeGenerationException("Java codegen rules configuration could not be read from the location : " + rulesProviderLocation);
}
return codeGenRules;
}
protected ApiConfiguration readApiConfiguration(String apiConfigLocation, ObjectMapper mapper, File configFile) {
ApiConfiguration configuration = null;
try {
configuration = mapper.readValue(configFile, ApiConfiguration.class);
} catch (IOException e) {
throw new CodeGenerationException("Api configuration could not be read from the location : " + apiConfigLocation);
}
return configuration;
}
protected LanguageConfiguration readLanguageConfiguration(String langConfigLocation, ObjectMapper mapper, File configFile) {
LanguageConfiguration langConfig = null;
try {
langConfig = mapper.readValue(configFile, LanguageConfiguration.class);
} catch (IOException e) {
throw new CodeGenerationException("Language configuration value could not be read from the location : " + langConfigLocation);
}
return langConfig;
}
protected LanguageConfiguration initializeLangConfig(LanguageConfiguration configuration) {
return configuration;
}
}

View File

@ -22,6 +22,8 @@ import java.util.List;
public class ResourceMethod {
private String title;
private String description;
private List<MethodArgument> arguments;
@ -53,6 +55,14 @@ public class ResourceMethod {
private Model inputModel;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}

View File

@ -96,6 +96,7 @@ public class SwaggerResourceDocReader {
//make connection to resource and get the documentation
for (String resourceURL : resourceURLs) {
resourceURL = resourceURL + "?api_key=" + apiKey;
WebResource aResource = apiClient.resource(resourceURL);
aResource.header("api_key", apiKey);
ClientResponse clientResponse = aResource.header("api_key", apiKey).get(ClientResponse.class);
@ -133,7 +134,7 @@ public class SwaggerResourceDocReader {
}else{
apiResourceUrl = trimResourceName( apiListResource);
}
apiResourceUrl = apiResourceUrl + "?api_key="+ apiKey;
WebResource aResource = apiClient.resource(apiResourceUrl);
aResource.header("api_key", apiKey);
ClientResponse clientResponse = aResource.header("api_key", apiKey).get(ClientResponse.class);

View File

@ -29,11 +29,11 @@ import java.util.Map;
*/
public class ApiConfiguration {
private Map<String, String> baseClassNames = new HashMap<String, String>();
private Map<String, String> serviceBaseClasses = new HashMap<String, String>();
private String defaultServiceBaseClass = "Object";
private String modelBaseClass = "Object";
private String defaultModelBaseClass = "Object";
/**
* Default model imports that we need to include in all service classes. This is needed because some times,
* we may need to write custom classes and those classes will not be known to code generation. To import those
@ -57,26 +57,22 @@ public class ApiConfiguration {
}
public String getDefaultServiceBaseClass() {
return defaultServiceBaseClass;
public Map<String, String> getServiceBaseClasses() {
return serviceBaseClasses;
}
public void setServiceBaseClasses(Map<String, String> serviceBaseClasses) {
this.serviceBaseClasses = serviceBaseClasses;
}
public void setDefaultServiceBaseClass(String defaultServiceBaseClass) {
this.defaultServiceBaseClass = defaultServiceBaseClass;
}
public Map<String, String> getBaseClassNames() {
return baseClassNames;
}
public void setBaseClassNames(Map<String, String> baseClassNames) {
this.baseClassNames = baseClassNames;
}
public void setServiceBaseClass(String defaultServiceBaseClass) {
this.defaultServiceBaseClass = defaultServiceBaseClass;
public String getDefaultServiceBaseClass() {
return this.defaultServiceBaseClass;
}
public void setServiceBaseClass(String serviceName, String className) {
@ -88,22 +84,22 @@ public class ApiConfiguration {
throw new CodeGenerationException("Error settting base class for service: class name was not provided");
}
baseClassNames.put(serviceName, className);
serviceBaseClasses.put(serviceName, className);
}
public String getServiceBaseClass(String serviceName) {
if(baseClassNames.containsKey(serviceName)){
return baseClassNames.get(serviceName);
if(serviceBaseClasses.containsKey(serviceName)){
return serviceBaseClasses.get(serviceName);
}
return defaultServiceBaseClass;
}
public String getModelBaseClass() {
return modelBaseClass;
public String getDefaultModelBaseClass() {
return defaultModelBaseClass;
}
public void setModelBaseClass(String modelBaseClass) {
this.modelBaseClass = modelBaseClass;
public void setDefaultModelBaseClass(String defaultModelBaseClass) {
this.defaultModelBaseClass = defaultModelBaseClass;
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.wordnik.swagger.codegen.config.java;
package com.wordnik.swagger.codegen.config;
import com.wordnik.swagger.codegen.config.RulesProvider;
@ -26,12 +26,12 @@ import java.util.List;
* Date: 5/31/11
* Time: 7:04 AM
*/
public class JavaCodeGenRulesProvider implements RulesProvider {
public class CodeGenRulesProvider implements RulesProvider {
private List<String> ignoreMethods = new ArrayList<String>();
private List<String> ignoreModels = new ArrayList<String>();
public JavaCodeGenRulesProvider() {
public CodeGenRulesProvider() {
}

View File

@ -19,7 +19,7 @@ package com.wordnik.swagger.codegen.config;
import java.util.List;
/**
* Implementations of this class is responsible for generating mapping between rest data types and language
* Implementations of this class is responsible for generating mapping between resource documentation data types and language
* specific data type
*
* User: ramesh
@ -40,14 +40,6 @@ public interface DataTypeMappingProvider {
*/
public boolean isPrimitiveType(String type);
/**
* provide the sttring that needs to be used when defining methods that returns no values
*
* Example: in java this value will be <code>void</code>
* @return
*/
public String getReturnTypeForVoidMethods();
/**
* Signature that should be used when returning list of given object type.
*
@ -112,10 +104,11 @@ public interface DataTypeMappingProvider {
public String generateSetInitialization(String typeClass);
/**
* Gets list of imports that needs to be included when used objects of type List.
* Gets list of items that needs to be included when referring list objects in model or resource classes.
*
* Example: in java while using lists we use an interface of <Code>List</Code> and implementation of
* <Code>ArrayList</Code>. SO the output will as follows:
* Example: In java this information is used as java imports. In java while using lists we use an interface of
* <Code>List</Code> and implementation of <Code>ArrayList</Code>. So the the implementation of this method in java
* language will be:
* <Code>
* List<String> imports = new ArrayList<String>();
imports.add("java.util.List");
@ -123,13 +116,14 @@ public interface DataTypeMappingProvider {
* </Code>
* @return
*/
public List<String> getListImportPackages();
public List<String> getListIncludes();
/**
* Gets list of imports that needs to be included when used objects of type Map.
* Gets list of items that needs to be included when referring map objects in model or resource classes.
*
* Example: in java while using maps we use an interface of <Code>Map</Code> and implementation of
* <Code>HashMap</Code>. SO the output will as follows:
* Example: In java this information is used as java imports. In java while using map we use an interface of
* <Code>Map</Code> and implementation of <Code>HashMap</Code>. So the the implementation of this method in java
* language will be:
* <Code>
* List<String> imports = new ArrayList<String>();
imports.add("java.util.Map");
@ -137,13 +131,14 @@ public interface DataTypeMappingProvider {
* </Code>
* @return
*/
public List<String> getMapImportPackages();
public List<String> getMapIncludes();
/**
* Gets list of imports that needs to be included when used objects of type Set.
* Gets list of items that needs to be included when referring set objects in model or resource classes.
*
* Example: in java while using sets we use an interface of <Code>Set</Code> and implementation of
* <Code>HashSet</Code>. SO the output will as follows:
* <Code>HashSet</Code>. So the the implementation of this method in java
* language will be:
* <Code>
* List<String> imports = new ArrayList<String>();
imports.add("java.util.Set");
@ -151,47 +146,39 @@ public interface DataTypeMappingProvider {
* </Code>
* @return
*/
public List<String> getSetImportPackages();
public List<String> getSetIncludes();
/**
* Gets list of imports that needs to be included when used objects of type Date.
* Gets list of items that needs to be included when referring date objects in model or resource classes.
*
* Example: in java while using Data we use <Codejava.util.Date</Code>. So the output will as follows:
* Example: in java while using Data we use <Code> java.util.Date</Code>. So the output will as follows:
* <Code>
* List<String> imports = new ArrayList<String>();
imports.add("java.util.Date");
* </Code>
* @return
*/
public List<String> getDateImports();
public List<String> getDateIncludes();
/**
* Object type definition for a given input
* Class type definition for a given input.
*
* Example: In java language: For inputs Integer and primitive true, the class type will be int, if primitiveObject is false
* the class type will be Integer. For inputs user the class type will be User as the input object is not primitive.
* for input List[user] the class type will be <Code> List<User> </Code> . For input Map[int, String] the equivalent java
* translation will be <Code> Map<Integer, String> </Code>
*
* @param type
* @param primitiveObject
* @param primitiveObject This argument used to indicate, if the given input type is primitive,
* should we return primitive types or primitive classes.
* @return
*/
public String getObjectType(String type, boolean primitiveObject);
public String getClassType(String type, boolean primitiveObject);
/**
* Gets the value of return type converted from web service response documentation.
* If the class contains generics then this will return type of generics object else returns same object
*
* Example: If the resource documentation ays return type as List[User] the equivalent translation for java will be
*
* <Code> List<User ></Code>
*
* If the input is Map[int, String] the equivalent java translation will be <Code> Map<Integer, String> </Code>
* @param type
* @return
*/
public String getReturnValueType(String type);
/**
* Gets the class of return values from web service response documentation. If the service returns list the class
* indicates type of object in the list
*
* Example: If the resource documentation ays return type as List[User] the equivalent translation for java will be
* Example: If the resource documentation says return type as List[User] the equivalent generic type for java will be
*
* <Code> User </Code>
*
@ -199,5 +186,5 @@ public interface DataTypeMappingProvider {
* @param type
* @return
*/
public String getReturnClassType(String type);
public String getGenericType(String type);
}

View File

@ -31,7 +31,7 @@ public class LanguageConfiguration {
private String structureLocation;
private String apiServerRootLocation;
private String libraryHome;
private String modelClassLocation;
@ -102,11 +102,11 @@ public class LanguageConfiguration {
this.structureLocation = structureLocation;
}
public String getApiServerRootLocation() {
return apiServerRootLocation;
public String getLibraryHome() {
return libraryHome;
}
public void setApiServerRootLocation(String apiServerRootLocation) {
this.apiServerRootLocation = apiServerRootLocation;
public void setLibraryHome(String libraryHome) {
this.libraryHome = libraryHome;
}
}

View File

@ -17,7 +17,7 @@
package com.wordnik.swagger.codegen.config;
/**
* Implementor of this class is responsible for generating the names for service classes and methods in
* Implementation of this class is responsible for generating the names for service classes and methods in
* each of those service classes
*
* User: ramesh
@ -110,7 +110,7 @@ public interface NamingPolicyProvider {
/**
* Gets the signature of the method that gets value for give attribute name.
*
* Example: If class name is user and attibute name is email the out in java language will be
* Example: If class name is user and attribute name is email the out in java language will be
* <code>user.getEmail()</code>
*
* @param className

View File

@ -33,7 +33,22 @@ import java.util.Map;
*/
public interface RulesProvider {
/**
* Checks if the method needs to be ignored when generating libraries.
*
* This is used if clients want to override the implementation of the method and not use methods generated by the code gen.
*
* @param serviceName
* @param methodName
* @return
*/
public boolean isMethodIgnored(String serviceName, String methodName);
/**
* Checks if model needs to be ignored in code generation.
*
* @param modelName
* @return
*/
public boolean isModelIgnored(String modelName);
}

View File

@ -27,6 +27,8 @@ import com.wordnik.swagger.exception.CodeGenerationException;
*/
public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider {
public static String INPUT_OBJECT_SUFFIX = "Input";
/**
* gets the name of class that is responsible for tracking current library version
* @return
@ -36,7 +38,7 @@ public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider {
}
/**
* Converts the first character of the input into string.
* Converts the first character of the input into upper case .
* Example: If the input is word, the return value will be Word
* @param input
* @return
@ -45,13 +47,13 @@ public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider {
if(input != null && input.length() > 0) {
return input.substring(0,1).toUpperCase() + input.substring(1);
}else{
throw new CodeGenerationException("Error converting input to first letter caps becuase of null input");
throw new CodeGenerationException("Error converting input to first letter caps becuase of null or empty input");
}
}
/**
* Converts the first character of the input into string.
* Example: If the input is word, the return value will be Word
* Converts the first character of the input into lower case.
* Example: If the input is GetWord, the return value will be getWord
* @param input
* @return
*/
@ -59,11 +61,21 @@ public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider {
if(input != null && input.length() > 0) {
return input.substring(0,1).toLowerCase() + input.substring(1);
}else{
throw new CodeGenerationException("Error converting input to first letter to lower because of null input");
throw new CodeGenerationException("Error converting input to first letter to lower because of null or empty input");
}
}
public String getServiceName(String resourcePath) {
/**
* Generate name of the service from resource path.
*
* Example: if input is /user.json the generated name for this path will be UserAPI
* If the input is /user.json/{userId}, the service name will still be generated as UserAPI
*
* @param resourcePath
* @return
*/
public String getServiceName(String resourcePath) {
String className = null;
int index = resourcePath.indexOf(".");
if(index >= 0) {
@ -79,7 +91,7 @@ public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider {
}
}
return className+ "API";
}
}
/**
* Generates the name of service methods.
@ -96,8 +108,22 @@ public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider {
}
/**
* For input UserAPI and resource path /findUserById the suggested input object name will be: UserFindUserByIdInput
*
* If the input path is /{userId}/delete the sugegsted name will be UserDeleteInput. The path parameters are ignored
* in generating the input object name
*
* Note: Input objects are only created when the number of input arguments in a method exceeds certain number so <br/> that the method signatures are clean
*
*
* @param serviceName
* @param resourcePath
* @return
*/
public String getInputObjectName(String serviceName, String resourcePath) {
//Since service name has API at the end remove that fromt he name
String inputobjectName = serviceName.substring(0, serviceName.length() - 3);
String[] pathElements = resourcePath.split("/");
@ -108,7 +134,7 @@ public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider {
if(pathElement != null && pathElement.length() > 0) {
int position = pathElement.indexOf("{");
if(position < 0) {
inputobjectName = inputobjectName + applyClassNamingPolicy(pathElement) + Model.INPUT_OBJECT_SUFFIX;
inputobjectName = inputobjectName + applyClassNamingPolicy(pathElement) + INPUT_OBJECT_SUFFIX;
}
}
}

View File

@ -76,33 +76,10 @@ public class JavaDataTypeMappingProvider implements DataTypeMappingProvider {
return false;
}
/**
* If the data type is primitive and it is expecting object structure then return primitive objects
* else return primitive types
* @param type
* @param primitiveObject -- indicates if the object is primitive or not
* @return
*/
public String getObjectType(String type, boolean primitiveObject) {
if(isPrimitiveType(type)){
if(primitiveObject){
return primitiveObjectMap.get(type);
}else{
return primitiveValueMap.get(type);
}
}else{
return nameGenerator.applyClassNamingPolicy(type);
}
}
public String getListReturnTypeSignature(String typeClass) {
return "List<"+nameGenerator.applyClassNamingPolicy(typeClass)+">";
}
public String getReturnTypeForVoidMethods() {
return "void";
}
public String getMapReturnTypeSignature(String typeClass) {
return "Map<"+nameGenerator.applyClassNamingPolicy(typeClass)+">";
}
@ -123,28 +100,28 @@ public class JavaDataTypeMappingProvider implements DataTypeMappingProvider {
return " new HashSet<"+nameGenerator.applyClassNamingPolicy(typeClass)+">()";
}
public List<String> getListImportPackages() {
public List<String> getListIncludes() {
List<String> imports = new ArrayList<String>();
imports.add("java.util.List");
imports.add("java.util.ArrayList");
return imports;
}
public List<String> getMapImportPackages() {
public List<String> getMapIncludes() {
List<String> imports = new ArrayList<String>();
imports.add("java.util.Map");
imports.add("java.util.HashMap");
return imports;
}
public List<String> getSetImportPackages() {
public List<String> getSetIncludes() {
List<String> imports = new ArrayList<String>();
imports.add("java.util.Set");
imports.add("java.util.HashSet");
return imports; }
public List<String> getDateImports() {
public List<String> getDateIncludes() {
List<String> imports = new ArrayList<String>();
imports.add("java.util.Date");
return imports;
@ -157,21 +134,21 @@ public class JavaDataTypeMappingProvider implements DataTypeMappingProvider {
* @param type
* @return
*/
public String getReturnClassType(String type) {
public String getGenericType(String type) {
String classShortName = "";
if(type.startsWith("List[")){
classShortName = type.substring(5, type.length()-1);
classShortName = getObjectType(classShortName, true);
classShortName = getClassType(classShortName, true);
}else if (type.startsWith("Map[")) {
classShortName = type.substring(4, type.length()-1);
classShortName = getObjectType(classShortName, true);
classShortName = getClassType(classShortName, true);
}else if (type.startsWith("Set[")) {
classShortName = type.substring(4, type.length()-1);
classShortName = getObjectType(classShortName, true);
}else if (type.equals("ok")) {
classShortName = getClassType(classShortName, true);
}else if (type.equalsIgnoreCase("ok")) {
classShortName = "void";
}else{
classShortName = getObjectType(type, true);
classShortName = getClassType(type, true);
}
return classShortName;
}
@ -184,23 +161,44 @@ public class JavaDataTypeMappingProvider implements DataTypeMappingProvider {
* @param type
* @return
*/
public String getReturnValueType(String type) {
public String getClassType(String type, boolean primitiveObject) {
if(type.equalsIgnoreCase("void")|| type.equalsIgnoreCase("ok")){
return "void";
}
String classShortName = "";
if(type.startsWith("List[")){
classShortName = type.substring(5, type.length()-1);
classShortName = "List<"+getObjectType(classShortName, true)+">";
classShortName = "List<"+ getClassName(classShortName, true)+">";
}else if (type.startsWith("Map[")) {
classShortName = type.substring(4, type.length()-1);
classShortName = "Map<"+getObjectType(classShortName, true) +">";
classShortName = "Map<"+ getClassName(classShortName, true) +">";
}else if (type.startsWith("Set[")) {
classShortName = type.substring(4, type.length()-1);
classShortName = "Set<"+getObjectType(classShortName, true) +">";
classShortName = "Set<"+ getClassName(classShortName, true) +">";
}else{
classShortName = getObjectType(type, true);
classShortName = getClassName(type, true);
}
return classShortName;
}
/**
* If the data type is primitive and it is expecting object structure then return primitive objects
* else return primitive types
* @param type
* @param primitiveObject -- indicates if the object is primitive or not
* @return
*/
private String getClassName(String type, boolean primitiveObject) {
if(isPrimitiveType(type)){
if(primitiveObject){
return primitiveObjectMap.get(type);
}else{
return primitiveValueMap.get(type);
}
}else{
return nameGenerator.applyClassNamingPolicy(type);
}
}
}

View File

@ -18,6 +18,7 @@ package com.wordnik.swagger.codegen.config.java;
import com.wordnik.swagger.codegen.LibraryCodeGenerator;
import com.wordnik.swagger.codegen.config.ApiConfiguration;
import com.wordnik.swagger.codegen.config.CodeGenRulesProvider;
import com.wordnik.swagger.codegen.config.LanguageConfiguration;
import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider;
import com.wordnik.swagger.codegen.util.FileUtil;
@ -26,7 +27,6 @@ import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
/**
@ -40,60 +40,19 @@ public class JavaLibCodeGen extends LibraryCodeGenerator {
if(args.length < 1){
throw new CodeGenerationException("Invalid number of arguments passed: No command line argument was passed to the program for config json");
}
String configPath = args[0];
JavaLibCodeGen codeGenerator = new JavaLibCodeGen(configPath);
codeGenerator.generateCode();
}
public JavaLibCodeGen(String configPath){
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final File configFile = new File(configPath);
this.setApiConfig(readApiConfiguration(configPath, mapper, configFile));
this.setCodeGenRulesProvider(readRulesProviderConfig(configPath, mapper, configFile));
this.setLanguageConfig( initializeLangConfig(readLanguageConfiguration(configPath, mapper, configFile)) );
super(configPath);
this.setDataTypeMappingProvider(new JavaDataTypeMappingProvider());
this.setNameGenerator(new CamelCaseNamingPolicyProvider());
}
private JavaCodeGenRulesProvider readRulesProviderConfig(String rulesProviderLocation, ObjectMapper mapper, File configFile) {
JavaCodeGenRulesProvider javaCodeGenRules = null;
try {
javaCodeGenRules = mapper.readValue(configFile, JavaCodeGenRulesProvider.class);
} catch (IOException e) {
throw new CodeGenerationException("Java codegen rules configuration could not be read from the location : " + rulesProviderLocation);
}
return javaCodeGenRules;
}
private ApiConfiguration readApiConfiguration(String apiConfigLocation, ObjectMapper mapper, File configFile) {
ApiConfiguration configuration = null;
try {
configuration = mapper.readValue(configFile, ApiConfiguration.class);
} catch (IOException e) {
throw new CodeGenerationException("Api configuration could not be read from the location : " + apiConfigLocation);
}
return configuration;
}
private LanguageConfiguration readLanguageConfiguration(String langConfigLocation, ObjectMapper mapper, File configFile) {
LanguageConfiguration langConfig = null;
try {
langConfig = mapper.readValue(configFile, LanguageConfiguration.class);
} catch (IOException e) {
throw new CodeGenerationException("Language configuration value could not be read from the location : " + langConfigLocation);
}
return langConfig;
}
private LanguageConfiguration initializeLangConfig(LanguageConfiguration javaConfiguration) {
@Override
protected LanguageConfiguration initializeLangConfig(LanguageConfiguration javaConfiguration) {
javaConfiguration.setClassFileExtension(".java");
javaConfiguration.setTemplateLocation("conf/java/templates");
javaConfiguration.setStructureLocation("conf/java/structure");
@ -103,10 +62,10 @@ public class JavaLibCodeGen extends LibraryCodeGenerator {
//create ouput directories
FileUtil.createOutputDirectories(javaConfiguration.getModelClassLocation(), javaConfiguration.getClassFileExtension());
FileUtil.createOutputDirectories(javaConfiguration.getResourceClassLocation(), javaConfiguration.getClassFileExtension());
FileUtil.cleanFiles(javaConfiguration.getApiServerRootLocation()+ "/src/main/java/com/wordnik/swagger/common");
FileUtil.cleanFiles(javaConfiguration.getApiServerRootLocation()+ "/src/main/java/com/wordnik/swagger/exception");
FileUtil.cleanFiles(javaConfiguration.getApiServerRootLocation()+ "/src/main/java/com/wordnik/swagger/annotations");
FileUtil.copyDirectory(new File(javaConfiguration.getStructureLocation()), new File(javaConfiguration.getApiServerRootLocation()));
FileUtil.clearFolder(javaConfiguration.getLibraryHome() + "/src/main/java/com/wordnik/swagger/common");
FileUtil.clearFolder(javaConfiguration.getLibraryHome() + "/src/main/java/com/wordnik/swagger/exception");
FileUtil.clearFolder(javaConfiguration.getLibraryHome() + "/src/main/java/com/wordnik/swagger/annotations");
FileUtil.copyDirectory(new File(javaConfiguration.getStructureLocation()), new File(javaConfiguration.getLibraryHome()));
return javaConfiguration;
}

View File

@ -40,8 +40,6 @@ public class Endpoint {
private List<ResourceMethod> methods;
private List<ErrorResponse> errorResponses;
public String getPath() {
return path;
}
@ -72,36 +70,15 @@ public class Endpoint {
public void setOperations(List<EndpointOperation> operations) {
this.operations = operations;
setOperationResponses();
}
public List<ErrorResponse> getErrorResponses() {
return errorResponses;
}
public void setErrorResponses(List<ErrorResponse> errorResponses) {
this.errorResponses = errorResponses;
setOperationResponses();
}
private void setOperationResponses() {
if(this.errorResponses != null && this.operations != null && this.operations.size() > 0 ){
for(EndpointOperation operation: this.operations){
if(operation.getResponse() != null & operation.getResponse().size() > 0){
for(Response response : operation.getResponse()){
response.setErrorResponses(this.errorResponses);
}
}
}
}
}
public List<ResourceMethod> generateMethods(Resource resource, DataTypeMappingProvider dataTypeMapper, NamingPolicyProvider nameGenerator) {
if(methods == null){
methods = new ArrayList<ResourceMethod>();
if(getOperations() != null) {
for(EndpointOperation operation: getOperations()) {
if(!operation.isDeprecated() && areModelsAvailable(operation.getParameters(), resource, dataTypeMapper)) {
//Note: Currently we are generating methods for depricated APIs also, We should provide this deprecation info on generated APIs also.
if(areModelsAvailable(operation.getParameters(), resource, dataTypeMapper)) {
methods.add(operation.generateMethod(this, resource, dataTypeMapper, nameGenerator));
}
}

View File

@ -49,9 +49,6 @@ public class EndpointOperation {
private boolean open;
@Deprecated
private List<Response> response;
private String responseClass;
private List<ModelField> parameters;
@ -62,11 +59,18 @@ public class EndpointOperation {
private List<String> tags;
@Deprecated
private String suggestedName;
private String nickname;
private List<ErrorResponse> errorResponses;
public List<ErrorResponse> getErrorResponses() {
return errorResponses;
}
public void setErrorResponses(List<ErrorResponse> errorResponses) {
this.errorResponses = errorResponses;
}
public String getHttpMethod() {
return httpMethod;
}
@ -99,26 +103,15 @@ public class EndpointOperation {
this.open = open;
}
public List<Response> getResponse() {
return response;
}
public void setResponse(List<Response> response) {
this.response = response;
}
public String getResponseClass() {
return responseClass;
}
public void setResponseClass(String responseClass) {
this.responseClass = responseClass;
this.setResponse(new ArrayList<Response>());
Response response = new Response();
response.setValueType(this.responseClass);
this.getResponse().add(response);
}
public List<ModelField> getParameters() {
return parameters;
}
@ -134,18 +127,9 @@ public class EndpointOperation {
public void setDeprecated(boolean deprecated) {
this.deprecated = deprecated;
}
public String getSuggestedName() {
return suggestedName;
}
public void setSuggestedName(String suggestedName) {
this.suggestedName = suggestedName;
}
public void setNickname(String nickname) {
this.nickname = nickname;
this.suggestedName = nickname;
}
public String getNickname() {
@ -165,8 +149,9 @@ public class EndpointOperation {
if(method == null){
method = new ResourceMethod();
//add method description
method.setDescription(this.getSummary() + "\n " + getNotes());
method.setTitle(this.getSummary() );
method.setDescription(this.getNotes());
//add method name
//get resource path for making web service call
/**
@ -204,7 +189,7 @@ public class EndpointOperation {
}
}
method.setResourcePath(endPoint.getPath());
method.setName(nameGenerator.getMethodName(endPoint.getPath(), this.getSuggestedName()));
method.setName(nameGenerator.getMethodName(endPoint.getPath(), this.getNickname()));
//create method argument
/**
@ -256,7 +241,7 @@ public class EndpointOperation {
modelField.setName("postObject");
}
anArgument.setName(modelField.getName());
anArgument.setDataType(dataTypeMapper.getReturnValueType(modelField.getDataType()));
anArgument.setDataType(dataTypeMapper.getClassType(modelField.getDataType(), false));
anArgument.setDescription(modelField.getDescription());
arguments.add(anArgument);
method.setPostObject(true);
@ -264,7 +249,7 @@ public class EndpointOperation {
if(modelField.isAllowMultiple() && dataTypeMapper.isPrimitiveType(modelField.getDataType())){
anArgument.setDataType(dataTypeMapper.getListReturnTypeSignature(
dataTypeMapper.getReturnValueType(modelField.getDataType())));
dataTypeMapper.getClassType(modelField.getDataType(), false)));
}
anArgument.setInputModelClassArgument(inputobjectName, nameGenerator);
}
@ -316,10 +301,8 @@ public class EndpointOperation {
method.setMethodType(this.getHttpMethod());
//get return value
List<Response> response = this.getResponse();
method.setReturnValue(dataTypeMapper.getReturnValueType(response.get(0).getValueType()));
method.setReturnClassName(dataTypeMapper.getReturnClassType(response.get(0).getValueType()));
method.setReturnValue(dataTypeMapper.getClassType(responseClass, false));
method.setReturnClassName(dataTypeMapper.getGenericType(responseClass));
//get description string for exception
@ -334,15 +317,11 @@ public class EndpointOperation {
*/
private String calculateExceptionMessage() {
StringBuilder errorMessage = new StringBuilder();
if(this.getResponse() != null) {
for(Response response: this.getResponse()) {
if(response.getErrorResponses() != null) {
for(ErrorResponse errorResponse : response.getErrorResponses()){
errorMessage.append(errorResponse.getCode() + " - " + errorResponse.getReason() +" ");
}
}
}
}
if(this.getErrorResponses() != null) {
for(ErrorResponse errorResponse : this.getErrorResponses()){
errorMessage.append(errorResponse.getCode() + " - " + errorResponse.getReason() +" ");
}
}
return errorMessage.toString();
}

View File

@ -25,8 +25,6 @@ import java.util.List;
*/
public class Model {
public static String INPUT_OBJECT_SUFFIX = "Input";
private String name;
private String description;

View File

@ -175,12 +175,12 @@ public class ModelField {
fieldDefinition = new FieldDefinition();
String type = paramType.trim();
if(type.contains("date")||type.contains("Date") ){
fieldDefinition.getImportDefinitions().add("java.util.Date");
fieldDefinition.getImportDefinitions().addAll(dataTypeMapper.getDateIncludes());
}
if(type.startsWith("List[")){
fieldDefinition.getImportDefinitions().addAll(dataTypeMapper.getListImportPackages());
fieldDefinition.getImportDefinitions().addAll(dataTypeMapper.getListIncludes());
String entryType = type.substring(5, type.length()-1);
entryType = dataTypeMapper.getObjectType(entryType, true);
entryType = dataTypeMapper.getClassType(entryType, true);
String returnType = dataTypeMapper.getListReturnTypeSignature(entryType);
fieldDefinition.setReturnType(returnType);
fieldDefinition.setInitialization(" = " + dataTypeMapper.generateListInitialization(entryType));
@ -191,9 +191,9 @@ public class ModelField {
}
}else if(type.startsWith("Set[")){
fieldDefinition.getImportDefinitions().addAll(dataTypeMapper.getSetImportPackages());
fieldDefinition.getImportDefinitions().addAll(dataTypeMapper.getSetIncludes());
String entryType = type.substring(4, type.length()-1);
entryType = dataTypeMapper.getObjectType(entryType, true);
entryType = dataTypeMapper.getClassType(entryType, true);
String returnType = dataTypeMapper.getSetReturnTypeSignature(entryType);
fieldDefinition.setReturnType(returnType);
fieldDefinition.setInitialization(" = " + dataTypeMapper.generateSetInitialization(entryType));
@ -204,13 +204,13 @@ public class ModelField {
}
}else if (type.startsWith("Map[")) {
fieldDefinition.getImportDefinitions().addAll(dataTypeMapper.getMapImportPackages());
fieldDefinition.getImportDefinitions().addAll(dataTypeMapper.getMapIncludes());
String keyClass, entryClass = "";
String entryType = type.substring(4, type.length()-1);
keyClass = entryType.substring(0, entryType.indexOf(",") );
entryClass = entryType.substring(entryType.indexOf(",") + 1, entryType.length());
//entryType = dataTypeMapper.getObjectType(entryType, true);
entryType = dataTypeMapper.getObjectType(keyClass, true) + "," + dataTypeMapper.getObjectType(entryClass, true);
//entryType = dataTypeMapper.getClassType(entryType, true);
entryType = dataTypeMapper.getClassType(keyClass, true) + "," + dataTypeMapper.getClassType(entryClass, true);
String returnType = dataTypeMapper.getMapReturnTypeSignature(entryType);
fieldDefinition.setReturnType(returnType);
fieldDefinition.setInitialization("= " + dataTypeMapper.generateMapInitialization(entryType));
@ -220,7 +220,7 @@ public class ModelField {
fieldDefinition.setName(this.getName());
}
}else{
fieldDefinition.setReturnType(dataTypeMapper.getObjectType(type, false));
fieldDefinition.setReturnType(dataTypeMapper.getClassType(type, false));
fieldDefinition.setName(this.getName());
}

View File

@ -39,6 +39,9 @@ public class Resource {
@JsonProperty("swaggerVersion")
private String swaggerVersion;
@JsonProperty("resourcePath")
private String resourcePath;
@JsonProperty("apis")
private List<Endpoint> endPoints = new ArrayList<Endpoint>();
@ -65,7 +68,6 @@ public class Resource {
this.apiVersion = apiVersion;
}
//TODO rename the JSON property too after the sandbox var has been renamed
@JsonProperty("swaggerVersion")
public String getSwaggerVersion() {
return swaggerVersion;
@ -76,6 +78,16 @@ public class Resource {
this.swaggerVersion = swaggerVersion;
}
@JsonProperty("resourcePath")
public String getResourcePath() {
return resourcePath;
}
@JsonProperty("resourcePath")
public void setResourcePath(String resourcePath) {
this.resourcePath = resourcePath;
}
@JsonProperty("apis")
public List<Endpoint> getEndPoints() {
return endPoints;

View File

@ -1,60 +0,0 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wordnik.swagger.codegen.resource;
import java.util.List;
/**
* User: ramesh
* Date: 3/31/11
* Time: 7:55 AM
*/
public class Response {
private String valueType;
private String condition;
private List<ErrorResponse> errorResponses;
public String getValueType() {
return valueType;
}
public void setValueType(String valueType) {
this.valueType = valueType;
}
public String getCondition() {
return condition;
}
public void setCondition(String condition) {
this.condition = condition;
}
public List<ErrorResponse> getErrorResponses() {
return errorResponses;
}
public void setErrorResponses(List<ErrorResponse> errorResponses) {
this.errorResponses = errorResponses;
}
}

View File

@ -27,6 +27,13 @@ import java.io.*;
*/
public class FileUtil {
/**
* Creates directory if doesn't exists and also cleans the files of given type if directory already contains some
* files.
*
* @param classLocation
* @param fileExtension
*/
public static void createOutputDirectories(String classLocation, String fileExtension) {
File outputLocation = new File(classLocation);
outputLocation.mkdirs(); //make folder if necessary
@ -35,6 +42,11 @@ public class FileUtil {
}
/**
* Deletes a fingle file and returns false fi file doesn't exists
* @param sFilePath
* @return
*/
public static boolean deleteFile(String sFilePath) {
File oFile = new File(sFilePath);
if (!oFile.exists()) {
@ -48,7 +60,7 @@ public class FileUtil {
* Deleet all the files from the specified location
* @param directoryLocation
*/
public static void cleanFiles(String directoryLocation) {
public static void clearFolder(String directoryLocation) {
File fDir = new File(directoryLocation);
File[] files = fDir.listFiles();
for(File aFile : files) {