001: /*
002: * Spoon - http://spoon.gforge.inria.fr/
003: * Copyright (C) 2006 INRIA Futurs <renaud.pawlak@inria.fr>
004: *
005: * This software is governed by the CeCILL-C License under French law and
006: * abiding by the rules of distribution of free software. You can use, modify
007: * and/or redistribute the software under the terms of the CeCILL-C license as
008: * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
009: *
010: * This program is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
013: *
014: * The fact that you are presently reading this means that you have had
015: * knowledge of the CeCILL-C license and that you accept its terms.
016: */
017:
018: package spoon.support.template;
019:
020: import java.lang.reflect.Field;
021: import java.lang.reflect.Modifier;
022: import java.util.ArrayList;
023: import java.util.Collection;
024: import java.util.HashMap;
025: import java.util.Map;
026:
027: import spoon.reflect.code.CtArrayAccess;
028: import spoon.reflect.code.CtCodeElement;
029: import spoon.reflect.code.CtExpression;
030: import spoon.reflect.code.CtLiteral;
031: import spoon.reflect.declaration.CtClass;
032: import spoon.reflect.declaration.CtField;
033: import spoon.reflect.declaration.CtSimpleType;
034: import spoon.reflect.reference.CtFieldReference;
035: import spoon.reflect.reference.CtTypeParameterReference;
036: import spoon.support.util.RtHelper;
037: import spoon.template.Parameter;
038: import spoon.template.Template;
039: import spoon.template.TemplateParameter;
040:
041: /**
042: * This class defines an API to manipulate template parameters.
043: */
044: public abstract class Parameters {
045:
046: private Parameters() {
047: }
048:
049: /**
050: * The prefix "_FIELD_" for a parameter that represents a fields in order to
051: * avoid name clashes.
052: */
053: protected static final String fieldPrefix = "_FIELD_";
054:
055: /**
056: * Gets the index of a one-dimension array (helper).
057: */
058: @SuppressWarnings("unchecked")
059: public static Integer getIndex(CtExpression<?> e) {
060: if (e.getParent() instanceof CtArrayAccess) {
061: CtExpression<Integer> indexExpression = ((CtArrayAccess<?, CtExpression<Integer>>) e
062: .getParent()).getIndexExpression();
063: return ((CtLiteral<Integer>) indexExpression).getValue();
064: }
065: return null;
066: }
067:
068: /**
069: * Gets a template field parameter value.
070: */
071: public static Object getValue(Template template,
072: String parameterName, Integer index) {
073: Object tparamValue = null;
074: try {
075: Field rtField = null;
076: for (Field f : RtHelper.getAllFields(template.getClass())) {
077: if (isParameterSource(f)) {
078: if (parameterName.equals(getParameterName(f))) {
079: rtField = f;
080: break;
081: }
082: }
083: }
084: if (Modifier.isFinal(rtField.getModifiers())) {
085: Map<String, Object> m = finals.get(template);
086: if (m == null) {
087: return null;
088: }
089: return m.get(parameterName);
090: }
091: rtField.setAccessible(true);
092: tparamValue = rtField.get(template);
093: if (rtField.getType().isArray() && (index != null)) {
094: tparamValue = ((Object[]) tparamValue)[index];
095: }
096: } catch (Exception e) {
097: throw new UndefinedParameterException();
098: }
099: return tparamValue;
100: }
101:
102: static Map<Template, Map<String, Object>> finals = new HashMap<Template, Map<String, Object>>();
103:
104: public static CtField<?> getParameterField(
105: CtClass<? extends Template> templateClass,
106: String parameterName) {
107: for (CtField<?> f : templateClass.getFields()) {
108: Parameter p = f.getAnnotation(Parameter.class);
109: if (p == null) {
110: continue;
111: }
112: if (f.getSimpleName().equals(parameterName)) {
113: return f;
114: }
115: if (parameterName.equals(p.value())) {
116: return f;
117: }
118: }
119: return null;
120: }
121:
122: /**
123: * Sets a template field parameter value.
124: */
125: public static void setValue(Template template,
126: String parameterName, Integer index, Object value) {
127: Object tparamValue = null;
128: try {
129: Field rtField = null;
130: for (Field f : RtHelper.getAllFields(template.getClass())) {
131: if (isParameterSource(f)) {
132: if (parameterName.equals(getParameterName(f))) {
133: rtField = f;
134: break;
135: }
136: }
137: }
138: if (rtField == null) {
139: return;
140: }
141: if (Modifier.isFinal(rtField.getModifiers())) {
142: Map<String, Object> m = finals.get(template);
143: if (m == null) {
144: finals.put(template,
145: m = new HashMap<String, Object>());
146: }
147: m.put(parameterName, value);
148: return;
149: }
150: rtField.setAccessible(true);
151: rtField.set(template, value);
152: if (rtField.getType().isArray()) {
153: tparamValue = ((Object[]) tparamValue)[index];
154: }
155: } catch (Exception e) {
156: throw new UndefinedParameterException();
157: }
158: }
159:
160: private static String getParameterName(Field f) {
161: String name = f.getName();
162: Parameter p = f.getAnnotation(Parameter.class);
163: if ((p != null) && !p.value().equals("")) {
164: name = p.value();
165: }
166: return name;
167: }
168:
169: private static String getParameterName(CtFieldReference<?> f) {
170: String name = f.getSimpleName();
171: Parameter p = f.getAnnotation(Parameter.class);
172: if ((p != null) && !p.value().equals("")) {
173: name = p.value();
174: }
175: return name;
176: }
177:
178: /**
179: * Gets the names of all the template parameters of a given template type
180: * (including the ones defined by the super types).
181: */
182: public static Collection<String> getNames(
183: CtClass<? extends Template> templateType) {
184: Collection<String> params = new ArrayList<String>();
185: try {
186: for (CtFieldReference<?> f : templateType.getReference()
187: .getAllFields()) {
188: if (isParameterSource(f)) {
189: params.add(getParameterName(f));
190: }
191: }
192: } catch (Exception e) {
193: e.printStackTrace();
194: }
195: return params;
196: }
197:
198: /**
199: * Tells if a given field is a template parameter.
200: */
201: public static boolean isParameterSource(CtFieldReference<?> ref) {
202: return (ref.getAnnotation(Parameter.class) != null)
203: || (!((ref.getType() instanceof CtTypeParameterReference) || ref
204: .getSimpleName().equals("this")) && TemplateParameter.class
205: .isAssignableFrom(ref.getType()
206: .getActualClass()));
207: }
208:
209: /**
210: * Tells if a given field is a template parameter.
211: */
212: public static boolean isParameterSource(Field field) {
213: return (field.getAnnotation(Parameter.class) != null)
214: || TemplateParameter.class.isAssignableFrom(field
215: .getType());
216: }
217:
218: /**
219: * Creates an empty template parameter of the <code>T</code> type where
220: * {@link TemplateParameter#S()} does not return <code>null</code> in case
221: * the template code needs to be executed such as in static initializers.
222: */
223: @SuppressWarnings("unchecked")
224: public static <T> TemplateParameter<T> NIL(Class<? extends T> type) {
225: if (Number.class.isAssignableFrom(type)) {
226: return (TemplateParameter<T>) new TemplateParameter<Number>() {
227: public CtCodeElement getSubstitution(
228: CtSimpleType targetType) {
229: return null;
230: }
231:
232: public Number S() {
233: return 0;
234: }
235: };
236: }
237: return new TemplateParameter<T>() {
238: public CtCodeElement getSubstitution(CtSimpleType targetType) {
239: return null;
240: }
241:
242: public T S() {
243: return null;
244: }
245: };
246: }
247:
248: }
|