1 /*
2 * Copyright 2003-2007 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.codehaus.groovy.vmplugin.v5;
18
19 import java.lang.reflect;
20 import java.lang.annotation;
21 import java.util.Iterator;
22 import java.util.List;
23
24 import org.codehaus.groovy.GroovyBugError;
25 import org.codehaus.groovy.vmplugin.VMPlugin;
26 import org.codehaus.groovy.ast;
27 import org.codehaus.groovy.ast.expr;
28 import org.codehaus.groovy.ast.stmt.ReturnStatement;
29 import org.codehaus.groovy.ast.ClassHelper;
30
31 /**
32 * java 5 based functions
33 * @author Jochen Theodorou
34 *
35 */
36 public class Java5 implements VMPlugin {
37 private static Class[] PLUGIN_DGM={PluginDefaultGroovyMethods.class};
38
39 public void setAdditionalClassInformation(ClassNode cn) {
40 setGenericsTypes(cn);
41 }
42
43 private void setGenericsTypes(ClassNode cn) {
44 TypeVariable[] tvs = cn.getTypeClass().getTypeParameters();
45 GenericsType[] gts = configureTypeVariable(tvs);
46 cn.setGenericsTypes(gts);
47 }
48
49 private GenericsType[] configureTypeVariable(TypeVariable[] tvs) {
50 if (tvs.length==0) return null;
51 GenericsType[] gts = new GenericsType[tvs.length];
52 for (int i = 0; i < tvs.length; i++) {
53 gts[i] = configureTypeVariableDefintion(tvs[i]);
54 }
55 return gts;
56 }
57
58 private GenericsType configureTypeVariableDefintion(TypeVariable tv) {
59 ClassNode base = configureTypeVariableReference(tv);
60 ClassNode redirect = base.redirect();
61 base.setRedirect(null);
62 Type[] tBounds = tv.getBounds();
63 GenericsType gt;
64 if (tBounds.length==0) {
65 gt = new GenericsType(base);
66 } else {
67 ClassNode[] cBounds = configureTypes(tBounds);
68 gt = new GenericsType(base,cBounds,null);
69 gt.setName(base.getName());
70 gt.setPlaceholder(true);
71 }
72 base.setRedirect(redirect);
73 return gt;
74 }
75
76 private ClassNode[] configureTypes(Type[] types){
77 if (types.length==0) return null;
78 ClassNode[] nodes = new ClassNode[types.length];
79 for (int i=0; i<types.length; i++){
80 nodes[i] = configureType(types[i]);
81 }
82 return nodes;
83 }
84
85 private ClassNode configureType(Type type) {
86 if (type instanceof WildcardType) {
87 return configureWildcardType((WildcardType) type);
88 } else if (type instanceof ParameterizedType) {
89 return configureParameterizedType((ParameterizedType) type);
90 } else if (type instanceof GenericArrayType) {
91 return configureGenericArray((GenericArrayType) type);
92 } else if (type instanceof TypeVariable) {
93 return configureTypeVariableReference((TypeVariable) type);
94 } else if (type instanceof Class) {
95 return configureClass((Class) type);
96 } else {
97 throw new GroovyBugError("unknown type: " + type + " := " + type.getClass());
98 }
99 }
100
101 private ClassNode configureClass(Class c){
102 if (c.isPrimitive()) {
103 return ClassHelper.make(c);
104 } else {
105 return ClassHelper.makeWithoutCaching(c, false);
106 }
107 }
108
109 private ClassNode configureGenericArray(GenericArrayType genericArrayType) {
110 Type component = genericArrayType.getGenericComponentType();
111 ClassNode node = configureType(component);
112 return node.makeArray();
113 }
114
115 private ClassNode configureWildcardType(WildcardType wildcardType) {
116 ClassNode base = ClassHelper.makeWithoutCaching("?");
117 //TODO: more than one lower bound for wildcards?
118 ClassNode[] lowers = configureTypes(wildcardType.getLowerBounds());
119 ClassNode lower=null;
120 if (lower!=null) lower = lowers[0];
121
122 ClassNode[] upper = configureTypes(wildcardType.getUpperBounds());
123 GenericsType t = new GenericsType(base,upper,lower);
124 t.setWildcard(true);
125
126 ClassNode ref = ClassHelper.makeWithoutCaching(Object.class,false);
127 ref.setGenericsTypes(new GenericsType[]{t});
128
129 return ref;
130 }
131
132 private ClassNode configureParameterizedType(ParameterizedType parameterizedType) {
133 ClassNode base = configureType(parameterizedType.getRawType());
134 GenericsType[] gts = configureTypeArguments(parameterizedType.getActualTypeArguments());
135 base.setGenericsTypes(gts);
136 return base;
137 }
138
139 private ClassNode configureTypeVariableReference(TypeVariable tv) {
140 ClassNode cn = ClassHelper.makeWithoutCaching(tv.getName());
141 cn.setGenericsPlaceHolder(true);
142 ClassNode cn2 = ClassHelper.makeWithoutCaching(tv.getName());
143 GenericsType[] gts = new GenericsType[]{new GenericsType(cn2)};
144 cn.setGenericsTypes(gts);
145 cn.setRedirect(ClassHelper.OBJECT_TYPE);
146 return cn;
147 }
148
149 private GenericsType[] configureTypeArguments(Type[] ta) {
150 if (ta.length==0) return null;
151 GenericsType[] gts = new GenericsType[ta.length];
152 for (int i = 0; i < ta.length; i++) {
153 gts[i] = new GenericsType(configureType(ta[i]));
154 }
155 return gts;
156 }
157
158 public Class[] getPluginDefaultGroovyMethods() {
159 return PLUGIN_DGM;
160 }
161
162 private void setAnnotationMetaData(ClassNode cn) {
163 Annotation[] annotations = cn.getTypeClass().getAnnotations();
164 for (int i=0; i<annotations.length; i++) {
165 Annotation annotation = annotations[i];
166 AnnotationNode node = new AnnotationNode(ClassHelper.make(annotation.annotationType()));
167 configureAnnotation(node,annotation);
168 cn.addAnnotation(node);
169 }
170 }
171
172 private void configureAnnotationFromDefinition(AnnotationNode definition, AnnotationNode root) {
173 ClassNode type = definition.getClassNode();
174 if (!type.isResolved()) return;
175 Class clazz = type.getTypeClass();
176 if (clazz==Retention.class) {
177 Expression exp = definition.getMember("value");
178 if (!(exp instanceof PropertyExpression)) return;
179 PropertyExpression pe = (PropertyExpression) exp;
180 String name = pe.getPropertyAsString();
181 RetentionPolicy policy = RetentionPolicy.valueOf(name);
182 setRetentionPolicy(policy,root);
183 } else if (clazz==Target.class) {
184 Expression exp = definition.getMember("value");
185 if (!(exp instanceof ListExpression)) return;
186 ListExpression le = (ListExpression) exp;
187 int bitmap = 0;
188 for (Iterator it=le.getExpressions().iterator(); it.hasNext();) {
189 PropertyExpression element = (PropertyExpression) it.next();
190 String name = element.getPropertyAsString();
191 ElementType value = ElementType.valueOf(name);
192 bitmap |= getElementCode(value);
193 }
194 root.setAllowedTargets(bitmap);
195 }
196 }
197
198 public void configureAnnotation(AnnotationNode node) {
199 ClassNode type = node.getClassNode();
200 List annotations = type.getAnnotations();
201 for (Iterator it=annotations.iterator(); it.hasNext();) {
202 AnnotationNode an = (AnnotationNode) it.next();
203 configureAnnotationFromDefinition(an,node);
204 }
205
206 configureAnnotationFromDefinition(node,node);
207 }
208
209 private void configureAnnotation(AnnotationNode node, Annotation annotation) {
210 Class type = annotation.annotationType();
211 if (type == Retention.class) {
212 Retention r = (Retention) annotation;
213 RetentionPolicy value = r.value();
214 setRetentionPolicy(value,node);
215 node.setMember("value",new PropertyExpression(
216 new ClassExpression(ClassHelper.makeWithoutCaching(RetentionPolicy.class,false)),
217 value.toString()));
218 } else if (type == Target.class) {
219 Target t = (Target) annotation;
220 ElementType[] elements = t.value();
221 int bitmap = 0;
222 for (int i=0; i<elements.length; i++) {
223 bitmap |= getElementCode(elements[i]);
224 }
225 node.setAllowedTargets(bitmap);
226 }
227 }
228
229 private void setRetentionPolicy(RetentionPolicy value, AnnotationNode node) {
230 switch (value) {
231 case RUNTIME: node.setRuntimeRetention(true); break;
232 case SOURCE: node.setSourceRetention(true); break;
233 case CLASS: node.setClassRetention(true); break;
234 default: throw new GroovyBugError("unsupported Retention "+value);
235 }
236 }
237
238 private int getElementCode(ElementType value) {
239 switch (value) {
240 case TYPE: return AnnotationNode.TYPE_TARGET;
241 case CONSTRUCTOR: return AnnotationNode.CONSTRUCTOR_TARGET;
242 case METHOD: return AnnotationNode.METHOD_TARGET;
243 case FIELD: return AnnotationNode.FIELD_TARGET;
244 case PARAMETER: return AnnotationNode.PARAMETER_TARGET;
245 case LOCAL_VARIABLE: return AnnotationNode.LOCAL_VARIABLE_TARGET;
246 case ANNOTATION_TYPE: return AnnotationNode.ANNOTATION_TARGET;
247 case PACKAGE: return AnnotationNode.PACKAGE_TARGET;
248 default: throw new GroovyBugError("unsupported Target " + value);
249 }
250 }
251
252 private void setMethodDefaultValue(MethodNode mn, Method m) {
253 Object defaultValue = m.getDefaultValue();
254 mn.setCode(new ReturnStatement(new ConstantExpression(defaultValue)));
255 mn.setAnnotationDefault(true);
256 }
257
258 public void configureClassNode(CompileUnit compileUnit, ClassNode classNode) {
259 Class clazz = classNode.getTypeClass();
260 Field[] fields = clazz.getDeclaredFields();
261 for (int i = 0; i < fields.length; i++) {
262 Field f = fields[i];
263 ClassNode ret = makeClassNode(compileUnit,f.getGenericType(),f.getType());
264 classNode.addField(fields[i].getName(), fields[i].getModifiers(), ret, null);
265 }
266 Method[] methods = clazz.getDeclaredMethods();
267 for (int i = 0; i < methods.length; i++) {
268 Method m = methods[i];
269 ClassNode ret = makeClassNode(compileUnit,m.getGenericReturnType(),m.getReturnType());
270 Parameter[] params = makeParameters(compileUnit,m.getGenericParameterTypes(),m.getParameterTypes());
271 ClassNode[] exceptions = makeClassNodes(compileUnit,m.getGenericExceptionTypes(),m.getExceptionTypes());
272 MethodNode mn = new MethodNode(m.getName(), m.getModifiers(), ret, params, exceptions, null);
273 setMethodDefaultValue(mn,m);
274 classNode.addMethod(mn);
275 }
276 Constructor[] constructors = clazz.getDeclaredConstructors();
277 for (int i = 0; i < constructors.length; i++) {
278 Constructor ctor = constructors[i];
279 Parameter[] params = makeParameters(compileUnit,ctor.getGenericParameterTypes(), ctor.getParameterTypes());
280 ClassNode[] exceptions = makeClassNodes(compileUnit,ctor.getGenericExceptionTypes(),ctor.getExceptionTypes());
281 classNode.addConstructor(ctor.getModifiers(), params, exceptions, null);
282 }
283
284 Class sc = clazz.getSuperclass();
285 if (sc != null) classNode.setUnresolvedSuperClass(makeClassNode(compileUnit,clazz.getGenericSuperclass(),sc));
286 makeInterfaceTypes(compileUnit,classNode,clazz);
287 setAnnotationMetaData(classNode);
288
289 }
290
291 private void makeInterfaceTypes(CompileUnit cu, ClassNode classNode, Class clazz) {
292 Type[] interfaceTypes = clazz.getGenericInterfaces();
293 if (interfaceTypes.length==0) {
294 classNode.setInterfaces(ClassNode.EMPTY_ARRAY);
295 } else {
296 Class[] interfaceClasses = clazz.getInterfaces();
297 ClassNode[] ret = new ClassNode[interfaceTypes.length];
298 for (int i=0;i<interfaceTypes.length;i++){
299 ret[i] = makeClassNode(cu, interfaceTypes[i], interfaceClasses[i]);
300 }
301 classNode.setInterfaces(ret);
302 }
303 }
304
305 private ClassNode[] makeClassNodes(CompileUnit cu, Type[] types, Class[] cls) {
306 ClassNode[] nodes = new ClassNode[types.length];
307 for (int i=0;i<nodes.length;i++) {
308 nodes[i] = makeClassNode(cu, types[i],cls[i]);
309 }
310 return nodes;
311 }
312
313 private ClassNode makeClassNode(CompileUnit cu, Type t, Class c) {
314 ClassNode back = null;
315 if (cu!=null) back = cu.getClass(c.getName());
316 if (back==null) back = ClassHelper.make(c);
317 if (!(t instanceof Class)) {
318 ClassNode front = configureType(t);
319 front.setRedirect(back);
320 return front;
321 }
322 return back;
323 }
324
325 private Parameter[] makeParameters(CompileUnit cu, Type[] types, Class[] cls) {
326 Parameter[] params = Parameter.EMPTY_ARRAY;
327 if (types.length>0) {
328 params = new Parameter[types.length];
329 for (int i=0;i<params.length;i++) {
330 params[i] = makeParameter(cu,types[i],cls[i],i);
331 }
332 }
333 return params;
334 }
335
336 private Parameter makeParameter(CompileUnit cu, Type type, Class cl,int idx) {
337 ClassNode cn = makeClassNode(cu,type,cl);
338 return new Parameter(cn, "param" + idx);
339 }
340 }
341