001: package tide.classsyntax;
002:
003: import java.lang.reflect.*;
004: import java.util.*;
005: import java.util.regex.*;
006:
007: /** Used in completion to map type parameters (definition) with the instance (usage) names.
008: */
009: public final class TypeParametersMapper {
010: final TypeVariable[] classTypes;
011: final String usageTypes;
012: // K,V,... => impl class names
013: final Map<String, String> implNamesForParam = new HashMap<String, String>();
014:
015: /**
016: * @param classTypes are the types declared in the bytecode for example <code><E,K></code>
017: * @param usageTypes are the types declared in the source for example "Double, Integer"
018: */
019: public TypeParametersMapper(TypeVariable[] classTypes,
020: String usageTypes) {
021: this .usageTypes = usageTypes;
022: this .classTypes = classTypes;
023:
024: if (classTypes == null)
025: return;
026: if (usageTypes == null)
027: return;
028: if (usageTypes.length() == 0)
029: return;
030:
031: String[] utl = usageTypes.split(",");
032: if (utl == null || utl.length == 0)
033: return;
034: for (int i = 0; i < classTypes.length; i++) {
035: implNamesForParam.put(classTypes[i].getName(), utl[i]
036: .trim());
037: }
038: }
039:
040: public String mapType(Type typeToMap) {
041: String tt = toStringTypeT(typeToMap);
042: return tt;
043: }
044:
045: /* @return typeToMap as default.
046: * @param nameToMap is the name that you will map, for example K, as appearing in the bytecode
047: * => returns "Integer"
048: *
049: private String map(String typeToMap)
050: {
051: if(typeToMap==null) return "";
052:
053:
054: String def = typeToMap; //Utils.toStringTypeForCompletion(typeToMap);
055:
056: if(def.length()==0) return def;
057: if(classTypes==null || classTypes.length==0) return def;
058: if(usageTypes==null || usageTypes.length()==0) return def;
059:
060: String[] utl = usageTypes.split(",");
061: if(utl==null || utl.length==0) return def;
062: if(classTypes.length != utl.length) return def;
063:
064: String tm = implNamesForParam.get(typeToMap);
065: if(tm!=null) return tm;
066:
067: System.out.println("\nTypeParametersMapper: not found: "+def);
068: System.out.println("CT: "+Arrays.toString(classTypes));
069: System.out.println("UL: "+Arrays.toString(utl));
070: return def;
071: } */
072:
073: private String toStringTypePT(ParameterizedType pt) {
074: /* System.out.println("\nParameterizedType");
075: System.out.println("raw: "+pt.getRawType());
076: System.out.println("owner: "+pt.getOwnerType());
077: System.out.println("args: "+Arrays.toString(pt.getActualTypeArguments()));*/
078:
079: StringBuilder sb = new StringBuilder();
080: if (pt.getRawType() != null)
081: sb.append(toStringTypeT(pt.getRawType()));
082: if (pt.getActualTypeArguments() != null) {
083: sb.append("<");
084: for (int i = 0; i < pt.getActualTypeArguments().length; i++) {
085: if (i > 0)
086: sb.append(", ");
087: sb
088: .append(toStringTypeT(pt
089: .getActualTypeArguments()[i]));
090: }
091: sb.append(">");
092: }
093: return sb.toString();
094: }
095:
096: @tide.annotations.Recurse
097: private String toStringTypeT(Type t) {
098: //System.out.println("\ntoStringType("+t+"): ");
099: if (t instanceof ParameterizedType) {
100: return toStringTypePT((ParameterizedType) t);
101: } else if (t instanceof Class) {
102: Class cl = (Class) t;
103: return cl.getSimpleName();
104: } else if (t instanceof TypeVariable) {
105: // easy case...
106: TypeVariable tv = (TypeVariable) t;
107: String n = implNamesForParam.get(tv.getName());
108: if (n != null)
109: return n;
110: return tv.getName();
111: } else if (t instanceof GenericArrayType) {
112: return toStringTypeT(((GenericArrayType) t)
113: .getGenericComponentType())
114: + "[]";
115: } else if (t instanceof WildcardType) {
116: //System.out.println("#### WildcardType: "+t);
117: WildcardType wt = (WildcardType) t;
118:
119: StringBuilder ret = new StringBuilder();
120:
121: Type[] lbs = wt.getLowerBounds();
122: if (lbs.length > 0) {
123: for (Type lbt : wt.getLowerBounds()) {
124: //System.out.println(" LowerBound: "+lbt);
125: ret.append(toStringTypeT(lbt) + ", ");
126: }
127: if (ret.toString().endsWith(", "))
128: ret.setLength(ret.length() - 2); // ???
129: } else {
130: ret.append("?");
131: }
132:
133: if (wt.getUpperBounds().length > 0) {
134: ret.append(" extends ");
135: }
136:
137: for (Type ubt : wt.getUpperBounds()) {
138: ret.append(toStringTypeT(ubt));
139: ret.append(", ");
140: //System.out.println(" UpperBound: "+ubt);
141: }
142: if (ret.toString().endsWith(", "))
143: ret.setLength(ret.length() - 2);
144:
145: /*BAD
146: //String ret = ""+t;
147: // example "? extends E"
148:
149: for(String ti : this.implNamesForParam.keySet())
150: {
151: ret = ret.replace(ti, this.implNamesForParam.get(ti));
152: } */
153:
154: String rs = ret.toString();
155:
156: if (rs.equals("? extends Object"))
157: rs = "?"; // of course :-)
158:
159: return rs;
160: } else {
161: System.out.println("TST??? " + t.getClass());
162: }
163:
164: return "?";
165:
166: }
167:
168: /** @return the params in the form "E=String, K=Hello".
169: */
170: @Override
171: public final String toString() {
172: StringBuilder sb = new StringBuilder();
173: for (String ti : this .implNamesForParam.keySet()) {
174: sb.append(ti + "=" + this .implNamesForParam.get(ti) + ", ");
175: }
176: if (sb.toString().endsWith(", "))
177: sb.setLength(sb.length() - 2);
178: return sb.toString();
179: }
180:
181: /*test*/
182: public static void main(String[] arguments) {
183: try {
184: Class<?> cl = Class.forName("java.util.Vector");
185: Method[] dms = cl.getDeclaredMethods();
186:
187: for (int i = 0; i < dms.length; i++) {
188: //System.out.println(""+i+": "+dms[i].toGenericString());
189: }
190: TypeParametersMapper tm = new TypeParametersMapper(cl
191: .getTypeParameters(), "AAAA,BBBB");
192:
193: Method m1 = dms[15]; //0,2, 15
194:
195: System.out.println("" + m1.toGenericString());
196: System.out.println("" + m1.getGenericReturnType());
197: System.out.println("RT = "
198: + tm.toStringTypeT(m1.getGenericReturnType()));
199:
200: for (Type ti : m1.getGenericParameterTypes()) {
201: System.out.println(" " + tm.mapType(ti) + " for "
202: + ti);
203: }
204:
205: // System.out.println(""+ tm.replaceAllTypeParams("aaa<K, V>"));
206:
207: // System.out.println(""+ tm.replaceAllTypeParams( dms[8].toGenericString() ));
208: } catch (Exception e) {
209: e.printStackTrace();
210: }
211: }
212:
213: /*
214:
215: /* A little bit subtle, but works.
216: * replaces "<K>" ", K>" "<K," ", K," with their impl names.
217: * we must be careful, not recurse replacing !!
218: * @param name is for example "java.util.Set<K>", this will replace K with the
219: *
220: *
221: public String replaceAllTypeParams(String name)
222: {
223: System.out.println("repl "+name);
224: String ret = name;
225: for(String pn : implNamesForParam.keySet())
226: {
227: String imn = implNamesForParam.get(pn);
228: //System.out.println(""+pn+" => "+imn);
229: ret = ret.replaceAll( Pattern.quote("<"+pn+">"), "<"+imn+">");
230: ret = ret.replaceAll( Pattern.quote("<"+pn+","), "<"+imn+",");
231: ret = ret.replaceAll( Pattern.quote(", "+pn+">"), ", "+imn+">");
232: ret = ret.replaceAll( Pattern.quote(", "+pn+","), ", "+imn+",");
233: }
234: //System.out.println(" => "+ret);
235:
236: return ret;
237: } */
238:
239: }
|