Initial support for factory methods
This commit is contained in:
@@ -45,6 +45,7 @@ public class DependencyInjectorGenerator {
|
|||||||
private final boolean lazy;
|
private final boolean lazy;
|
||||||
private final Set<Field> fields = Sets.newLinkedHashSet();
|
private final Set<Field> fields = Sets.newLinkedHashSet();
|
||||||
private final Set<Parameter> parameters = Sets.newLinkedHashSet();
|
private final Set<Parameter> parameters = Sets.newLinkedHashSet();
|
||||||
|
private final Set<FactoryMethod> factoryMethods = Sets.newLinkedHashSet();
|
||||||
|
|
||||||
private final Dependencies dependencies = new Dependencies();
|
private final Dependencies dependencies = new Dependencies();
|
||||||
|
|
||||||
@@ -109,6 +110,10 @@ public class DependencyInjectorGenerator {
|
|||||||
generateDestroy(injectorClassName, out);
|
generateDestroy(injectorClassName, out);
|
||||||
out.println();
|
out.println();
|
||||||
generateGetters(out);
|
generateGetters(out);
|
||||||
|
if (!factoryMethods.isEmpty()) {
|
||||||
|
out.println();
|
||||||
|
generateFactoryMethods(out);
|
||||||
|
}
|
||||||
// Needed to fix double-checked locking
|
// Needed to fix double-checked locking
|
||||||
// out.println();
|
// out.println();
|
||||||
// generateMakeFunction(out);
|
// generateMakeFunction(out);
|
||||||
@@ -221,6 +226,26 @@ public class DependencyInjectorGenerator {
|
|||||||
return field;
|
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) {
|
private void generateImports(PrintStream out, String injectorPackageName) {
|
||||||
for (Field field : fields) {
|
for (Field field : fields) {
|
||||||
generateImportDirectives(out, field.getType(), injectorPackageName);
|
generateImportDirectives(out, field.getType(), injectorPackageName);
|
||||||
@@ -313,48 +338,13 @@ public class DependencyInjectorGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
generateInitializingCode(p, fields);
|
InjectionLogicGenerator.FIELDS.generate(p, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
p.popIndent();
|
p.popIndent();
|
||||||
p.println("}");
|
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) {
|
private static List<Method> getPostConstructMethods(Class<?> clazz) {
|
||||||
return getInjectSpecialMethods(clazz, PostConstruct.class);
|
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 static class Dependencies {
|
||||||
|
|
||||||
private final Set<Field> allFields = Sets.newLinkedHashSet();
|
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) {
|
private static String var(@NotNull DiType type) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(StringUtil.decapitalize(type.getClazz().getSimpleName().replaceFirst("(?<=.)Impl$", "")));
|
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