/* * Copyright 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.gwt.inject.rebind.binding; import com.google.gwt.inject.rebind.ErrorManager; import com.google.gwt.inject.rebind.reflect.MethodLiteral; import com.google.gwt.inject.rebind.reflect.NoSourceNameException; import com.google.gwt.inject.rebind.reflect.ReflectUtil; import com.google.gwt.inject.rebind.util.GuiceUtil; import com.google.gwt.inject.rebind.util.InjectorMethod; import com.google.gwt.inject.rebind.util.MethodCallUtil; import com.google.gwt.inject.rebind.util.NameGenerator; import com.google.gwt.inject.rebind.util.SourceSnippet; import com.google.gwt.inject.rebind.util.SourceSnippetBuilder; import com.google.inject.Key; import com.google.inject.TypeLiteral; import com.google.inject.internal.ProviderMethod; import java.lang.reflect.Method; import java.util.Collection; import java.util.List; /** * A binding that calls a provider method. This binding depends on * the {@code GinModule}'s key, meaning that it will cause the module * itself to be instantiated at runtime so it can call the provider * method. */ public class ProviderMethodBinding extends AbstractBinding implements Binding { private final GuiceUtil guiceUtil; private MethodLiteral<?, Method> providerMethod; private final MethodCallUtil methodCallUtil; private final Class<?> moduleType; private final Key<?> targetKey; ProviderMethodBinding(ErrorManager errorManager, GuiceUtil guiceUtil, MethodCallUtil methodCallUtil, ProviderMethod<?> providerMethod, Context context) { super(context, TypeLiteral.get(providerMethod.getMethod().getDeclaringClass())); this.guiceUtil = guiceUtil; this.methodCallUtil = methodCallUtil; this.moduleType = providerMethod.getInstance().getClass(); Method method = providerMethod.getMethod(); this.providerMethod = MethodLiteral.get(method, TypeLiteral.get(method.getDeclaringClass())); this.targetKey = providerMethod.getKey(); if (!ReflectUtil.hasAccessibleDefaultConstructor(method.getDeclaringClass())) { errorManager.logError( "Cannot invoke a @Provides method on a module without a default constructor. " + "Gin must be able to create the module at runtime in order to invoke an instance " + "method. Method name: %s", method); } } // TODO(schmitt): This implementation creates a new module instance for // every provider method invocation. Instead we should likely create just a // single instance of the module, invoke it repeatedly and share it between // provider methods. public SourceSnippet getCreationStatements(NameGenerator nameGenerator, List<InjectorMethod> methodsOutput) throws NoSourceNameException { String moduleSourceName = ReflectUtil.getSourceName(moduleType); String createModule = "new " + moduleSourceName + "()"; String type = ReflectUtil.getSourceName(targetKey.getTypeLiteral()); return new SourceSnippetBuilder() .append(type).append(" result = ") .append(methodCallUtil.createMethodCallWithInjection(providerMethod, createModule, nameGenerator, methodsOutput)) .build(); } public Collection<Dependency> getDependencies() { Collection<Dependency> dependencies = guiceUtil.getDependencies(targetKey, providerMethod); dependencies.add(new Dependency(Dependency.GINJECTOR, targetKey, getContext())); return dependencies; } }