Initial support for factory methods
This commit is contained in:
@@ -45,6 +45,7 @@ public class DependencyInjectorGenerator {
|
||||
private final boolean lazy;
|
||||
private final Set<Field> fields = Sets.newLinkedHashSet();
|
||||
private final Set<Parameter> parameters = Sets.newLinkedHashSet();
|
||||
private final Set<FactoryMethod> factoryMethods = Sets.newLinkedHashSet();
|
||||
|
||||
private final Dependencies dependencies = new Dependencies();
|
||||
|
||||
@@ -109,6 +110,10 @@ public class DependencyInjectorGenerator {
|
||||
generateDestroy(injectorClassName, out);
|
||||
out.println();
|
||||
generateGetters(out);
|
||||
if (!factoryMethods.isEmpty()) {
|
||||
out.println();
|
||||
generateFactoryMethods(out);
|
||||
}
|
||||
// Needed to fix double-checked locking
|
||||
// out.println();
|
||||
// generateMakeFunction(out);
|
||||
@@ -221,6 +226,26 @@ public class DependencyInjectorGenerator {
|
||||
return field;
|
||||
}
|
||||
|
||||
public void addFactoryMethod(@NotNull Class<?> returnType, Class<?>... parameterTypes) {
|
||||
List<DiType> types = Lists.newArrayList();
|
||||
for (Class<?> type : parameterTypes) {
|
||||
types.add(new DiType(type));
|
||||
}
|
||||
addFactoryMethod(new DiType(returnType), types);
|
||||
}
|
||||
|
||||
public void addFactoryMethod(@NotNull DiType returnType, DiType... parameterTypes) {
|
||||
addFactoryMethod(returnType, Arrays.asList(parameterTypes));
|
||||
}
|
||||
|
||||
public void addFactoryMethod(@NotNull DiType returnType, @NotNull Collection<DiType> parameterTypes) {
|
||||
List<Parameter> parameters = Lists.newArrayList();
|
||||
for (DiType type : parameterTypes) {
|
||||
parameters.add(new Parameter(type, var(type), null, false));
|
||||
}
|
||||
factoryMethods.add(new FactoryMethod("create" + returnType.getSimpleName(), returnType, parameters));
|
||||
}
|
||||
|
||||
private void generateImports(PrintStream out, String injectorPackageName) {
|
||||
for (Field field : fields) {
|
||||
generateImportDirectives(out, field.getType(), injectorPackageName);
|
||||
@@ -313,48 +338,13 @@ public class DependencyInjectorGenerator {
|
||||
}
|
||||
}
|
||||
else {
|
||||
generateInitializingCode(p, fields);
|
||||
InjectionLogicGenerator.FIELDS.generate(p, fields);
|
||||
}
|
||||
|
||||
p.popIndent();
|
||||
p.println("}");
|
||||
}
|
||||
|
||||
private static void generateInitializingCode(@NotNull Printer p, @NotNull Collection<Field> fields) {
|
||||
// Initialize fields
|
||||
for (Field field : fields) {
|
||||
//if (!backsParameter.contains(field) || field.isPublic()) {
|
||||
p.println("this.", field.getName(), " = ", field.getInitialization().renderAsCode(), ";");
|
||||
//}
|
||||
}
|
||||
p.printlnWithNoIndent();
|
||||
|
||||
// Call setters
|
||||
for (Field field : fields) {
|
||||
for (SetterDependency dependency : field.getDependencies()) {
|
||||
String prefix = field.isPublic() ? "this." : "";
|
||||
String dependencyName = dependency.getDependency().getName();
|
||||
String dependentName = dependency.getDependent().getName();
|
||||
p.println(prefix, dependentName, ".", dependency.getSetterName(), "(", dependencyName, ");");
|
||||
}
|
||||
if (!field.getDependencies().isEmpty()) {
|
||||
p.printlnWithNoIndent();
|
||||
}
|
||||
}
|
||||
|
||||
// call @PostConstruct
|
||||
for (Field field : fields) {
|
||||
// TODO: type of field may be different from type of object
|
||||
List<Method> postConstructMethods = getPostConstructMethods(getEffectiveFieldType(field).getClazz());
|
||||
for (Method postConstruct : postConstructMethods) {
|
||||
p.println(field.getName(), ".", postConstruct.getName(), "();");
|
||||
}
|
||||
if (postConstructMethods.size() > 0) {
|
||||
p.printlnWithNoIndent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Method> getPostConstructMethods(Class<?> clazz) {
|
||||
return getInjectSpecialMethods(clazz, PostConstruct.class);
|
||||
}
|
||||
@@ -442,6 +432,60 @@ public class DependencyInjectorGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFactoryMethods(PrintStream out) {
|
||||
Printer p = new Printer(out);
|
||||
p.pushIndent();
|
||||
for (FactoryMethod method : factoryMethods) {
|
||||
generateFactoryMethod(p, method);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFactoryMethod(Printer p, FactoryMethod method) {
|
||||
Dependencies localDependencies = new Dependencies();
|
||||
|
||||
Map<Parameter, Field> parameterToField = Maps.newHashMap();
|
||||
for (Parameter parameter : method.getParameters()) {
|
||||
Field field = new Field(true, parameter.getType(), parameter.getName());
|
||||
localDependencies.addSatisfiedField(field);
|
||||
parameterToField.put(parameter, field);
|
||||
}
|
||||
|
||||
for (Field storedField : fields) {
|
||||
localDependencies.addSatisfiedField(storedField);
|
||||
}
|
||||
|
||||
Field resultField = new Field(true, method.getReturnType(), "_result");
|
||||
localDependencies.addField(resultField);
|
||||
|
||||
Collection<Field> fields = Lists.newArrayList(localDependencies.satisfyDependencies());
|
||||
fields.add(resultField);
|
||||
|
||||
p.println("public ", type(method.getReturnType()), " ", method.getName(), "(");
|
||||
p.pushIndent();
|
||||
for (Iterator<Parameter> iterator = method.getParameters().iterator(); iterator.hasNext(); ) {
|
||||
Parameter parameter = iterator.next();
|
||||
p.print(type(parameter.getType()), " ", parameter.getName());
|
||||
if (iterator.hasNext()) {
|
||||
p.printlnWithNoIndent(", ");
|
||||
}
|
||||
}
|
||||
p.println();
|
||||
p.popIndent();
|
||||
p.println(") {");
|
||||
p.pushIndent();
|
||||
|
||||
InjectionLogicGenerator.LOCAL_VARIABLES.generate(p, fields);
|
||||
|
||||
p.println("return ", resultField.getName(), ";");
|
||||
|
||||
p.popIndent();
|
||||
p.println("}");
|
||||
}
|
||||
|
||||
private String type(DiType type) {
|
||||
return type.getSimpleName();
|
||||
}
|
||||
|
||||
private static class Dependencies {
|
||||
|
||||
private final Set<Field> allFields = Sets.newLinkedHashSet();
|
||||
@@ -571,6 +615,84 @@ public class DependencyInjectorGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class InjectionLogicGenerator {
|
||||
|
||||
public static final InjectionLogicGenerator FIELDS = new InjectionLogicGenerator() {
|
||||
@Override
|
||||
public String prefixForPostConstructorCall(Field field) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prefixForSetterCall(Field field) {
|
||||
return field.isPublic() ? "this." : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prefixForInitialization(Field field) {
|
||||
return "this.";
|
||||
}
|
||||
};
|
||||
|
||||
public static final InjectionLogicGenerator LOCAL_VARIABLES = new InjectionLogicGenerator() {
|
||||
@Override
|
||||
public String prefixForPostConstructorCall(Field field) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prefixForSetterCall(Field field) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prefixForInitialization(Field field) {
|
||||
return field.getType() + " ";
|
||||
}
|
||||
};
|
||||
|
||||
public final void generate(@NotNull Printer p, @NotNull Collection<Field> fields) {
|
||||
// Initialize fields
|
||||
for (Field field : fields) {
|
||||
//if (!backsParameter.contains(field) || field.isPublic()) {
|
||||
p.println(prefixForInitialization(field), field.getName(), " = ", field.getInitialization().renderAsCode(), ";");
|
||||
//}
|
||||
}
|
||||
p.printlnWithNoIndent();
|
||||
|
||||
// Call setters
|
||||
for (Field field : fields) {
|
||||
for (SetterDependency dependency : field.getDependencies()) {
|
||||
String prefix = prefixForSetterCall(field);
|
||||
String dependencyName = dependency.getDependency().getName();
|
||||
String dependentName = dependency.getDependent().getName();
|
||||
p.println(prefix, dependentName, ".", dependency.getSetterName(), "(", dependencyName, ");");
|
||||
}
|
||||
if (!field.getDependencies().isEmpty()) {
|
||||
p.printlnWithNoIndent();
|
||||
}
|
||||
}
|
||||
|
||||
// call @PostConstruct
|
||||
for (Field field : fields) {
|
||||
// TODO: type of field may be different from type of object
|
||||
List<Method> postConstructMethods = getPostConstructMethods(getEffectiveFieldType(field).getClazz());
|
||||
for (Method postConstruct : postConstructMethods) {
|
||||
p.println(prefixForPostConstructorCall(field), field.getName(), ".", postConstruct.getName(), "();");
|
||||
}
|
||||
if (postConstructMethods.size() > 0) {
|
||||
p.printlnWithNoIndent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract String prefixForInitialization(Field field);
|
||||
|
||||
protected abstract String prefixForSetterCall(Field field);
|
||||
|
||||
protected abstract String prefixForPostConstructorCall(Field field);
|
||||
}
|
||||
|
||||
private static String var(@NotNull DiType type) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(StringUtil.decapitalize(type.getClazz().getSimpleName().replaceFirst("(?<=.)Impl$", "")));
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.jet.di;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FactoryMethod {
|
||||
private final String name;
|
||||
private final List<Parameter> parameters;
|
||||
private final DiType returnType;
|
||||
|
||||
public FactoryMethod(@NotNull String name, @NotNull DiType returnType, @NotNull List<Parameter> parameters) {
|
||||
this.name = name;
|
||||
this.parameters = parameters;
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Parameter> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DiType getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user