Singletons supported in Injector Generator
This commit is contained in:
@@ -128,36 +128,37 @@ public class Dependencies {
|
|||||||
|
|
||||||
Class<?> clazz = type.getClazz();
|
Class<?> clazz = type.getClazz();
|
||||||
if (clazz.isInterface()) {
|
if (clazz.isInterface()) {
|
||||||
|
if (initializeAsSingleton(field, type)) return;
|
||||||
throw new IllegalArgumentException("cannot instantiate interface: " + clazz.getName() + " needed for " + neededFor);
|
throw new IllegalArgumentException("cannot instantiate interface: " + clazz.getName() + " needed for " + neededFor);
|
||||||
}
|
}
|
||||||
if (Modifier.isAbstract(clazz.getModifiers())) {
|
if (Modifier.isAbstract(clazz.getModifiers())) {
|
||||||
|
if (initializeAsSingleton(field, type)) return;
|
||||||
throw new IllegalArgumentException("cannot instantiate abstract class: " + clazz.getName() + " needed for " + neededFor);
|
throw new IllegalArgumentException("cannot instantiate abstract class: " + clazz.getName() + " needed for " + neededFor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: projections are not computed here
|
// Note: projections are not computed here
|
||||||
|
|
||||||
if (isKotlinSingletonObject(clazz)) {
|
// Look for constructor
|
||||||
field.setInitialization(new ObjectInstanceFieldAccess(clazz));
|
List<Constructor<?>> publicConstructors = findPublicConstructors(clazz.getConstructors());
|
||||||
return;
|
if (publicConstructors.size() != 1) {
|
||||||
|
if (initializeAsSingleton(field, type)) return;
|
||||||
|
if (publicConstructors.size() == 0) {
|
||||||
|
throw new IllegalArgumentException("No public constructor: " + clazz.getName() + " needed for " + neededFor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("Too many public constructors in " + clazz.getName() + " needed for " + neededFor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for constructor
|
Constructor<?> publicConstructor = publicConstructors.get(0);
|
||||||
Constructor<?>[] constructors = clazz.getConstructors();
|
|
||||||
if (constructors.length == 0 || !Modifier.isPublic(constructors[0].getModifiers())) {
|
|
||||||
throw new IllegalArgumentException("No constructor: " + clazz.getName() + " needed for " + neededFor);
|
|
||||||
}
|
|
||||||
if (constructors.length > 1) {
|
|
||||||
throw new IllegalArgumentException("Too many constructors in " + clazz.getName() + " needed for " + neededFor);
|
|
||||||
}
|
|
||||||
Constructor<?> constructor = constructors[0];
|
|
||||||
|
|
||||||
// Find arguments
|
// Find arguments
|
||||||
ConstructorCall dependency = new ConstructorCall(constructor);
|
ConstructorCall dependency = new ConstructorCall(publicConstructor);
|
||||||
Type[] parameterTypes = constructor.getGenericParameterTypes();
|
Type[] parameterTypes = publicConstructor.getGenericParameterTypes();
|
||||||
for (Type parameterType : parameterTypes) {
|
for (Type parameterType : parameterTypes) {
|
||||||
Field fieldForParameter = findDependencyOfType(
|
Field fieldForParameter = findDependencyOfType(
|
||||||
DiType.fromReflectionType(parameterType),
|
DiType.fromReflectionType(parameterType),
|
||||||
"constructor: " + constructor + ", parameter: " + parameterType,
|
"constructor: " + publicConstructor + ", parameter: " + parameterType,
|
||||||
neededFor.prepend(field)
|
neededFor.prepend(field)
|
||||||
);
|
);
|
||||||
used.add(fieldForParameter);
|
used.add(fieldForParameter);
|
||||||
@@ -167,14 +168,48 @@ public class Dependencies {
|
|||||||
field.setInitialization(dependency);
|
field.setInitialization(dependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isKotlinSingletonObject(Class<?> clazz) {
|
@NotNull
|
||||||
|
private static List<Constructor<?>> findPublicConstructors(Constructor<?>[] constructors) {
|
||||||
|
List<Constructor<?>> result = new ArrayList<Constructor<?>>();
|
||||||
|
for (Constructor<?> constructor : constructors) {
|
||||||
|
if (Modifier.isPublic(constructor.getModifiers())) {
|
||||||
|
result.add(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean initializeAsSingleton(Field field, DiType type) {
|
||||||
|
Class<?> clazz = type.getClazz();
|
||||||
|
|
||||||
|
return initializeBySingletonMethod(field, clazz, "getInstance")
|
||||||
|
|| initializeBySingletonField(field, clazz, "INSTANCE")
|
||||||
|
|| initializeBySingletonField(field, clazz, "INSTANCE$");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean initializeBySingletonMethod(Field field, Class<?> clazz, String name) {
|
||||||
try {
|
try {
|
||||||
clazz.getDeclaredField("INSTANCE$");
|
clazz.getMethod(name);
|
||||||
|
field.setInitialization(GetSingleton.byMethod(clazz, name));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean initializeBySingletonField(Field field, Class<?> clazz, String name) {
|
||||||
|
try {
|
||||||
|
clazz.getField(name);
|
||||||
|
field.setInitialization(GetSingleton.byField(clazz, name));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (NoSuchFieldException e) {
|
catch (NoSuchFieldException e) {
|
||||||
return false;
|
// Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Field> satisfyDependencies() {
|
public Collection<Field> satisfyDependencies() {
|
||||||
|
|||||||
+26
-14
@@ -17,38 +17,50 @@
|
|||||||
package org.jetbrains.jet.di;
|
package org.jetbrains.jet.di;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
public class ObjectInstanceFieldAccess implements Expression {
|
public class GetSingleton implements Expression {
|
||||||
private final Class<?> clazz;
|
|
||||||
|
|
||||||
public ObjectInstanceFieldAccess(@NotNull Class<?> clazz) {
|
public static GetSingleton byMethod(@NotNull Class<?> singletonClass, @NotNull String methodName) {
|
||||||
this.clazz = clazz;
|
return new GetSingleton(singletonClass, methodName, "()");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GetSingleton byField(@NotNull Class<?> singletonClass, @NotNull String fieldName) {
|
||||||
|
return new GetSingleton(singletonClass, fieldName, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Class<?> singletonClass;
|
||||||
|
private final String memberName;
|
||||||
|
private final String callSuffix;
|
||||||
|
|
||||||
|
private GetSingleton(@NotNull Class<?> singletonClass, @NotNull String name, String callSuffix) {
|
||||||
|
this.singletonClass = singletonClass;
|
||||||
|
this.memberName = name;
|
||||||
|
this.callSuffix = callSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return renderAsCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public String renderAsCode() {
|
public String renderAsCode() {
|
||||||
return clazz.getSimpleName() + ".INSTANCE$";
|
return singletonClass.getSimpleName() + "." + memberName + callSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Collection<DiType> getTypesToImport() {
|
public Collection<DiType> getTypesToImport() {
|
||||||
return Collections.singleton(new DiType(clazz));
|
return Collections.singletonList(new DiType(singletonClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public DiType getType() {
|
public DiType getType() {
|
||||||
return new DiType(clazz);
|
return new DiType(singletonClass);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return clazz.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user