/** * Copyright (C) 2013-2016 The Rythm Engine project * for LICENSE and other details see: * https://github.com/rythmengine/rythmengine */ package org.rythmengine.internal.compiler; import org.rythmengine.RythmEngine; import org.rythmengine.utils.S; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * Facilitate {@link org.rythmengine.RythmEngine} to infer param types */ public class ParamTypeInferencer { private ParamTypeInferencer() { } public static String typeTransform(String type) { type = type.trim(); if (type.contains("Boolean") && type.matches("(.*[^a-zA-Z0-9_]+)?boolean([^a-zA-Z0-9_].*|$)")) return type.replace("Boolean","boolean"); else if (type.contains("Integer") && type.matches("(.*[^a-zA-Z0-9_]+)?int([^a-zA-Z0-9_].*|$)")) return type.replace("Integer","int"); else if (type.contains("Float") && type.matches("(.*[^a-zA-Z0-9_]+)?float([^a-zA-Z0-9_].*|$)")) return type.replace("Float","float"); else if (type.contains("Double") && type.matches("(.*[^a-zA-Z0-9_]+)?double([^a-zA-Z0-9_].*|$)")) return type.replace("Double","double"); else if (type.contains("Character") && type.matches("(.*[^a-zA-Z0-9_]+)?char([^a-zA-Z0-9_].*|$)")) return type.replace("Character","char"); else if (type.contains("Long") && type.matches("(.*[^a-zA-Z0-9_]+)?long([^a-zA-Z0-9_].*|$)")) return type.replace("Long","long"); else if (type.contains("Byte") && type.matches("(.*[^a-zA-Z0-9_]+)?byte([^a-zA-Z0-9_].*|$)")) return type.replace("Byte","byte"); else return type; } private static final ThreadLocal<Map<String, String>> typeMap = new ThreadLocal<Map<String, String>>() { @Override protected Map<String, String> initialValue() { return new HashMap<String, String>(); } }; private static final ThreadLocal<String> uuid = new ThreadLocal<String>() { @Override protected String initialValue() { return ""; } }; private static String getTypeName(Object val) { String clsName; if (null == val) { clsName = "Object"; } else { Class c = val.getClass(); clsName = c.getName(); if (clsName.contains("$")) { //anonymous or embedded class, let's try parent type if (clsName.startsWith("java.")) { clsName = c.getSuperclass().getName(); } else if (!clsName.matches(".*\\$[0-9]+$")) { clsName = clsName.replace('$', '.'); } else { clsName = "Object"; } } if (c.isArray()) { Class cc = c.getComponentType(); while (cc.isArray()) cc = cc.getComponentType(); String cName = cc.getName(); String s = clsName; // now count the number of '[' to see how many dimension this array has int d = 0; for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == '[') { d++; } else { break; } } StringBuilder sb = new StringBuilder(cName); for (int i = 0; i < d; ++i) { sb.append("[]"); } clsName = sb.toString(); } else { // try to see if this is a generic type if (val instanceof Collection) { Collection col = (Collection)val; if (col.size() > 0) { if (val instanceof Map) { Object k = ((Map) val).keySet().iterator().next(); Object v = ((Map) val).get(k); String kType = getTypeName(k); String vType = null == v ? "Object" : getTypeName(v); clsName = clsName + "<" + kType + "," + vType + ">"; } else { Object e = col.iterator().next(); String eType = null == val ? "Object" : getTypeName(e); clsName = clsName + "<" + eType + ">"; } } } } } return clsName; } public static void registerParams(RythmEngine engine, Object... args) { if (!engine.conf().typeInferenceEnabled()) return; if (null == args || args.length == 0) return; Map<String, String> tMap = typeMap.get(); tMap.clear(); long id = 0; if (args.length == 1 && args[0] instanceof Map) { Map<String, Object> params = (Map) args[0]; for (Map.Entry<String, Object> entry : params.entrySet()) { Object val = entry.getValue(); String typeName = getTypeName(val); tMap.put(entry.getKey(), typeName); id += typeName.hashCode() * entry.getKey().hashCode(); } } else { // suppose template variable is denoted with @1, @2 ... for (int i = 0; i < args.length; ++i) { String name = "__v_" + (i + 1); // start from 1 instead of 0 String typeName = getTypeName(args[i]); tMap.put(name, typeName); id += (i + 1) * typeName.hashCode(); } } if (id < 0) id = -1 * id; uuid.set(String.valueOf(id)); } public static String uuid() { return S.str(uuid.get()); } public static Map<String, String> getTypeMap() { return typeMap.get(); } }