serialization/deserialization added
This commit is contained in:
parent
1f563d1a4d
commit
920cd85f2c
|
|
@ -38,8 +38,8 @@ import javax.lang.model.element.Modifier
|
|||
|
||||
//TODO: missable in future
|
||||
//TODO: NUMBER/BOOLEAN enums in future
|
||||
//TODO: maybe save md5-hashes to check if files/scheme changed
|
||||
|
||||
//TODO: move out of allvariants - too much
|
||||
//TODO: serialization/deserialization
|
||||
//TODO: setup generation by map yaml->package
|
||||
|
||||
|
|
@ -55,6 +55,8 @@ class Types {
|
|||
static final TypeName API_MODEL = ClassName.bestGuess("ru.touchin.templates.ApiModel")
|
||||
static final TypeName LOGAN_SQUARE_JSON_MODEL = ClassName.bestGuess("ru.touchin.templates.logansquare.LoganSquareJsonModel")
|
||||
static final TypeName OBJECT_UTILS = ClassName.bestGuess("ru.touchin.roboswag.core.utils.ObjectUtils")
|
||||
static final TypeName OBJECT_OUTPUT_STREAM = ClassName.bestGuess("java.io.ObjectOutputStream")
|
||||
static final TypeName OBJECT_INPUT_STREAM = ClassName.bestGuess("java.io.ObjectInputStream")
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -220,12 +222,12 @@ class EnumObject extends SchemeObject {
|
|||
*/
|
||||
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),
|
||||
BOOLEAN(TypeName.BOOLEAN, ClassName.get(Boolean.class), false, "writeBoolean", "readBoolean"),
|
||||
INT(TypeName.INT, ClassName.get(Integer.class), false, "writeInt", "readInt"),
|
||||
LONG(TypeName.LONG, ClassName.get(Long.class), false, "writeLong", "readLong"),
|
||||
FLOAT(TypeName.FLOAT, ClassName.get(Float.class), false, "writeFloat", "readFloat"),
|
||||
DOUBLE(TypeName.DOUBLE, ClassName.get(Double.class), false, "writeDouble", "readDouble"),
|
||||
STRING(ClassName.get(String.class), false, "writeUTF", "readUTF"),
|
||||
LIST(ClassName.get(List.class), true),
|
||||
MAP(ClassName.get(Map.class), true),
|
||||
DATE_TIME(ClassName.bestGuess("org.joda.time.DateTime"), false),
|
||||
|
|
@ -239,19 +241,29 @@ enum FieldType {
|
|||
final TypeName nonPrimitiveTypeName
|
||||
// flag to check if such type could be validate via ApiModel class methods in some way
|
||||
final boolean ableToInnerValidate
|
||||
final String serializationMethodName
|
||||
final String deserializationMethodName
|
||||
|
||||
FieldType(final boolean ableToInnerValidate) {
|
||||
this(null, null, ableToInnerValidate)
|
||||
this(null, null, ableToInnerValidate, null, null)
|
||||
}
|
||||
|
||||
FieldType(final TypeName typeName, final boolean ableToInnerValidate) {
|
||||
this(typeName, typeName, ableToInnerValidate)
|
||||
this(typeName, typeName, ableToInnerValidate, null, null)
|
||||
}
|
||||
|
||||
FieldType(final TypeName primitiveTypeName, final TypeName nonPrimitiveTypeName, final boolean ableToInnerValidate) {
|
||||
FieldType(final TypeName typeName, final boolean ableToInnerValidate,
|
||||
final String serializationMethodName, final String deserializationMethodName) {
|
||||
this(typeName, typeName, ableToInnerValidate, serializationMethodName, deserializationMethodName)
|
||||
}
|
||||
|
||||
FieldType(final TypeName primitiveTypeName, final TypeName nonPrimitiveTypeName, final boolean ableToInnerValidate,
|
||||
final String serializationMethodName, final String deserializationMethodName) {
|
||||
this.primitiveTypeName = primitiveTypeName
|
||||
this.nonPrimitiveTypeName = nonPrimitiveTypeName
|
||||
this.ableToInnerValidate = ableToInnerValidate
|
||||
this.serializationMethodName = serializationMethodName
|
||||
this.deserializationMethodName = deserializationMethodName
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -679,26 +691,42 @@ class ClassObject extends SchemeObject {
|
|||
.addAnnotation(AnnotationSpec.builder(Types.JSON_OBJECT).addMember("serializeNullObjects", "true").build())
|
||||
.superclass(superclass != null ? superclass : Types.LOGAN_SQUARE_JSON_MODEL)
|
||||
|
||||
// add type variables
|
||||
// adds type variables
|
||||
for (String typeVariable : typeVariables) {
|
||||
classBuilder.addTypeVariable(TypeVariableName.get(typeVariable))
|
||||
}
|
||||
|
||||
// add default constructor
|
||||
// adds default constructor
|
||||
classBuilder.addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC).addStatement("super()").build())
|
||||
|
||||
// create full constructor only if it is extends from LoganSquareJsonModel,
|
||||
// creates full constructor only if it is extends from LoganSquareJsonModel,
|
||||
// else we can't create constructor as parent constructor could also have parameters
|
||||
final MethodSpec.Builder fullConstructorBuilder = superclass == null ?
|
||||
MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC).addStatement("super()")
|
||||
: null
|
||||
|
||||
// create validate() method
|
||||
// creates validate() method
|
||||
final MethodSpec.Builder validateMethod = MethodSpec.methodBuilder("validate").addModifiers(Modifier.PUBLIC)
|
||||
.addAnnotation(Override.class)
|
||||
.addException(ClassName.bestGuess("ValidationException"))
|
||||
.addStatement("super.validate()")
|
||||
|
||||
// creates writeObject() method
|
||||
final MethodSpec.Builder serializeMethod = MethodSpec.methodBuilder("writeObject").addModifiers(Modifier.PRIVATE)
|
||||
.addException(ClassName.get(IOException.class))
|
||||
.addParameter(ParameterSpec.builder(Types.OBJECT_OUTPUT_STREAM, "outputStream", Modifier.FINAL)
|
||||
.addAnnotation(Types.NON_NULL)
|
||||
.build())
|
||||
|
||||
// creates readObject() method
|
||||
final MethodSpec.Builder deserializeMethod = MethodSpec.methodBuilder("readObject").addModifiers(Modifier.PRIVATE)
|
||||
.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "\$S", "unchecked").build())
|
||||
.addException(ClassName.get(IOException.class))
|
||||
.addException(ClassName.get(ClassNotFoundException.class))
|
||||
.addParameter(ParameterSpec.builder(Types.OBJECT_INPUT_STREAM, "inputStream", Modifier.FINAL)
|
||||
.addAnnotation(Types.NON_NULL)
|
||||
.build())
|
||||
|
||||
boolean first = true
|
||||
final CodeBlock.Builder equalsStatement = CodeBlock.builder()
|
||||
final CodeBlock.Builder hashCodeStatement = CodeBlock.builder()
|
||||
|
|
@ -708,6 +736,16 @@ class ClassObject extends SchemeObject {
|
|||
classBuilder.addMethod(field.generateGetterCode())
|
||||
classBuilder.addMethod(field.generateSetterCode())
|
||||
field.generateValidationCode(validateMethod)
|
||||
final String serializeMethodName = (!field.nullable && field.type.serializationMethodName != null
|
||||
? field.type.serializationMethodName : "writeObject");
|
||||
final String deserializeMethodName = (!field.nullable && field.type.deserializationMethodName != null
|
||||
? field.type.deserializationMethodName : "readObject");
|
||||
serializeMethod.addStatement("outputStream.\$L(\$L)", serializeMethodName, field.name)
|
||||
if (deserializeMethodName.equals("readObject")) {
|
||||
deserializeMethod.addStatement("\$L = (\$T) inputStream.\$L()", field.name, field.typeName, deserializeMethodName)
|
||||
} else{
|
||||
deserializeMethod.addStatement("\$L = inputStream.\$L()", field.name, deserializeMethodName)
|
||||
}
|
||||
|
||||
if (fullConstructorBuilder != null) {
|
||||
fullConstructorBuilder.addParameter(ParameterSpec.builder(field.typeName, field.name, Modifier.FINAL)
|
||||
|
|
@ -748,9 +786,9 @@ class ClassObject extends SchemeObject {
|
|||
equalsStatement.add(";\n")
|
||||
hashCodeStatement.add(");\n")
|
||||
|
||||
// create validate() method
|
||||
// creates validate() method
|
||||
classBuilder.addMethod(validateMethod.build())
|
||||
// add equals() method
|
||||
// adds equals() method
|
||||
classBuilder.addMethod(MethodSpec.methodBuilder("equals").addModifiers(Modifier.PUBLIC)
|
||||
.addAnnotation(Override.class)
|
||||
.returns(TypeName.BOOLEAN)
|
||||
|
|
@ -759,11 +797,15 @@ class ClassObject extends SchemeObject {
|
|||
.beginControlFlow("if (object == null || getClass() != object.getClass())").addStatement("return false").endControlFlow()
|
||||
.addStatement("final \$T that = (\$T) object", ClassName.bestGuess(name), ClassName.bestGuess(name))
|
||||
.addCode(equalsStatement.build()).build())
|
||||
// add hashCode() method
|
||||
// adds hashCode() method
|
||||
classBuilder.addMethod(MethodSpec.methodBuilder("hashCode").addModifiers(Modifier.PUBLIC)
|
||||
.addAnnotation(Override.class)
|
||||
.returns(TypeName.INT)
|
||||
.addCode(hashCodeStatement.build()).build())
|
||||
// adds writeObject() method
|
||||
classBuilder.addMethod(serializeMethod.build())
|
||||
// adds readObject() method
|
||||
classBuilder.addMethod(deserializeMethod.build())
|
||||
|
||||
if (fullConstructorBuilder != null) {
|
||||
classBuilder.addMethod(fullConstructorBuilder.build())
|
||||
|
|
@ -791,26 +833,32 @@ class FileUtils {
|
|||
|
||||
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'
|
||||
}
|
||||
final File generatedModelsDirectory = new File("${project.buildDir}/generated/source/jsonModels/${variant.dirName}")
|
||||
/**
|
||||
* Generating Java classes describing JSON models from specific YAML scheme.
|
||||
*/
|
||||
def generateJsonModelsTask = tasks.create("generateJsonModels${variant.name}") << {
|
||||
String modelsPackage = android.extensions.findByName("apiGeneratorModelsPackage")
|
||||
String schemeFilePath = android.extensions.findByName("apiGeneratorSchemePath")
|
||||
if (modelsPackage == null) {
|
||||
modelsPackage = android.defaultConfig.applicationId + '.logic.api.model'
|
||||
}
|
||||
|
||||
if (schemePath == null) {
|
||||
return
|
||||
}
|
||||
if (schemeFilePath == null) {
|
||||
return
|
||||
}
|
||||
|
||||
File schemeFile = new File(schemePath)
|
||||
if (!schemeFile.exists()) {
|
||||
schemeFile = new File("${project.projectDir}", schemePath)
|
||||
}
|
||||
File schemeFile = new File(schemeFilePath)
|
||||
if (!schemeFile.exists()) {
|
||||
schemeFile = new File("${project.projectDir}", schemeFilePath)
|
||||
}
|
||||
if (!schemeFile.exists()) {
|
||||
throw new Exception("JSON models scheme file not found at '" + schemeFilePath + "' or at '${project.projectDir}/" + schemeFilePath + "'")
|
||||
}
|
||||
FileUtils.purgeDirectory(generatedModelsDirectory)
|
||||
|
||||
def apiModelsGenerationTask = tasks.create("apiModelsGeneration${variant.name}") << {
|
||||
|
||||
Yaml yaml = new Yaml()
|
||||
Map<String, SchemeObject> schemeObjects = new HashMap<>()
|
||||
final Yaml yaml = new Yaml()
|
||||
final 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"))
|
||||
|
|
@ -838,9 +886,7 @@ android.applicationVariants.all {
|
|||
}
|
||||
}
|
||||
|
||||
FileUtils.purgeDirectory(generatedModels)
|
||||
|
||||
for (SchemeObject schemeObject : schemeObjects.values()) {
|
||||
for (final SchemeObject schemeObject : schemeObjects.values()) {
|
||||
if (schemeObject instanceof ClassObject) {
|
||||
try {
|
||||
schemeObject.resolveFieldsInfo(schemeObjects)
|
||||
|
|
@ -849,13 +895,13 @@ android.applicationVariants.all {
|
|||
}
|
||||
}
|
||||
try {
|
||||
schemeObject.writeToFile(generatedModels, schemeObjects, modelsPackage)
|
||||
schemeObject.writeToFile(generatedModelsDirectory, schemeObjects, modelsPackage)
|
||||
} catch (final Exception exception) {
|
||||
throw new Exception("Error on generating code for '" + schemeObject.name + "' : " + exception.getMessage())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apiModelsGenerationTask.description = 'Generates API models'
|
||||
variant.registerJavaGeneratingTask apiModelsGenerationTask, generatedModels
|
||||
generateJsonModelsTask.description = 'Generates Java classes for JSON models'
|
||||
variant.registerJavaGeneratingTask generateJsonModelsTask, generatedModelsDirectory
|
||||
}
|
||||
Loading…
Reference in New Issue