
com.google.gwt.inject.client.assistedinject.GinFactoryModuleBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gin Show documentation
Show all versions of gin Show documentation
GIN (GWT INjection) brings automatic dependency injection to Google Web Toolkit client-side code. GIN is built on top of Guice and uses (a subset of) Guice's binding language.
/*
* Copyright 2010 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.client.assistedinject;
import com.google.gwt.inject.client.GinModule;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import java.lang.annotation.Annotation;
/**
* Copied and modified from
* {@link com.google.inject.assistedinject.FactoryModuleBuilder}. Usage is
* mostly the same, with the exception of forwarded bindings (see at the
* bottom of this documentation).
*
* Provides a factory that combines the caller's arguments with
* injector-supplied values to construct objects.
*
* Defining a factory
* Create an interface whose methods return the constructed type, or any of its
* supertypes. The method's parameters are the arguments required to build the
* constructed type.
*
* public interface PaymentFactory {
* Payment create(Date startDate, Money amount);
* }
*
* You can name your factory methods whatever you like, such as create,
* createPayment or newPayment.
*
* Creating a type that accepts factory parameters
* {@code constructedType} is a concrete class with an
* {@literal @}{@link Inject}-annotated constructor. In addition to injector-
* supplied parameters, the constructor should have parameters that match each
* of the factory method's parameters. Each factory-supplied parameter requires
* an {@literal @}{@link Assisted} annotation. This serves to document that the
* parameter is not bound by your application's modules.
*
* public class RealPayment implements Payment {
* {@literal @}Inject
* public RealPayment(
* CreditService creditService,
* AuthService authService,
* {@literal @}Assisted Date startDate,
* {@literal @}Assisted Money amount) {
* ...
* }
* }
*
* Multiple factory methods for the same type
* If the factory contains many methods that return the same type, you can
* create multiple constructors in your concrete class, each constructor
* marked with with {@literal @}{@link AssistedInject}, in order to match the
* different parameters types of the factory methods.
*
* public interface PaymentFactory {
* Payment create(Date startDate, Money amount);
* Payment createWithoutDate(Money amount);
* }
*
* public class RealPayment implements Payment {
* {@literal @}AssistedInject
* public RealPayment(
* CreditService creditService,
* AuthService authService,
* {@literal @}Assisted Date startDate,
* {@literal @}Assisted Money amount) {
* ...
* }
*
* {@literal @}AssistedInject
* public RealPayment(
* CreditService creditService,
* AuthService authService,
* {@literal @}Assisted Money amount) {
* ...
* }
* }
*
* Configuring simple factories
* In your {@link Module module}, install a {@code GinFactoryModuleBuilder}
* that creates the factory:
*
* install(new GinFactoryModuleBuilder()
* .implement(Payment.class, RealPayment.class)
* .build(PaymentFactory.class);
*
* As a side-effect of this binding, Gin will inject the factory to initialize
* it for use. The factory cannot be used until the injector has been
* initialized.
*
* Using the factory
* Inject your factory into your application classes. When you use the factory,
* your arguments will be combined with values from the injector to construct
* an instance.
*
* public class PaymentAction {
* {@literal @}Inject private PaymentFactory paymentFactory;
*
* public void doPayment(Money amount) {
* Payment payment = paymentFactory.create(new Date(), amount);
* payment.apply();
* }
* }
*
* Making parameter types distinct
* The types of the factory method's parameters must be distinct. To use
* multiple parameters of the same type, use a named
* {@literal @}{@link Assisted} annotation to disambiguate the parameters. The
* names must be applied to the factory method's parameters:
*
* public interface PaymentFactory {
* Payment create(
* {@literal @}Assisted("startDate") Date startDate,
* {@literal @}Assisted("dueDate") Date dueDate,
* Money amount);
* }
*
* ...and to the concrete type's constructor parameters:
*
* public class RealPayment implements Payment {
* {@literal @}Inject
* public RealPayment(
* CreditService creditService,
* AuthService authService,
* {@literal @}Assisted("startDate") Date startDate,
* {@literal @}Assisted("dueDate") Date dueDate,
* {@literal @}Assisted Money amount) {
* ...
* }
* }
*
* Values are created by Gin
* Returned factories use child injectors to create values. The values are
* eligible for method interception. In addition, {@literal @}{@link Inject}
* members will be injected before they are returned.
*
* More configuration options
* In addition to simply specifying an implementation class for any returned
* type, factories' return values can be automatic or can be configured to use
* annotations:
*
* If you just want to return the types specified in the factory, do not
* configure any implementations:
*
* public interface FruitFactory {
* Apple getApple(Color color);
* }
* ...
* protected void configure() {
* install(new GinFactoryModuleBuilder().build(FruitFactory.class));
* }
*
* Note that any type returned by the factory in this manner needs to be an
* implementation class.
*
* To return two different implementations for the same interface from your
* factory, use binding annotations on your return types:
*
* interface CarFactory {
* {@literal @}Named("fast") Car getFastCar(Color color);
* {@literal @}Named("clean") Car getCleanCar(Color color);
* }
* ...
* protected void configure() {
* install(new GinFactoryModuleBuilder()
* .implement(Car.class, Names.named("fast"), Porsche.class)
* .implement(Car.class, Names.named("clean"), Prius.class)
* .build(CarFactory.class));
* }
*
*
* In difference to regular Guice Assisted Inject, in Gin,
* return types in your factory are not further resolved using
* your regular injector configuration. This means that in the following
* example you'll still get a {@code Chicken} and not a {@code Rooster}:
*
* interface Animal {}
* public class Chicken implements Animal {}
* public class Rooster extends Chicken {}
* interface AnimalFactory {
* Animal getAnimal();
* }
* ...
* protected void configure() {
* bind(Chicken.class).to(Rooster.class);
* install(new GinFactoryModuleBuilder()
* .implement(Animal.class, Chicken.class)
* .build(AnimalFactory.class));
* }
*
*/
public class GinFactoryModuleBuilder {
private final BindingCollector bindings = new BindingCollector();
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(Class source, Class extends T> target) {
return implement(source, TypeLiteral.get(target));
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(Class source, TypeLiteral extends T> target) {
return implement(TypeLiteral.get(source), target);
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(TypeLiteral source, Class extends T> target) {
return implement(source, TypeLiteral.get(target));
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(TypeLiteral source,
TypeLiteral extends T> target) {
return implement(Key.get(source), target);
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(Class source, Annotation annotation,
Class extends T> target) {
return implement(source, annotation, TypeLiteral.get(target));
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(Class source, Annotation annotation,
TypeLiteral extends T> target) {
return implement(TypeLiteral.get(source), annotation, target);
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(TypeLiteral source, Annotation annotation,
Class extends T> target) {
return implement(source, annotation, TypeLiteral.get(target));
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(TypeLiteral source, Annotation annotation,
TypeLiteral extends T> target) {
return implement(Key.get(source, annotation), target);
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(Class source,
Class extends Annotation> annotationType, Class extends T> target) {
return implement(source, annotationType, TypeLiteral.get(target));
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(Class source,
Class extends Annotation> annotationType, TypeLiteral extends T> target) {
return implement(TypeLiteral.get(source), annotationType, target);
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(TypeLiteral source,
Class extends Annotation> annotationType, Class extends T> target) {
return implement(source, annotationType, TypeLiteral.get(target));
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(TypeLiteral source,
Class extends Annotation> annotationType, TypeLiteral extends T> target) {
return implement(Key.get(source, annotationType), target);
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(Key source, Class extends T> target) {
return implement(source, TypeLiteral.get(target));
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinFactoryModuleBuilder implement(Key source, TypeLiteral extends T> target) {
bindings.addBinding(source, target);
return this;
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinModule build(Class factoryInterface) {
return build(TypeLiteral.get(factoryInterface));
}
/**
* See the factory configuration examples at {@link GinFactoryModuleBuilder}.
*/
public GinModule build(TypeLiteral factoryInterface) {
return build(Key.get(factoryInterface));
}
public GinModule build(Key factoryInterface) {
return new FactoryModule(
bindings.getBindings(),
factoryInterface,
findCaller(factoryInterface));
}
/**
* Find the topmost stack element that's not a method of this class, which is
* presumably the location in a Gin module that invoked build().
*
* @param factoryInterface An object identifying the factory interface; used
* to generate a fallback message if we can't determine the caller.
*/
private String findCaller(Object factoryInterface) {
Throwable dummyThrowableForStackTrace = new Throwable();
StackTraceElement[] stackTrace = dummyThrowableForStackTrace.getStackTrace();
for (StackTraceElement element : stackTrace) {
if (!element.getClassName().equals(GinFactoryModuleBuilder.class.getName())) {
return element.toString();
}
}
return "definition of factory " + factoryInterface;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy