package clear.cdb.annotation.processors;
import clear.cdb.support.logger.LogLocation;
import clear.cdb.support.logger.ProcessorLogger;
import clear.cdb.support.template.FreemarkerUtil;
import com.farata.dto2extjs.annotations.JSClass;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.*;
import javax.lang.model.util.Elements;
import javax.tools.JavaFileObject;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
@SupportedAnnotationTypes("com.farata.dto2extjs.annotations.*")
public class TypescriptAnnotationProcessor extends BaseAnnotationProcessor {
private String dtoGeneratedPath = "/tmp";
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
dtoGeneratedPath = processingEnv.getOptions().get("dtoGeneratedPath");
for (TypeElement annotaion : annotations) {
// process only JSCLass annotations
if (JS_CLASS_ANNOTATION_TYPE.equals(annotaion.asType().toString())) {
final Set<? extends Element> annotatedTypes = roundEnv.getElementsAnnotatedWith(JSClass.class);
for (Element elem : annotatedTypes) {
final ElementKind elementKind = elem.getKind();
switch (elementKind) {
case ENUM:
logger.warning(LogLocation.MESSAGER, "Enum not supported");
case CLASS:
try { generateDTO(roundEnv, (TypeElement)elem); }
catch (Exception e) {
logger.warning(LogLocation.MESSAGER, "Error " + elem.getSimpleName()
+ " " + ProcessorLogger.exceptionToString(e));
}
break;
case INTERFACE:
logger.warning(LogLocation.MESSAGER, "Interface not supported");
break;
default:
continue;
}
}
}
}
return true;
}
private void generateDTO(RoundEnvironment roundEnv, TypeElement elem) throws Exception {
Map<String, Object> context = getDTOContext(roundEnv, elem);
String packageName = context.get("package").toString();
String filename = elem.getSimpleName().toString() + ".ts";
File file = new File(filename);
if (!file.exists()) {
String source = FreemarkerUtil.render("/ftl/typescript/typescript-model-custom.ftl", context);
File destinationFolder = new File(dtoGeneratedPath + "/" + packageName);
if (!destinationFolder.exists()) {
destinationFolder.mkdirs();
}
String destination = destinationFolder + "/" + filename;
Files.write(FileSystems.getDefault().getPath(destination), source.getBytes());
logger.note(LogLocation.MESSAGER, "Generated " + filename);
}
String filename2 = elem.getSimpleName().toString() + "_.ts";
String destination2 = dtoGeneratedPath + "/" + packageName + "/" + filename2;
String source2 = FreemarkerUtil.render("/ftl/typescript/typescript-model-generated.ftl", context);
Files.write(FileSystems.getDefault().getPath(destination2), source2.getBytes());
logger.note(LogLocation.MESSAGER, "Generated " + filename2);
}
private Map<String, Object> getDTOContext(RoundEnvironment roundEnv, TypeElement elem) {
Map<String, Object> result = new HashMap<String, Object>();
result.put("package", ((PackageElement)elem.getEnclosingElement()).getQualifiedName().toString());
result.put("classSimpleName", elem.getSimpleName().toString());
result.put("fields", getFields(roundEnv, elem));
return result;
}
private List<DTOField> getFields(RoundEnvironment roundEnv, TypeElement elem) {
// TODO get fields
return Collections.EMPTY_LIST;
}
public String convertFromJava(Class type) {
String t = type.getSimpleName().toLowerCase();
if (t.contains("[]")) return "any[]";
if (t.equals("boolean")) {
return "boolean";
} else if (t.equals("string")) {
return "string";
} else if (t.equals("byte") || t.equals("int") || t.equals("short") || t.equals("long") || t.equals("float") || t.equals("double")) {
return "number";
} else if (t.equals("date")) {
return "Date";
} else if (t.equals("list")) {
return "any[]";
} else if (t.equals("map")) {
return "Object";
}
throw new RuntimeException("Unknown Java to Typescript type conversion: " + t);
}
public static class DTOField {
public String name, type;
public boolean key;
DTOField(String name, String type, boolean key) {
this.name = name;
this.type = type;
this.key = key;
}
}
}