package xapi.dev.ui; import com.github.javaparser.ASTHelper; import com.github.javaparser.ast.expr.AnnotationExpr; import com.github.javaparser.ast.expr.BooleanLiteralExpr; import com.github.javaparser.ast.expr.CharLiteralExpr; import com.github.javaparser.ast.expr.DoubleLiteralExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.IntegerLiteralExpr; import com.github.javaparser.ast.expr.JsonContainerExpr; import com.github.javaparser.ast.expr.JsonPairExpr; import com.github.javaparser.ast.expr.LiteralExpr; import com.github.javaparser.ast.expr.LongLiteralExpr; import com.github.javaparser.ast.expr.MemberValuePair; import com.github.javaparser.ast.expr.NullLiteralExpr; import com.github.javaparser.ast.expr.StringLiteralExpr; import xapi.collect.X_Collect; import xapi.collect.api.IntTo; import xapi.collect.api.StringTo; import xapi.dev.source.ClassBuffer; import xapi.source.api.IsType; import xapi.source.impl.ImmutableType; /** * Created by James X. Nelson (james @wetheinter.net) on 6/22/16. */ public class DataTypeOptions { private String collection; private String factory; private String type; private String adder; private StringTo<IsType> fieldTypes; public DataTypeOptions() { fieldTypes = X_Collect.newStringMap(IsType.class); } public DataTypeOptions fromAnnotation( ClassBuffer cb, JsonContainerExpr json, AnnotationExpr anno, boolean searchTypes ) { if (anno != null) { for (MemberValuePair member : anno.getMembers()) { switch (member.getName()) { case "collection": case "value": assert collection == null : "Do not supply both `collection` and `value` to @Type annotation " + anno; collection = ASTHelper.extractAnnoValue(member); break; case "type": type = ASTHelper.extractAnnoValue(member); break; case "adder": adder = ASTHelper.extractAnnoValue(member); break; case "factory": factory = ASTHelper.extractAnnoValue(member); break; case "auto": searchTypes = true; break; } } } // attempt to determine generic type, using an extremely lazy peek at values. // if more complex type mapping is required, we should defer to a more comprehensive // type resolving system than the hack below. Expression best = null; for (JsonPairExpr pair : json.getPairs()) { final Expression val = pair.getValueExpr(); if (best == null) { best = val; } else if (val.getClass() != best.getClass() && !(val instanceof NullLiteralExpr)) { best = null; break; } fieldTypes.put(pair.getKeyString(), extractType(pair, json)); } if (type == null && searchTypes) { if (best != null) { if (best instanceof IntegerLiteralExpr) { type = "Integer"; } else if (best instanceof LongLiteralExpr) { type = "Long"; } else if (best instanceof DoubleLiteralExpr) { type = "Double"; } else if (best instanceof CharLiteralExpr) { type = "Character"; } else if (best instanceof BooleanLiteralExpr) { type = "Boolean"; } else if (best instanceof StringLiteralExpr) { type = "String"; } } } if (type == null) { type = "Object"; } if (collection == null) { collection = (defaultCollectionType(json)).getName(); } if (factory == null) { if (collection.startsWith("xapi")) { String factoryCls = cb.addImport(X_Collect.class); factory = factoryCls + ".new" + (json.isArray() ? "List" : "StringMap") + "($type.class)"; } else { factory = "new $type()"; } } if (adder == null) { adder = json.isArray() ? "add" : "put"; } return this; } protected IsType extractType(Expression val) { if (val instanceof LiteralExpr) { if (val instanceof IntegerLiteralExpr) { return new ImmutableType("", "int"); } else if (val instanceof LongLiteralExpr) { return new ImmutableType("", "long"); } else if (val instanceof DoubleLiteralExpr) { return new ImmutableType("", "double"); } else if (val instanceof CharLiteralExpr) { return new ImmutableType("", "char"); } else if (val instanceof BooleanLiteralExpr) { return new ImmutableType("", "boolean"); } else if (val instanceof StringLiteralExpr) { return new ImmutableType("java.lang", "String"); } // TODO: arrays, ui containers, annotated elements, constructors, etc... } return new ImmutableType("java.lang", "Object"); } protected IsType extractType(JsonPairExpr pair, JsonContainerExpr json) { final Expression val = pair.getValueExpr(); return extractType(val); } protected Class<?> defaultCollectionType(JsonContainerExpr json) { return json.isArray() ? IntTo.class : StringTo.class; } public String getCollection() { return collection; } public String getFactory() { return factory; } public String getType() { return type; } public String getAdder() { return adder; } public StringTo<IsType> getFieldTypes() { return fieldTypes; } }