blob: 9d98ad53abd1ed1551801d60486f88729eb81795 [file] [log] [blame]
package com.google.autofactory;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import javax.annotation.Generated;
import javax.annotation.processing.Filer;
import javax.inject.Inject;
import javax.lang.model.element.Element;
import javax.tools.JavaFileObject;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.squareup.java.JavaWriter;
final class FactoryWriter {
private final Filer filer;
@Inject FactoryWriter(Filer filer) {
this.filer = filer;
}
private static final Joiner argumentJoiner = Joiner.on(", ");
void writeFactory(final FactoryDescriptor descriptor, Element originatingElement)
throws IOException {
JavaFileObject sourceFile = filer.createSourceFile(descriptor.name(), originatingElement);
JavaWriter writer = new JavaWriter(sourceFile.openWriter());
writer.emitPackage(Names.getPackage(descriptor.name()).toString())
.emitImports("javax.annotation.Generated");
writer.emitImports("javax.inject.Inject");
if (!descriptor.providerNames().isEmpty()) {
writer.emitImports("javax.inject.Provider");
}
// for (String implementingClass : descriptor.implementing()) {
// String packageName = getPackage(implementingClass);
// if (!"java.lang".equals(packageName) && !descriptor.packageName().equals(packageName)) {
// writer.emitImports(implementingClass);
// }
// }
// String[] implementedClasses = FluentIterable.from(descriptor.implementing())
// .transform(new Function<String, String>() {
// @Override public String apply(String implemetingClass) {
// return getType(implemetingClass);
// }
// })
// .toSortedSet(Ordering.natural())
// .toArray(new String[] {});
String factoryName = Names.getSimpleName(descriptor.name()).toString();
writer.emitAnnotation(Generated.class, ImmutableMap.of("value", "\"auto-factory\""))
.beginType(factoryName, "class", Modifier.FINAL, null);
ImmutableList.Builder<String> constructorTokens = ImmutableList.builder();
for (Entry<Key, String> entry : descriptor.providerNames().entrySet()) {
Key key = entry.getKey();
String providerName = entry.getValue();
writer.emitField("Provider<" + key.getType() + ">", providerName,
Modifier.PRIVATE | Modifier.FINAL);
Optional<String> qualifier = key.getQualifier();
String qualifierPrefix = qualifier.isPresent() ? "@" + qualifier.get() + " " : "";
constructorTokens.add(qualifierPrefix + "Provider<" + key.getType() + ">").add(providerName);
}
writer.emitAnnotation("Inject");
writer.beginMethod(null, factoryName, 0, constructorTokens.build().toArray(new String[0]));
for (String providerName : descriptor.providerNames().values()) {
writer.emitStatement("this.%1$s = %1$s", providerName);
}
writer.endMethod();
for (final FactoryMethodDescriptor methodDescriptor : descriptor.methodDescriptors()) {
writer.beginMethod(methodDescriptor.returnType(), methodDescriptor.name(), 0,
parameterTokens(methodDescriptor.passedParameters()));
FluentIterable<String> creationParameterNames =
FluentIterable.from(methodDescriptor.creationParameters())
.transform(new Function<Parameter, String>() {
@Override public String apply(Parameter parameter) {
return methodDescriptor.passedParameters().contains(parameter)
? parameter.name()
: descriptor.providerNames().get(parameter.asKey()) + ".get()";
}
});
writer.emitStatement("return new %s(%s)", methodDescriptor.returnType(),
argumentJoiner.join(creationParameterNames));
writer.endMethod();
}
writer.endType();
writer.close();
}
private static String[] parameterTokens(Collection<Parameter> parameters) {
List<String> parameterTokens =
Lists.newArrayListWithCapacity(parameters.size());
for (Parameter parameter : parameters) {
parameterTokens.add(parameter.type());
parameterTokens.add(parameter.name());
}
return parameterTokens.toArray(new String[0]);
}
}