001: package jaxx.reflect;
002:
003: import java.io.*;
004: import java.lang.reflect.*;
005: import java.util.*;
006:
007: import jaxx.*;
008: import jaxx.compiler.*;
009: import jaxx.reflect.*;
010: import jaxx.tags.*;
011: import jaxx.parser.*;
012:
013: // TODO: need to unify this implementation with the parsing in ScriptManager
014: public class JavaFileParser {
015: private JAXXCompiler compiler;
016: private String className;
017: private String packageName = null;
018: private String super class = "java.lang.Object";
019: private List/*<MethodDescriptor>*/methods = new ArrayList/*<MethodDescriptor>*/();
020: private List/*<FieldDescriptor>*/fields = new ArrayList/*<FieldDescriptor>*/();
021:
022: private JavaFileParser(ClassLoader classLoader) {
023: compiler = JAXXCompiler.createDummyCompiler(classLoader);
024: }
025:
026: public static ClassDescriptor parseJavaFile(String displayName,
027: Reader src, ClassLoader classLoader)
028: throws ClassNotFoundException {
029: // has some limitations -- it reports all members as public, leaves getDeclaredMethod and getDeclaredField
030: // undefined, and doesn't report interfaces. It's safe to leave those the way they are for now, because
031: // JAXX doesn't look at any of those for non-JAXX classes.
032: JavaFileParser parser = new JavaFileParser(classLoader);
033: parser.doParse(displayName, src);
034:
035: List/*<MethodDescriptor>*/publicMethods = parser.methods;
036: List/*<FieldDescriptor>*/publicFields = parser.fields;
037: List/*<MethodDescriptor>*/declaredMethods = new ArrayList/*<MethodDescriptor>*/(
038: publicMethods);
039: List/*<FieldDescriptor>*/declaredFields = new ArrayList/*<FieldDescriptor>*/(
040: publicFields);
041: Iterator/*<MethodDescriptor>*/methods = publicMethods
042: .iterator();
043: while (methods.hasNext()) {
044: MethodDescriptor method = (MethodDescriptor) methods.next();
045: if (!Modifier.isPublic(method.getModifiers()))
046: methods.remove();
047: }
048: Iterator/*<FieldDescriptor>*/fields = publicFields.iterator();
049: while (fields.hasNext()) {
050: FieldDescriptor field = (FieldDescriptor) fields.next();
051: if (!Modifier.isPublic(field.getModifiers()))
052: fields.remove();
053: }
054: ClassDescriptor super classDescriptor = ClassDescriptorLoader
055: .getClassDescriptor(parser.super class, classLoader);
056: publicMethods.addAll(Arrays.asList(super classDescriptor
057: .getMethodDescriptors()));
058: publicFields.addAll(Arrays.asList(super classDescriptor
059: .getFieldDescriptors()));
060: Set/*<String>*/interfaces = new HashSet/*<String>*/();
061: ClassDescriptor[] super classInterfaces = super classDescriptor
062: .getInterfaces();
063: for (int i = 0; i < super classInterfaces.length; i++)
064: interfaces.add(super classInterfaces[i].getName());
065: return new ClassDescriptor(parser.className,
066: parser.packageName, parser.super class, new String[0],
067: false, false, null, null, classLoader,
068: (MethodDescriptor[]) publicMethods
069: .toArray(new MethodDescriptor[publicMethods
070: .size()]),
071: (FieldDescriptor[]) publicFields
072: .toArray(new FieldDescriptor[publicFields
073: .size()])) {
074: public FieldDescriptor getDeclaredFieldDescriptor(
075: String name) throws NoSuchFieldException {
076: throw new NoSuchFieldException(name);
077: }
078:
079: public MethodDescriptor getDeclaredMethodDescriptor(
080: String name, ClassDescriptor[] parameterTypes)
081: throws NoSuchMethodException {
082: throw new NoSuchMethodException(name);
083: }
084: };
085: }
086:
087: private void doParse(String displayName, Reader src) {
088: try {
089: JavaParser p = new JavaParser(src);
090: p.CompilationUnit();
091: SimpleNode node = p.popNode();
092: if (node != null)
093: scanCompilationUnit(node);
094: else
095: throw new CompilerException(
096: "Internal error: null node parsing Java file from "
097: + src);
098: } catch (ParseException e) {
099: throw new CompilerException(
100: "Error parsing Java source code " + displayName
101: + ": " + e.getMessage());
102: }
103: }
104:
105: private void scanCompilationUnit(SimpleNode node) {
106: for (int i = 0; i < node.jjtGetNumChildren(); i++) {
107: SimpleNode child = node.getChild(i);
108: int nodeType = child.getId();
109: if (nodeType == JavaParserTreeConstants.JJTPACKAGEDECLARATION) {
110: packageName = child.getChild(1).getText().trim();
111: compiler.addImport(packageName + ".*");
112: } else if (nodeType == JavaParserTreeConstants.JJTIMPORTDECLARATION) {
113: String text = child.getText().trim();
114: if (text.startsWith("import"))
115: text = text.substring("import".length()).trim();
116: if (text.endsWith(";"))
117: text = text.substring(0, text.length() - 1);
118: compiler.addImport(text);
119: } else if (nodeType == JavaParserTreeConstants.JJTTYPEDECLARATION)
120: scanCompilationUnit(child);
121: else if (nodeType == JavaParserTreeConstants.JJTCLASSORINTERFACEDECLARATION)
122: scanClass(child);
123: }
124: }
125:
126: // scans the main ClassOrInterfaceDeclaration
127: private void scanClass(SimpleNode node) {
128: boolean isInterface = node.firstToken.image.equals("interface");
129: className = node.firstToken.next.image;
130: if (packageName != null)
131: className = packageName + "." + className;
132: for (int i = 0; i < node.jjtGetNumChildren(); i++) {
133: SimpleNode child = node.getChild(i);
134: int nodeType = child.getId();
135: if (nodeType == JavaParserTreeConstants.JJTEXTENDSLIST) {
136: if (!isInterface) {
137: assert child.jjtGetNumChildren() == 1 : "expected ExtendsList to have exactly one child for a non-interface class";
138: String rawName = child.getChild(0).getText().trim();
139: super class = TagManager.resolveClassName(rawName,
140: compiler);
141: if (super class == null)
142: throw new CompilerException(
143: "Could not find class: " + rawName);
144: }
145: } else if (nodeType == JavaParserTreeConstants.JJTCLASSORINTERFACEBODY)
146: scanClassNode(child);
147: }
148: }
149:
150: // scans class body nodes
151: private void scanClassNode(SimpleNode node) {
152: int nodeType = node.getId();
153: if (nodeType == JavaParserTreeConstants.JJTMETHODDECLARATION) {
154: String returnType = null;
155: String name = null;
156: List/*<String>*/parameterTypes = new ArrayList/*<String>*/();
157: List/*<String>*/parameterNames = new ArrayList/*<String>*/();
158: for (int i = 0; i < node.jjtGetNumChildren(); i++) {
159: SimpleNode child = node.getChild(i);
160: int type = child.getId();
161: if (type == JavaParserTreeConstants.JJTRESULTTYPE)
162: returnType = TagManager.resolveClassName(child
163: .getText().trim(), compiler);
164: else if (type == JavaParserTreeConstants.JJTMETHODDECLARATOR) {
165: name = child.firstToken.image.trim();
166: SimpleNode formalParameters = child.getChild(0);
167: assert formalParameters.getId() == JavaParserTreeConstants.JJTFORMALPARAMETERS;
168: for (int j = 0; j < formalParameters
169: .jjtGetNumChildren(); j++) {
170: SimpleNode parameter = formalParameters
171: .getChild(j);
172: String rawParameterType = parameter.getChild(1)
173: .getText().trim().replaceAll(
174: "\\.\\.\\.", "[]");
175: String parameterType = TagManager
176: .resolveClassName(rawParameterType,
177: compiler);
178: if (parameterType == null
179: && JAXXCompiler.STRICT_CHECKS)
180: throw new CompilerException(
181: "could not find class '"
182: + rawParameterType + "'");
183: parameterTypes.add(parameterType);
184: parameterNames.add(parameter.getChild(2)
185: .getText().trim());
186: }
187: }
188: }
189: methods
190: .add(new MethodDescriptor(name, Modifier.PUBLIC,
191: returnType, (String[]) parameterTypes
192: .toArray(new String[parameterTypes
193: .size()]), compiler
194: .getClassLoader())); // TODO: determine the actual modifiers
195: } else if (nodeType == JavaParserTreeConstants.JJTCLASSORINTERFACEDECLARATION) {
196: // TODO: handle inner classes
197: } else if (nodeType == JavaParserTreeConstants.JJTCONSTRUCTORDECLARATION) {
198: // TODO: handle constructors
199: } else if (nodeType == JavaParserTreeConstants.JJTFIELDDECLARATION) {
200: String text = node.getText();
201: String declaration = text;
202: int equals = text.indexOf("=");
203: if (equals != -1)
204: declaration = declaration.substring(0, equals);
205: declaration = declaration.trim();
206: String[] declarationTokens = declaration.split("\\s");
207: boolean isFinal = Arrays.asList(declarationTokens)
208: .contains("final");
209: boolean isStatic = Arrays.asList(declarationTokens)
210: .contains("static");
211: String name = declarationTokens[declarationTokens.length - 1];
212: if (name.endsWith(";"))
213: name = name.substring(0, name.length() - 1).trim();
214: String className = declarationTokens[declarationTokens.length - 2];
215: String type = TagManager.resolveClassName(className,
216: compiler);
217: fields.add(new FieldDescriptor(name, Modifier.PUBLIC, type,
218: compiler.getClassLoader())); // TODO: determine the actual modifiers
219: } else {
220: for (int i = 0; i < node.jjtGetNumChildren(); i++) {
221: SimpleNode child = node.getChild(i);
222: scanClassNode(child);
223: }
224: }
225: }
226: }
|