Tweaking the code generator to do imports and qualified names properly.
git-svn-id: https://google-guice.googlecode.com/svn/trunk@436 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/extensions/compiletime/compiletime.iml b/extensions/compiletime/compiletime.iml
index 0a650bf..64bbec6 100644
--- a/extensions/compiletime/compiletime.iml
+++ b/extensions/compiletime/compiletime.iml
@@ -7,7 +7,7 @@
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content>
<content url="file://$MODULE_DIR$/../../generatedsrc">
- <sourceFolder url="file://$MODULE_DIR$/../../generatedsrc" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/../../generatedsrc" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
diff --git a/extensions/compiletime/src/com/google/inject/CodeGenReflectionFactory.java b/extensions/compiletime/src/com/google/inject/CodeGenReflectionFactory.java
index c4f9676..9308407 100644
--- a/extensions/compiletime/src/com/google/inject/CodeGenReflectionFactory.java
+++ b/extensions/compiletime/src/com/google/inject/CodeGenReflectionFactory.java
@@ -20,10 +20,10 @@
import com.google.inject.internal.*;
import static com.google.inject.internal.Objects.nonNull;
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
-import java.lang.reflect.Type;
import java.util.*;
/**
@@ -92,15 +92,10 @@
* Writes generated .java files to {@code generatedSourceDirectory}.
*/
void writeToFile(File generatedSourceDirectory) throws IOException {
- File directory = generatedSourceDirectory;
- for (String packagePart : new String[] { "com", "google", "inject" }) {
- directory = new File(directory, packagePart);
- }
- directory.mkdirs();
- File sourceFile = new File(directory, generatedClassSimpleName() + ".java");
- Writer writer = new OutputStreamWriter(new FileOutputStream(sourceFile), "ISO-8859-1");
- new ClassWriter(writer).writeClass();
- writer.close();
+ JavaCodeGenerator out = JavaCodeGenerator.open(generatedSourceDirectory,
+ generatedCodePackage, generatedClassSimpleName());
+ new ClassWriter(out).writeClass();
+ out.close();
}
private String generatedClassSimpleName() {
@@ -108,32 +103,40 @@
}
private class ClassWriter {
- final Writer writer;
+ final JavaCodeGenerator out;
- ClassWriter(Writer writer) {
- this.writer = writer;
+ ClassWriter(JavaCodeGenerator out) {
+ this.out = out;
}
void writeClass() throws IOException {
- writeLine("// Generated by Guice. Do not edit!");
- writeLine("package %s;", generatedCodePackage);
- writeLine();
- writeLine("import %s;", typeName(Reflection.class));
- writeLine("import %s;", typeName(ConstructionProxy.class));
- writeLine("import %s;", typeName(InvocationTargetException.class));
- writeLine("import %s;", typeName(Parameter.class));
- writeLine("import %s;", typeName(List.class));
- writeLine("import %s;", typeName(Member.class));
- writeLine("import %s;", typeName(Parameter.class));
- writeLine("import %s;", typeName(Nullability.class));
- writeLine("import %s;", typeName(Arrays.class));
- writeLine("import %s;", typeName(Key.class));
- writeLine();
- writeLine("public class %s implements Reflection {", generatedClassSimpleName());
- writeLine();
+ out.writePackageHeader();
+ out.writeImport(Reflection.class);
+ out.writeImport(ConstructionProxy.class);
+ out.writeImport(InvocationTargetException.class);
+ out.writeImport(Parameter.class);
+ out.writeImport(List.class);
+ out.writeImport(Member.class);
+ out.writeImport(Parameter.class);
+ out.writeImport(Nullability.class);
+ out.writeImport(Arrays.class);
+ out.writeImport(SuppressWarnings.class);
+ out.writeImport(Key.class);
+ out.writeImport(IllegalArgumentException.class);
+ out.writeImport(Object.class);
+ for (Map.Entry<Class<?>, ConstructionProxy<?>> entry : constructionProxies.entrySet()) {
+ out.writeImport(entry.getKey());
+ for (Parameter<?> parameter : entry.getValue().getParameters()) {
+ out.writeImport(parameter.getKey().getTypeLiteral().getType());
+ }
+ }
+
+ out.writeLine();
+ out.openScope("public class %s implements Reflection {", generatedClassSimpleName());
+ out.writeLine();
writeGetConstructionProxy();
- writeLine();
- writeLine("}");
+ out.writeLine();
+ out.closeScope("}");
}
String keyLiteral(Key<?> key) {
@@ -143,72 +146,49 @@
if (key.getAnnotationType() != null) {
throw new UnsupportedOperationException("TODO");
}
- return String.format("Key.get(%s.class)", typeName(key.getTypeLiteral().getType()));
+ return String.format("Key.get(%s.class)", out.typeName(key.getTypeLiteral().getType()));
}
- String typeName(Type type) {
- if (type instanceof Class<?>) {
- Class<?> clas = (Class<?>) type;
- StringBuilder result = new StringBuilder();
- result.append(clas.getPackage().getName());
- for (Class<?> enclosing = clas.getEnclosingClass(); enclosing != null;
- enclosing = enclosing.getEnclosingClass()) {
- result.append(".").append(enclosing.getSimpleName());
- }
- result.append(".").append(clas.getSimpleName());
- return result.toString();
-
- } else {
- throw new UnsupportedOperationException();
- }
- }
void writeGetConstructionProxy() throws IOException {
- writeLine(" public <T> ConstructionProxy<T> getConstructionProxy(Class<T> implementation) {");
+ out.writeLine("@%s(\"unchecked\")", SuppressWarnings.class);
+ out.openScope("public <T> ConstructionProxy<T> getConstructionProxy(Class<T> implementation) {");
for (Map.Entry<Class<?>, ConstructionProxy<?>> entry : constructionProxies.entrySet()) {
- String implementation = typeName(entry.getKey());
- writeLine(" if (implementation == %s.class) {", implementation);
- writeLine(" return (ConstructionProxy) new ConstructionProxy<%s>() {", implementation);
- writeLine(" public %s newInstance(final Object... arguments) throws InvocationTargetException {", implementation);
- writeLine(" return new %s(", implementation);
+ Class<?> implementation = entry.getKey();
+ out.openScope("if (implementation == %s.class) {", implementation);
+ out.openScope("return (%s) new %s<%s>() {", ConstructionProxy.class, ConstructionProxy.class, implementation);
+ out.openScope("public %s newInstance(final %s... arguments) throws %s {", implementation, Object.class, InvocationTargetException.class);
+ out.openScope("return new %s(", implementation);
int argument = 0;
for (Iterator<Parameter<?>> i = entry.getValue().getParameters().iterator(); i.hasNext(); ) {
Parameter<?> parameter = i.next();
String separator = i.hasNext() ? "," : "";
- writeLine(" (%s) arguments[%d]%s", typeName(parameter.getKey().getTypeLiteral().getType()), argument, separator);
+ out.writeLine("(%s) arguments[%d]%s", parameter.getKey().getTypeLiteral().getType(), argument, separator);
argument++;
}
- writeLine(" );");
- writeLine(" }");
- writeLine(" public List<Parameter<?>> getParameters() {");
- writeLine(" return Arrays.<Parameter<?>>asList(");
+ out.closeScope(");");
+ out.closeScope("}");
+ out.openScope("public %s<%s<?>> getParameters() {", List.class, Parameter.class);
+ out.openScope("return %s.<%s<?>>asList(", Arrays.class, Parameter.class);
+ argument = 0;
for (Iterator<Parameter<?>> i = entry.getValue().getParameters().iterator(); i.hasNext(); ) {
Parameter<?> parameter = i.next();
String separator = i.hasNext() ? "," : "";
- writeLine(" Parameter.create(%s, %s, Nullability.%s)%s", argument, keyLiteral(parameter.getKey()), parameter.getNullability(), separator);
+ out.writeLine("%s.create(%s, %s, %s.%s)%s", Parameter.class, argument, keyLiteral(parameter.getKey()), Nullability.class, parameter.getNullability(), separator);
argument++;
}
- writeLine(" );");
- writeLine(" }");
- writeLine(" public Member getMember() {");
- writeLine(" return null;");
- writeLine(" }");
- writeLine(" };");
- writeLine(" }");
+ out.closeScope(");");
+ out.closeScope("}");
+ out.openScope("public %s getMember() {", Member.class);
+ out.writeLine("return null;");
+ out.closeScope("}");
+ out.closeScope("};");
+ out.closeScope("}");
}
- writeLine();
- writeLine(" throw new IllegalArgumentException();");
- writeLine(" }");
- }
-
- void writeLine(String format, Object... args) throws IOException {
- writer.append(String.format(format, args));
- writeLine();
- }
-
- void writeLine() throws IOException {
- writer.append("\n");
+ out.writeLine();
+ out.writeLine("throw new %s();", IllegalArgumentException.class);
+ out.closeScope("}");
}
}
}
diff --git a/extensions/compiletime/src/com/google/inject/JavaCodeGenerator.java b/extensions/compiletime/src/com/google/inject/JavaCodeGenerator.java
new file mode 100644
index 0000000..cd2ed09
--- /dev/null
+++ b/extensions/compiletime/src/com/google/inject/JavaCodeGenerator.java
@@ -0,0 +1,136 @@
+/**
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.google.inject;
+
+import java.io.*;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author jessewilson@google.com (Jesse Wilson)
+ */
+public class JavaCodeGenerator {
+
+ private final Writer writer;
+ private final String packageName;
+ private int indent = 0;
+
+ /**
+ * Imported classes, by their simple name. If multiple classes with the same
+ * simplename have been imported, the fully qualified names will be used for
+ * all but one of those classes.
+ */
+ private final Map<String, Class<?>> importedClasses = new HashMap<String, Class<?>>();
+
+ private JavaCodeGenerator(Writer writer, String packageName) {
+ this.writer = writer;
+ this.packageName = packageName;
+ }
+
+ public static JavaCodeGenerator open(File generatedSourceDirectory,
+ String packageName, String topLevelClassName) throws IOException {
+ File directory = generatedSourceDirectory;
+ for (String packagePart : packageName.split("\\.")) {
+ directory = new File(directory, packagePart);
+ }
+ directory.mkdirs();
+ File sourceFile = new File(directory, topLevelClassName + ".java");
+ return new JavaCodeGenerator(
+ new OutputStreamWriter(new FileOutputStream(sourceFile), "ISO-8859-1"), packageName);
+ }
+
+ public void writePackageHeader() throws IOException {
+ writeLine("// Generated by Guice. Do not edit!");
+ writeLine("package %s;", packageName);
+ writeLine();
+ }
+
+ public void writeImport(Type type) throws IOException {
+ if (!(type instanceof Class)) {
+ throw new UnsupportedOperationException();
+ }
+
+ Class<?> clas = (Class<?>) type;
+
+ if (importedClasses.containsKey(clas.getSimpleName())) {
+ return;
+ }
+
+ if (!"java.lang".equals(clas.getPackage().getName())) {
+ writeLine("import %s;", typeName(type));
+ }
+ importedClasses.put(clas.getSimpleName(), clas);
+ }
+
+ public String typeName(Type type) {
+ if (type instanceof Class<?>) {
+ Class<?> clas = (Class<?>) type;
+ if (importedClasses.get(clas.getSimpleName()) == type) {
+ return clas.getSimpleName();
+ }
+ StringBuilder result = new StringBuilder();
+ result.append(clas.getPackage().getName());
+ for (Class<?> enclosing = clas.getEnclosingClass(); enclosing != null;
+ enclosing = enclosing.getEnclosingClass()) {
+ result.append(".").append(enclosing.getSimpleName());
+ }
+ result.append(".").append(clas.getSimpleName());
+ return result.toString();
+
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private Object[] processArgs(Object... args) {
+ args = args.clone();
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] instanceof Class<?>) {
+ args[i] = typeName((Class<?>) args[i]);
+ }
+ }
+ return args;
+ }
+
+ public void writeLine(String format, Object... args) throws IOException {
+ for (int i = 0; i < indent; i++) {
+ writer.append(" ");
+ }
+ writer.append(String.format(format, processArgs(args)));
+ writeLine();
+ }
+
+ public void openScope(String format, Object... args) throws IOException {
+ writeLine(format, args);
+ indent++;
+ }
+
+ public void closeScope(String format, Object... args) throws IOException {
+ indent--;
+ writeLine(format, args);
+ }
+
+ public void writeLine() throws IOException {
+ writer.append("\n");
+ }
+
+ public void close() throws IOException {
+ writer.close();
+ }
+}