001: /*
002: * Project: BeautyJ - Customizable Java Source Code Transformer
003: * Class: de.gulden.util.javasource.Type
004: * Version: 1.1
005: *
006: * Date: 2004-09-29
007: *
008: * Note: Contains auto-generated Javadoc comments created by BeautyJ.
009: *
010: * This is licensed under the GNU General Public License (GPL)
011: * and comes with NO WARRANTY. See file license.txt for details.
012: *
013: * Author: Jens Gulden
014: * Email: beautyj@jensgulden.de
015: */
016:
017: package de.gulden.util.javasource;
018:
019: import de.gulden.util.javasource.jjt.Node;
020: import de.gulden.util.javasource.jjt.*;
021: import javax.xml.parsers.*;
022: import org.w3c.dom.*;
023: import java.io.*;
024: import java.util.*;
025:
026: /**
027: * Represents a type.
028: *
029: * @author Jens Gulden
030: * @version 1.0
031: */
032: public class Type implements ParserTreeConstants, Serializable {
033:
034: // ------------------------------------------------------------------------
035: // --- fields ---
036: // ------------------------------------------------------------------------
037:
038: /**
039: * The type name.
040: */
041: protected String typeName;
042:
043: /**
044: * The dimension.
045: */
046: protected int dimension;
047:
048: /**
049: * The my member.
050: */
051: protected Member myMember;
052:
053: // ------------------------------------------------------------------------
054: // --- constructor ---
055: // ------------------------------------------------------------------------
056:
057: /**
058: * Creates a new instance of Type.
059: */
060: public Type(Member member) {
061: myMember = member;
062: }
063:
064: // ------------------------------------------------------------------------
065: // --- methods ---
066: // ------------------------------------------------------------------------
067:
068: /**
069: * Returns the unqualified type name.
070: */
071: public String getUnqualifiedTypeName() {
072: return SourceObject.unqualify(typeName,
073: countOuterClasses(typeName));
074: }
075:
076: /**
077: * Returns the type name.
078: */
079: public String getTypeName() {
080: return typeName;
081: }
082:
083: /**
084: * Returns the full type name.
085: */
086: public String getFullTypeName() {
087: return getTypeName() + SourceParser.repeat("[]", dimension);
088: }
089:
090: /**
091: * Returns the full type name.
092: */
093: public String getFullUnqualifiedTypeName() {
094: return getUnqualifiedTypeName()
095: + SourceParser.repeat("[]", dimension);
096: }
097:
098: /**
099: * Returns the dimension.
100: */
101: public int getDimension() {
102: return dimension;
103: }
104:
105: /**
106: * Sets the type name.
107: */
108: public void setTypeName(String n) {
109: typeName = n;
110: }
111:
112: /**
113: * Sets the dimension.
114: */
115: public void setDimension(int d) {
116: dimension = d;
117: }
118:
119: /**
120: * Output this object as XML.
121: *
122: * @return The XML tag.
123: * @see #initFromXML
124: */
125: public Element buildXML(Document d) {
126: Element e = d.createElement("type");
127: String typeName = getTypeName();
128: e.setAttribute("name", typeName);
129: e.setAttribute("unqualifiedName", SourceObject
130: .unqualify(typeName));
131: e.setAttribute("dimension", String.valueOf(getDimension()));
132: e.setAttribute("fullName", String.valueOf(getFullTypeName()));
133: return e;
134: }
135:
136: /**
137: * Initialize this object from XML.
138: *
139: * @param element The XML tag.
140: * @throws IOException if an i/o error occurs
141: */
142: public void initFromXML(Element element) throws IOException {
143: String n = element.getAttribute("name");
144: String d = element.getAttribute("dimension");
145: if ((n != null) && (d != null)) {
146: try {
147: typeName = n;
148: dimension = Integer.parseInt(d);
149: } catch (NumberFormatException nfe) {
150: throw new IOException(
151: "'<type>' tag must have numeric attribute 'dimension'");
152: }
153: } else {
154: throw new IOException(
155: "'<type>' tag must have attribute 'qualifiedName'");
156: }
157: }
158:
159: /**
160: * Initialize this object from parsed Java code.
161: * Special way of invoking.
162: *
163: * @param fathernode A father node from where array-declarators are recursively counted.
164: */
165: void initFromAST(Node fathernode) {
166: initFromAST(fathernode, null);
167: }
168:
169: /**
170: * Initialize this object from parsed Java code.
171: * Special way of invoking.
172: *
173: * @param fathernode A father node from where array-declarators are recursively counted. May be null.
174: * @param varnode variable declarator node from where additional array-declarators are recursively counted. May be null.
175: */
176: void initFromAST(Node fathernode, Node varnode) {
177: Node typenode = fathernode.getChild(JJT_TYPE);
178: if (typenode.getChild(JJT_NAME) != null) {
179: String n = typenode.getName();
180: typeName = myMember.getDeclaringClass().qualify(n);
181: } else {
182: typeName = "void";
183: }
184: Node searchNode;
185: if (varnode != null) {
186: searchNode = typenode;
187: } else {
188: searchNode = fathernode;
189: }
190: dimension = countArrayDimension(searchNode);
191: if (varnode != null) {
192: dimension += countArrayDimension(varnode);
193: }
194: }
195:
196: private int countOuterClasses(String classname) {
197: // is classname referencing source?
198: Package basePackage = myMember.getPackage().getBasePackage();
199: Class clazz = basePackage.findClass(classname);
200: if (clazz != null) { // yes, known from source
201: int cnt = 0;
202: while (clazz instanceof ClassInner) {
203: cnt++;
204: clazz = ((ClassInner) clazz).getDeclaringClass();
205: }
206: return cnt;
207: } else { // get from classpath
208: int cnt = 0;
209: boolean found = false;
210: do {
211: try {
212: //cl.loadClass(classname); // will fail if not inner class
213: java.lang.Class.forName(classname); // will throw exception if the name is a _valid_ inner class name, because inner classes must be seperated by '$' from their parents
214: found = true;
215: } catch (ClassNotFoundException cnfe) {
216: cnt++;
217: // remove last component, until a non-inner class is reached
218: int pos = classname.lastIndexOf('.');
219: if (pos == -1) { // should actually not happen as we assume parameter classname is aready qualified (and verified for existance by doing that)
220: return 0;
221: }
222: classname = classname.substring(0, pos);
223: }
224: } while (!found);
225: return cnt;
226: }
227: }
228:
229: // ------------------------------------------------------------------------
230: // --- static method ---
231: // ------------------------------------------------------------------------
232:
233: /**
234: * Traverse through sub-tree and count occurrences of _ISARRAY-node.
235: */
236: private static int countArrayDimension(Node n) {
237: if (n.getId() == JJT_ISARRAY) {
238: return 1;
239: } else if (n.getId() == JJT_CODE) {
240: return 0; // do not recurse into code-section
241: } else {
242: int sum = 0;
243: Node[] children = n.getAllChildren();
244: for (int i = 0; i < children.length; i++) {
245: Node child = children[i];
246: if (child.getId() != JJT_PARAMETER) { // don't recurse into parameter (if n if JJT_METHOD), testing here allows still the first call with n.getId()==JJT_PARAMETER when parsing parameters
247: sum += countArrayDimension(children[i]); // recursion
248: }
249: }
250: return sum;
251: }
252: }
253:
254: } // end Type
|