709 lines
29 KiB
Groovy
709 lines
29 KiB
Groovy
apply plugin: 'com.android.application'
|
|
|
|
buildscript {
|
|
repositories {
|
|
jcenter()
|
|
}
|
|
dependencies {
|
|
classpath 'org.yaml:snakeyaml:1.8'
|
|
classpath 'com.squareup:javapoet:1.8.0'
|
|
}
|
|
}
|
|
|
|
|
|
import com.squareup.javapoet.*
|
|
import javafx.util.Pair
|
|
import org.yaml.snakeyaml.Yaml
|
|
|
|
import javax.lang.model.element.Modifier
|
|
|
|
abstract class SchemeObject {
|
|
|
|
abstract void writeToFile(File directory, Map<String, SchemeObject> objects, String appPackage)
|
|
|
|
}
|
|
//TODO: missable in future
|
|
//TODO: move out of allvariants - too much
|
|
//TODO: refactor code
|
|
class ImportObject extends SchemeObject {
|
|
|
|
static final String GROUP_NAME = "imports"
|
|
|
|
final String name
|
|
final String fullName
|
|
|
|
ImportObject(String value) {
|
|
fullName = value.trim()
|
|
name = fullName.substring(fullName.lastIndexOf('.') + 1)
|
|
}
|
|
|
|
@Override
|
|
void writeToFile(final File directory, Map<String, SchemeObject> objects, String appPackage) {
|
|
//do nothing - imports are for other objects
|
|
}
|
|
|
|
}
|
|
|
|
class EnumObject extends SchemeObject {
|
|
|
|
enum Type {
|
|
STRING, NUMBER, BOOLEAN
|
|
}
|
|
|
|
static final String PREFIX = "enum "
|
|
|
|
final String name
|
|
Type type
|
|
|
|
Map<String, Object> values = new HashMap<>()
|
|
|
|
EnumObject(String name, Map<String, String> values) {
|
|
this.name = name.trim()
|
|
|
|
for (Map.Entry<String, String> entry : values) {
|
|
final apiValue = entry.value.trim()
|
|
if (apiValue.isEmpty()) {
|
|
throw new Exception("Name of enum is empty")
|
|
}
|
|
if (this.values.containsKey(entry.key)) {
|
|
throw new Exception("Name '" + value + "' already added to enum")
|
|
}
|
|
Type type = typeOf(apiValue)
|
|
if (this.type == null) {
|
|
this.type = type
|
|
} else if (this.type != type) {
|
|
throw new Exception("Type of value '" + value + "' conflicts with previous value type: " + this.type)
|
|
}
|
|
this.values.put(entry.key, apiValue)
|
|
}
|
|
}
|
|
|
|
@Override
|
|
void writeToFile(File directory, Map<String, SchemeObject> objects, String appPackage) {
|
|
TypeSpec.Builder enumBuilder = TypeSpec.enumBuilder(name)
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addSuperinterface(ClassName.bestGuess("ru.touchin.templates.logansquare.LoganSquareEnum"))
|
|
|
|
enumBuilder.addField(FieldSpec.builder(ClassName.get(String.class), "valueName",
|
|
Modifier.PRIVATE,
|
|
Modifier.FINAL)
|
|
.addAnnotation(ClassName.bestGuess("android.support.annotation.NonNull"))
|
|
.build())
|
|
|
|
enumBuilder.addMethod(MethodSpec.constructorBuilder()
|
|
.addParameter(ClassName.get(String.class), "valueName", Modifier.FINAL)
|
|
.addStatement("this.valueName = valueName")
|
|
.build())
|
|
|
|
enumBuilder.addMethod(MethodSpec.methodBuilder("getValueName")
|
|
.returns(ClassName.get(String.class))
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addAnnotation(ClassName.get(Override.class))
|
|
.addAnnotation(ClassName.bestGuess("android.support.annotation.NonNull"))
|
|
.addStatement("return valueName")
|
|
.build())
|
|
|
|
enumBuilder.addType(TypeSpec.classBuilder("LoganSquareConverter")
|
|
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
|
.superclass(ParameterizedTypeName.get(ClassName.bestGuess("ru.touchin.templates.logansquare.LoganSquareEnumConverter"), ClassName.bestGuess(name)))
|
|
.addMethod(MethodSpec.constructorBuilder()
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addStatement("super(values())")
|
|
.build())
|
|
.build())
|
|
|
|
for (Map.Entry<String, Object> entry : values) {
|
|
if (type == Type.STRING) {
|
|
enumBuilder.addEnumConstant(entry.key, TypeSpec.anonymousClassBuilder("\$S", entry.value).build())
|
|
} else {
|
|
enumBuilder.addEnumConstant(entry.key, TypeSpec.anonymousClassBuilder("\$L", entry.value).build())
|
|
}
|
|
}
|
|
|
|
JavaFile.builder(appPackage, enumBuilder.build()).indent(" ").build().writeTo(directory);
|
|
}
|
|
|
|
Type typeOf(String value) {
|
|
if (value.equals("true") || value.equals("false")) {
|
|
return Type.BOOLEAN
|
|
} else {
|
|
try {
|
|
Integer.parseInt(value)
|
|
return Type.NUMBER
|
|
} catch (NumberFormatException ignored) {
|
|
return Type.STRING
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
enum FieldType {
|
|
|
|
BOOLEAN(TypeName.BOOLEAN, ClassName.get(Boolean.class), false),
|
|
INT(TypeName.INT, ClassName.get(Integer.class), false),
|
|
LONG(TypeName.LONG, ClassName.get(Long.class), false),
|
|
FLOAT(TypeName.FLOAT, ClassName.get(Float.class), false),
|
|
DOUBLE(TypeName.DOUBLE, ClassName.get(Double.class), false),
|
|
STRING(ClassName.get(String.class), false),
|
|
LIST(ClassName.get(List.class), true),
|
|
MAP(ClassName.get(Map.class), true),
|
|
DATE_TIME(ClassName.bestGuess("org.joda.time.DateTime"), false),
|
|
ENUM(false),
|
|
MODEL(true),
|
|
IMPORTED_MODEL(true),
|
|
GENERIC(true)
|
|
|
|
final TypeName primitiveTypeName
|
|
final TypeName nonPrimitiveTypeName
|
|
final boolean ableToInnerValidate
|
|
|
|
FieldType(final boolean ableToInnerValidate) {
|
|
this(null, null, ableToInnerValidate)
|
|
}
|
|
|
|
FieldType(final TypeName typeName, final boolean ableToInnerValidate) {
|
|
this(typeName, typeName, ableToInnerValidate)
|
|
}
|
|
|
|
FieldType(final TypeName primitiveTypeName, final TypeName nonPrimitiveTypeName, final boolean ableToInnerValidate) {
|
|
this.primitiveTypeName = primitiveTypeName
|
|
this.nonPrimitiveTypeName = nonPrimitiveTypeName
|
|
this.ableToInnerValidate = ableToInnerValidate
|
|
}
|
|
|
|
static FieldType get(String typeString, Map<String, SchemeObject> objects) {
|
|
switch (typeString) {
|
|
case "string":
|
|
case "String": return STRING
|
|
case "List":
|
|
case "Collection":
|
|
case "LinkedList":
|
|
case "ArrayList": return LIST
|
|
case "Map":
|
|
case "HashMap":
|
|
case "TreeMap":
|
|
case "LinkedHashMap": return MAP
|
|
case "int":
|
|
case "Integer": return INT
|
|
case "boolean":
|
|
case "Boolean": return BOOLEAN
|
|
case "long":
|
|
case "Long": return LONG
|
|
case "float":
|
|
case "Float": return FLOAT
|
|
case "double":
|
|
case "Double": return DOUBLE
|
|
case "date":
|
|
case "datetime":
|
|
case "DateTime": return DATE_TIME
|
|
default:
|
|
SchemeObject object = objects.get(typeString);
|
|
if (object instanceof EnumObject) {
|
|
return ENUM
|
|
}
|
|
if (object instanceof ImportObject) {
|
|
return IMPORTED_MODEL
|
|
}
|
|
if (object instanceof ClassObject) {
|
|
return MODEL
|
|
}
|
|
return GENERIC
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
class TypeNameUtils {
|
|
|
|
static TypeName resolveType(String string, Map<String, SchemeObject> objects) {
|
|
String argumentName = FieldInfo.getTypeSimpleName(string)
|
|
SchemeObject schemeObject = objects.get(argumentName)
|
|
if (schemeObject instanceof ImportObject) {
|
|
return ClassName.bestGuess(schemeObject.fullName)
|
|
} else {
|
|
return ClassName.bestGuess(argumentName)
|
|
}
|
|
}
|
|
|
|
static Pair<String, TypeName> getTypeNameWithArguments(TypeName parentTypeName, String genericString, Map<String, SchemeObject> objects) {
|
|
List<TypeName> arguments = new ArrayList<>()
|
|
genericString = genericString.replace(" ", "")
|
|
while (!genericString.isEmpty()) {
|
|
int nextComma = genericString.indexOf(',')
|
|
int nextLeft = genericString.indexOf('<')
|
|
int nextRight = genericString.indexOf('>')
|
|
if (nextComma > 0 && nextComma < nextRight && (nextLeft == -1 || nextComma < nextLeft)) {
|
|
arguments.add(resolveType(genericString.substring(0, nextComma), objects))
|
|
genericString = genericString.substring(nextComma + 1)
|
|
continue
|
|
}
|
|
if (nextRight == -1) {
|
|
arguments.add(resolveType(genericString), objects)
|
|
break
|
|
}
|
|
if (nextLeft == -1 || nextRight < nextLeft) {
|
|
arguments.add(resolveType(genericString.substring(0, nextRight), objects))
|
|
genericString = nextRight < genericString.length() - 1 ? genericString.substring(nextRight + 1) : ""
|
|
break
|
|
}
|
|
TypeName innerType = resolveType(genericString.substring(0, nextLeft), objects)
|
|
genericString = genericString.substring(nextLeft + 1)
|
|
Pair<String, TypeName> innerArgs = getTypeNameWithArguments(innerType, genericString, objects)
|
|
genericString = innerArgs.key.substring(1)
|
|
arguments.add(innerArgs.value)
|
|
}
|
|
return new Pair<String, TypeName>(genericString, ParameterizedTypeName.get(parentTypeName, (TypeName[]) arguments.toArray()))
|
|
}
|
|
|
|
static TypeName resolveTypeName(String typeString, Map<String, SchemeObject> objects) {
|
|
String simpleName = FieldInfo.getTypeSimpleName(typeString)
|
|
String genericsSuffix = typeString.indexOf("<") > 0 ? typeString.substring(typeString.indexOf("<")) : null
|
|
SchemeObject schemeObject = objects.get(simpleName)
|
|
if (schemeObject instanceof ImportObject) {
|
|
if (genericsSuffix != null) {
|
|
return getTypeNameWithArguments(ClassName.bestGuess(schemeObject.fullName), genericsSuffix.substring(1), objects).value
|
|
} else {
|
|
return ClassName.bestGuess(schemeObject.fullName)
|
|
}
|
|
} else {
|
|
if (genericsSuffix != null) {
|
|
return getTypeNameWithArguments(ClassName.bestGuess(simpleName), genericsSuffix.substring(1), objects).value
|
|
} else {
|
|
return ClassName.bestGuess(simpleName)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
class FieldInfo {
|
|
|
|
static upperStartName(String name) {
|
|
if (name.isEmpty()) {
|
|
throw new Exception("Empty name of field")
|
|
}
|
|
if (name.length() == 1) {
|
|
return name.charAt(0).toUpperCase()
|
|
}
|
|
return name.charAt(0).toUpperCase().toString() + name.substring(1)
|
|
}
|
|
|
|
static String getTypeSimpleName(String typeString) {
|
|
String result = typeString.trim()
|
|
if (result.indexOf('.') > 0) {
|
|
result = result.substring(result.lastIndexOf('.') + 1)
|
|
}
|
|
if (result.indexOf('<') > 0) {
|
|
result = result.substring(0, result.indexOf('<'))
|
|
}
|
|
return result;
|
|
}
|
|
|
|
final String name
|
|
final String apiName
|
|
boolean nullable
|
|
boolean missable
|
|
boolean nonEmptyCollection
|
|
boolean solidCollection
|
|
final FieldType fieldType
|
|
final TypeName typeName
|
|
|
|
FieldInfo(String name, Map<String, String> parameters, Map<String, SchemeObject> objects) {
|
|
this.name = name
|
|
apiName = parameters.containsKey("apiName") ? parameters.get("apiName") : name
|
|
|
|
String flagsString = parameters.get("flags");
|
|
if (flagsString != null) {
|
|
List<String> flags = Arrays.asList(flagsString.replace(" ", "").split(","))
|
|
nullable = flags.contains("nullable")
|
|
missable = flags.contains("missable")
|
|
nonEmptyCollection = flags.contains("non-empty")
|
|
solidCollection = flags.contains("solid")
|
|
}
|
|
|
|
String typeString = parameters.get("type")
|
|
if (typeString == null) {
|
|
throw new Exception("Missed type for field: " + name)
|
|
}
|
|
fieldType = FieldType.get(getTypeSimpleName(typeString), objects);
|
|
if (fieldType.nonPrimitiveTypeName != null) {
|
|
if (fieldType == FieldType.LIST) {
|
|
typeName = TypeNameUtils.resolveTypeName(typeString, objects)
|
|
if (!typeName.toString().startsWith("java.util.List")) {
|
|
throw new Exception("Unsupported list type '" + typeName.toString() + "' of field: " + name + ". Supports only List<*>")
|
|
}
|
|
} else if (fieldType == FieldType.MAP) {
|
|
typeName = TypeNameUtils.resolveTypeName(typeString, objects)
|
|
if (!typeName.toString().startsWith("java.util.Map<String")) {
|
|
throw new Exception("Unsupported map type of field: " + name + ". Supports only Map<String, *>")
|
|
}
|
|
} else {
|
|
typeName = nullable ? fieldType.nonPrimitiveTypeName : fieldType.primitiveTypeName
|
|
}
|
|
} else if (fieldType != FieldType.GENERIC) {
|
|
typeName = TypeNameUtils.resolveTypeName(typeString, objects)
|
|
} else {
|
|
// generic
|
|
typeName = ClassName.bestGuess(typeString)
|
|
}
|
|
}
|
|
|
|
FieldSpec createField() {
|
|
return FieldSpec.builder(typeName, name, Modifier.PRIVATE)
|
|
.addAnnotation(AnnotationSpec.builder(ClassName.bestGuess("com.bluelinelabs.logansquare.annotation.JsonField"))
|
|
.addMember("name", "\$S", apiName)
|
|
.build())
|
|
.build()
|
|
}
|
|
|
|
static boolean checkNameStartsWith(String name, String prefix) {
|
|
return name.length() > prefix.length() && name.startsWith(prefix) && name.charAt(prefix.length()).isUpperCase()
|
|
}
|
|
|
|
String getGetterPrefix() {
|
|
if (fieldType != FieldType.BOOLEAN) {
|
|
return "get"
|
|
}
|
|
if (checkNameStartsWith(name, "is")) {
|
|
return "is"
|
|
} else if (checkNameStartsWith(name, "has")) {
|
|
return "has"
|
|
} else if (checkNameStartsWith(name, "have")) {
|
|
return "have"
|
|
}
|
|
return "get"
|
|
}
|
|
|
|
MethodSpec createGetter() {
|
|
String getterPrefix = getGetterPrefix();
|
|
final MethodSpec.Builder builder = MethodSpec.methodBuilder(getterPrefix.equals("get")
|
|
? getterPrefix + upperStartName(name)
|
|
: getterPrefix + upperStartName(name.substring(getterPrefix.length())))
|
|
.returns(typeName)
|
|
.addModifiers(Modifier.PUBLIC)
|
|
if (!typeName.isPrimitive()) {
|
|
builder.addAnnotation(AnnotationSpec.builder(nullable
|
|
? ClassName.bestGuess("android.support.annotation.Nullable")
|
|
: ClassName.bestGuess("android.support.annotation.NonNull"))
|
|
.build());
|
|
}
|
|
|
|
if (fieldType == FieldType.MAP) {
|
|
builder.addStatement("return \$T.unmodifiableMap(\$L)", ClassName.get(Collections.class), name)
|
|
} else if (fieldType == FieldType.LIST) {
|
|
builder.addStatement("return \$T.unmodifiableList(\$L)", ClassName.get(Collections.class), name)
|
|
} else {
|
|
builder.addStatement("return \$L", name)
|
|
}
|
|
return builder.build()
|
|
}
|
|
|
|
MethodSpec createSetter() {
|
|
final ParameterSpec.Builder parameterBuilder = ParameterSpec.builder(typeName, name, Modifier.FINAL)
|
|
if (!typeName.isPrimitive()) {
|
|
parameterBuilder.addAnnotation(AnnotationSpec.builder(nullable
|
|
? ClassName.bestGuess("android.support.annotation.Nullable")
|
|
: ClassName.bestGuess("android.support.annotation.NonNull"))
|
|
.build());
|
|
}
|
|
final MethodSpec.Builder builder = MethodSpec.methodBuilder("set" + upperStartName(name))
|
|
.addParameter(parameterBuilder.build())
|
|
.addModifiers(Modifier.PUBLIC)
|
|
|
|
if (fieldType == FieldType.MAP) {
|
|
builder.addStatement("this.\$L = \$T.unmodifiableMap(\$L)", name, ClassName.get(Collections.class), name)
|
|
} else if (fieldType == FieldType.LIST) {
|
|
builder.addStatement("this.\$L = \$T.unmodifiableList(\$L)", name, ClassName.get(Collections.class), name)
|
|
} else {
|
|
builder.addStatement("this.\$L = \$L", name, name)
|
|
}
|
|
|
|
return builder.build()
|
|
}
|
|
|
|
void addValidateStatements(MethodSpec.Builder validateMethod) {
|
|
if (!nullable) {
|
|
validateMethod.addStatement("validateNotNull(\$L)", name)
|
|
}
|
|
if (!fieldType.ableToInnerValidate) {
|
|
return
|
|
}
|
|
if (fieldType == FieldType.GENERIC || fieldType == FieldType.IMPORTED_MODEL) {
|
|
validateMethod
|
|
.beginControlFlow("if (\$L instanceof \$T)", name, ClassName.bestGuess("ru.touchin.templates.ApiModel"))
|
|
.addStatement("((\$T) \$L).validate()", ClassName.bestGuess("ru.touchin.templates.ApiModel"), name)
|
|
.endControlFlow()
|
|
return
|
|
}
|
|
if (nullable) {
|
|
validateMethod.beginControlFlow("if (\$L != null)", name)
|
|
}
|
|
if (fieldType == FieldType.LIST) {
|
|
if (nonEmptyCollection) {
|
|
validateMethod.addStatement("validateCollectionNotEmpty(\$L)", name)
|
|
}
|
|
if (solidCollection) {
|
|
validateMethod.addStatement("validateCollection(\$L, CollectionValidationRule.EXCEPTION_IF_ANY_INVALID)", name)
|
|
} else if (nonEmptyCollection) {
|
|
validateMethod.addStatement("validateCollection(\$L, CollectionValidationRule.EXCEPTION_IF_ALL_INVALID)", name)
|
|
} else {
|
|
validateMethod.addStatement("validateCollection(\$L, CollectionValidationRule.REMOVE_INVALID_ITEMS)", name)
|
|
}
|
|
} else if (fieldType == FieldType.MAP) {
|
|
if (nonEmptyCollection) {
|
|
validateMethod.addStatement("validateCollectionNotEmpty(\$L.values())", name)
|
|
}
|
|
validateMethod.addStatement("validateCollection(\$L.values(), CollectionValidationRule.EXCEPTION_IF_ANY_INVALID)", name)
|
|
} else if (fieldType == FieldType.MODEL) {
|
|
validateMethod.addStatement("\$L.validate()", name)
|
|
} else {
|
|
throw new Exception("Unexpected able to validate field type '" + fieldType + "' of field " + name)
|
|
}
|
|
if (nullable) {
|
|
validateMethod.endControlFlow()
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
class ClassObject extends SchemeObject {
|
|
|
|
static final String PREFIX = "class "
|
|
|
|
final String name
|
|
final Map<String, String> info
|
|
final List<FieldInfo> fields = new ArrayList<>()
|
|
final List<String> typeVariables = new ArrayList<>()
|
|
TypeName superclass
|
|
|
|
ClassObject(String name, Map<String, String> info) {
|
|
this.name = name
|
|
this.info = info
|
|
}
|
|
|
|
void resolveFieldsAndProperties(Map<String, SchemeObject> objects) {
|
|
final List<String> fieldNames = new ArrayList<>()
|
|
for (final Map.Entry entry : info.entrySet()) {
|
|
if (entry.key.equals("typeVariables")) {
|
|
for (String typeVariable : entry.value.replace(" ", "").split(",")) {
|
|
typeVariables.add(typeVariable)
|
|
}
|
|
continue
|
|
}
|
|
|
|
if (entry.key.equals("extends")) {
|
|
superclass = TypeNameUtils.resolveTypeName(entry.value.replace(" ", ""), objects)
|
|
continue
|
|
}
|
|
|
|
if (fieldNames.contains(entry.key)) {
|
|
throw new Exception("Duplicate field name: " + name)
|
|
}
|
|
fieldNames.add(entry.key)
|
|
|
|
if (entry.value instanceof Map) {
|
|
fields.add(new FieldInfo(entry.key, (Map<String, String>) entry.value, objects))
|
|
} else {
|
|
Map<String, String> parameters = new HashMap<>()
|
|
parameters.put("type", entry.value.toString())
|
|
fields.add(new FieldInfo(entry.key, parameters, objects))
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
void writeToFile(File directory, Map<String, SchemeObject> objects, String appPackage) {
|
|
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(name)
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addAnnotation(AnnotationSpec.builder(ClassName.bestGuess("com.bluelinelabs.logansquare.annotation.JsonObject"))
|
|
.addMember("serializeNullObjects", "true")
|
|
.build())
|
|
|
|
if (superclass != null) {
|
|
classBuilder.superclass(superclass)
|
|
} else {
|
|
classBuilder.superclass(ClassName.bestGuess("ru.touchin.templates.logansquare.LoganSquareJsonModel"))
|
|
}
|
|
|
|
for (String typeVariable : typeVariables) {
|
|
classBuilder.addTypeVariable(TypeVariableName.get(typeVariable))
|
|
}
|
|
|
|
classBuilder.addMethod(MethodSpec.constructorBuilder()
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addStatement("super()")
|
|
.build())
|
|
|
|
MethodSpec.Builder fullConstructorBuilder = (superclass == null) ?
|
|
MethodSpec.constructorBuilder()
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addStatement("super()")
|
|
: null
|
|
|
|
MethodSpec.Builder equalsMethod = MethodSpec.methodBuilder("equals")
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addAnnotation(Override.class)
|
|
.returns(TypeName.BOOLEAN)
|
|
.addParameter(ParameterSpec.builder(ClassName.get(Object.class), "object", Modifier.FINAL)
|
|
.addAnnotation(ClassName.bestGuess("android.support.annotation.Nullable"))
|
|
.build())
|
|
.beginControlFlow("if (this == object)")
|
|
.addStatement("return true")
|
|
.endControlFlow()
|
|
.beginControlFlow("if (object == null || getClass() != object.getClass())")
|
|
.addStatement("return false")
|
|
.endControlFlow()
|
|
.addStatement("final \$T that = (\$T) object", ClassName.bestGuess(name), ClassName.bestGuess(name))
|
|
|
|
MethodSpec.Builder hashCodeMethod = MethodSpec.methodBuilder("hashCode")
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addAnnotation(Override.class)
|
|
.returns(TypeName.INT)
|
|
|
|
MethodSpec.Builder validateMethod = MethodSpec.methodBuilder("validate")
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addAnnotation(Override.class)
|
|
.addException(ClassName.bestGuess("ValidationException"))
|
|
.addStatement("super.validate()")
|
|
|
|
boolean first = true
|
|
CodeBlock.Builder equalsStatement = CodeBlock.builder()
|
|
CodeBlock.Builder hashCodeStatement = CodeBlock.builder()
|
|
|
|
for (FieldInfo field : fields) {
|
|
classBuilder.addField(field.createField())
|
|
classBuilder.addMethod(field.createGetter())
|
|
classBuilder.addMethod(field.createSetter())
|
|
field.addValidateStatements(validateMethod)
|
|
|
|
if (fullConstructorBuilder != null) {
|
|
fullConstructorBuilder.addParameter(ParameterSpec.builder(field.typeName, field.name, Modifier.FINAL)
|
|
.addAnnotation(field.nullable
|
|
? ClassName.bestGuess("android.support.annotation.Nullable")
|
|
: ClassName.bestGuess("android.support.annotation.NonNull"))
|
|
.build())
|
|
if (field.fieldType == FieldType.LIST) {
|
|
fullConstructorBuilder.addStatement("this.\$L = \$T.unmodifiableList(\$L)", field.name, ClassName.get(Collections.class), field.name)
|
|
} else if (field.fieldType == FieldType.MAP) {
|
|
fullConstructorBuilder.addStatement("this.\$L = \$T.unmodifiableMap(\$L)", field.name, ClassName.get(Collections.class), field.name)
|
|
} else {
|
|
fullConstructorBuilder.addStatement("this.\$L = \$L", field.name, field.name)
|
|
}
|
|
}
|
|
|
|
if (first) {
|
|
if (superclass == null) {
|
|
hashCodeStatement.add("return \$T.hashCode(\$L", ClassName.bestGuess("ru.touchin.roboswag.core.utils.ObjectUtils"), field.name)
|
|
equalsStatement.add("return \$T.equals(\$L, that.\$L)", ClassName.bestGuess("ru.touchin.roboswag.core.utils.ObjectUtils"),
|
|
field.name, field.name)
|
|
} else {
|
|
hashCodeStatement.add("return \$T.hashCode(super.hashCode(), \$L", ClassName.bestGuess("ru.touchin.roboswag.core.utils.ObjectUtils"), field.name)
|
|
equalsStatement.add("return super.equals(that) && \$T.equals(\$L, that.\$L)", ClassName.bestGuess("ru.touchin.roboswag.core.utils.ObjectUtils"),
|
|
field.name, field.name)
|
|
}
|
|
} else {
|
|
if (field.fieldType == FieldType.MAP) {
|
|
equalsStatement.add("\n\t\t&& \$T.isMapsEquals(\$L, that.\$L)", ClassName.bestGuess("ru.touchin.roboswag.core.utils.ObjectUtils"),
|
|
field.name, field.name)
|
|
} else if (field.fieldType == FieldType.LIST) {
|
|
equalsStatement.add("\n\t\t&& \$T.isCollectionsEquals(\$L, that.\$L)", ClassName.bestGuess("ru.touchin.roboswag.core.utils.ObjectUtils"),
|
|
field.name, field.name)
|
|
} else {
|
|
equalsStatement.add("\n\t\t&& \$T.equals(\$L, that.\$L)", ClassName.bestGuess("ru.touchin.roboswag.core.utils.ObjectUtils"),
|
|
field.name, field.name)
|
|
}
|
|
|
|
hashCodeStatement.add(", \$L", field.name)
|
|
}
|
|
first = false
|
|
}
|
|
equalsStatement.add(";\n")
|
|
hashCodeStatement.add(");\n")
|
|
|
|
classBuilder.addMethod(validateMethod.build())
|
|
classBuilder.addMethod(equalsMethod.addCode(equalsStatement.build()).build())
|
|
classBuilder.addMethod(hashCodeMethod.addCode(hashCodeStatement.build()).build())
|
|
|
|
if (fullConstructorBuilder != null) {
|
|
classBuilder.addMethod(fullConstructorBuilder.build())
|
|
}
|
|
println "!!!!!" + appPackage
|
|
JavaFile.builder(appPackage, classBuilder.build())
|
|
.indent(" ")
|
|
.build().writeTo(directory);
|
|
}
|
|
|
|
}
|
|
|
|
class FileUtils {
|
|
|
|
static void purgeDirectory(File dir) {
|
|
for (File file : dir.listFiles()) {
|
|
if (file.isDirectory()) purgeDirectory(file);
|
|
file.delete();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
android.applicationVariants.all {
|
|
variant ->
|
|
File generatedModels = new File("${project.buildDir}/generated/source/api/model/${variant.dirName}")
|
|
String modelsPackage = android.extensions.findByName("apiGeneratorModelsPackage")
|
|
String schemePath = android.extensions.findByName("apiGeneratorSchemePath")
|
|
if (modelsPackage == null) {
|
|
modelsPackage = android.defaultConfig.applicationId + '.logic.api.model'
|
|
}
|
|
|
|
if (schemePath == null) {
|
|
return
|
|
}
|
|
|
|
File schemeFile = new File(schemePath)
|
|
if (!schemeFile.exists()) {
|
|
schemeFile = new File("${project.projectDir}", schemePath)
|
|
}
|
|
|
|
def apiModelsGenerationTask = tasks.create("apiModelsGeneration${variant.name}") << {
|
|
|
|
Yaml yaml = new Yaml();
|
|
Map<String, SchemeObject> schemeObjects = new HashMap<>()
|
|
schemeObjects.put("Map", new ImportObject("java.util.Map"))
|
|
schemeObjects.put("List", new ImportObject("java.util.List"))
|
|
schemeObjects.put("DateTime", new ImportObject("org.joda.time.DateTime"))
|
|
|
|
for (final Object data : yaml.loadAll(new FileReader(schemeFile))) {
|
|
if (data instanceof Map) {
|
|
for (final Map.Entry<String, Object> entry : data.entrySet()) {
|
|
if (entry.key.equals(ImportObject.GROUP_NAME)) {
|
|
for (String importString : (Iterable) entry.value) {
|
|
final ImportObject importObject = new ImportObject(importString)
|
|
schemeObjects.put(importObject.name, importObject)
|
|
}
|
|
} else if (entry.key.startsWith(EnumObject.PREFIX)) {
|
|
final EnumObject enumObject = new EnumObject(entry.key.substring(EnumObject.PREFIX.length()), entry.value)
|
|
schemeObjects.put(enumObject.name, enumObject)
|
|
} else if (entry.key.startsWith(ClassObject.PREFIX)) {
|
|
final ClassObject classObject = new ClassObject(entry.key.substring(ClassObject.PREFIX.length()), entry.value)
|
|
schemeObjects.put(classObject.name, classObject)
|
|
} else {
|
|
throw new Exception("Unexpected scheme object: " + entry.key)
|
|
}
|
|
}
|
|
} else {
|
|
throw new Exception("Yaml file '" + fileName + "' is invalid")
|
|
}
|
|
}
|
|
FileUtils.purgeDirectory(generatedModels)
|
|
for (SchemeObject schemeObject : schemeObjects.values()) {
|
|
if (schemeObject instanceof ClassObject) {
|
|
schemeObject.resolveFieldsAndProperties(schemeObjects)
|
|
}
|
|
schemeObject.writeToFile(generatedModels, schemeObjects, modelsPackage)
|
|
}
|
|
}
|
|
|
|
apiModelsGenerationTask.description = 'Generates API models'
|
|
variant.registerJavaGeneratingTask apiModelsGenerationTask, generatedModels
|
|
} |