org.directwebremoting.guice.util.Providers Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dwr Show documentation
Show all versions of dwr Show documentation
DWR is easy Ajax for Java. It makes it simple to call Java code directly from Javascript.
It gets rid of almost all the boiler plate code between the web browser and your Java code.
The newest version!
/*
* Copyright 2008 Tim Peierls
*
* 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.directwebremoting.guice.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.google.inject.Binder;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
import static java.lang.reflect.Modifier.*;
/**
* Utilities for creating ad hoc providers. These come in two flavors,
* constructor and factory method. In both cases, you can specify additional
* methods to inject after creation by chaining calls to
* {@link BindingProvider#injecting injecting(methodName, paramKeys)}.
* Each method has two variants, one with a {@code Binder} parameter and one
* without. The former reports construction errors via the binder (so more than
* one error can be reported), the latter throws a runtime exception immediately,
* preventing further error reporting.
*
* Some examples:
*
* bind(SomeInterface.class)
* .toProvider(
* .fromConstructor(LegacyImpl.class,
* Key.get(String.class, MyAnnotation.class))
* .injecting("configure", Key.get(Configuration.class)));
*
* This binds {@code SomeInterface} to a provider that uses the
* {@code LegacyImpl} constructor with a single String parameter.
* That parameter is injected as if it had been marked with {@code @MyAnnotation}.
* It also calls the {@code LegacyImpl.configure} method with an injected
* instance of {@code Configuration}.
*
* bind(SomeInterface.class)
* .toProvider(
* .fromFactoryMethod(SomeInterface.class,
* LegacyFactory.class, "newSomeInterface",
* Key.get(String.class, MyAnnotation.class)));
*
* This binds {@code SomeInterface} to a provider that calls a factory method
* {@code newSomeInterface} of {@code LegacyFactory} with a single string parameter,
* which is injected as if it were marked with {@code @MyAnnotation}. If the
* method is not static, an instance of {@code LegacyFactory} is created by injection
* and used to call the method.
* @author Tim Peierls [tim at peierls dot net]
*/
public class Providers
{
/**
* For fluent-style decoration with one or more method bindings when
* using {@link #fromConstructor(Class, Key...)}.
*/
public interface BindingProvider extends Provider
{
/**
* Adds injection of a method defined by the given name and parameter
* types (specified as Guice keys) to this provider.
*/
BindingProvider injecting(String methodName, Key>... paramKeys);
}
/**
* Creates a chainable provider that constructs an instance of the
* given type given a list of constructor parameter types, specified
* as Guice keys. Construction errors are thrown immediately.
*/
public static BindingProvider fromConstructor(Class type, final Key>... keys)
{
return new ConstructorBindingProvider(null, type, keys);
}
/**
* Creates a chainable provider that constructs an instance of the
* given type given a list of constructor parameter types, specified
* as Guice keys. Construction errors are passed to {@code binder}
* to be thrown at the end of all binding.
*/
public static BindingProvider fromConstructor(Binder binder, Class type, final Key>... keys)
{
return new ConstructorBindingProvider(binder, type, keys);
}
/**
* Creates a chainable provider that constructs an instance of {@code providedType}
* using a factory method defined by {@code factoryType}, {@code methodName},
* and a list of method parameter types specified as Guice keys. If the
* method is not static an instance of the factory type is created and injected.
* Construction errors are thrown immediately.
*/
public static BindingProvider fromFactoryMethod(
Class providedType, Class> factoryType, String methodName, final Key>... keys)
{
return new FactoryMethodBindingProvider(
null, providedType, Key.get(factoryType), methodName, keys);
}
/**
* Creates a chainable provider that constructs an instance of {@code providedType}
* using a factory method defined by {@code factoryType}, {@code methodName},
* and a list of method parameter types specified as Guice keys. If the
* method is not static an instance of the factory type is created and injected.
* Construction errors are passed to {@code binder} to be thrown at the end
* of all binding.
*/
public static BindingProvider fromFactoryMethod(
Binder binder, Class providedType,
Class> factoryType, String methodName, final Key>... keys)
{
return new FactoryMethodBindingProvider(
binder, providedType, Key.get(factoryType), methodName, keys);
}
/**
* Creates a chainable provider that constructs an instance of {@code providedType} by
* calling method {@code methodName} of the type in {@code factoryKey} with
* method parameter types specified as Guice keys. If the method is not static
* an instance is created and injected using the factory key.
* Construction errors are thrown immediately.
*/
public static BindingProvider fromFactoryMethod(
Class providedType, Key> factoryKey, String methodName, final Key>... keys)
{
return new FactoryMethodBindingProvider(
null, providedType, factoryKey, methodName, keys);
}
/**
* Creates a chainable provider that constructs an instance of {@code providedType} by
* calling method {@code methodName} of the type in {@code factoryKey} with
* method parameter types specified as Guice keys. If the method is not static
* an instance is created and injected using the factory key.
* Construction errors are passed to {@code binder} to be thrown at the end
* of all binding.
*/
public static BindingProvider fromFactoryMethod(
Binder binder, Class providedType,
Key> factoryKey, String methodName, final Key>... keys)
{
return new FactoryMethodBindingProvider(
binder, providedType, factoryKey, methodName, keys);
}
//
// Implementation classes
//
private abstract static class AbstractBindingProvider implements BindingProvider
{
protected AbstractBindingProvider(Binder binder, Class type, Key>... keys)
{
this.binder = binder;
this.type = type;
this.keys = keys;
}
public final T get()
{
return get(theInjector);
}
protected abstract T get(Injector injector);
public final BindingProvider injecting(String methodName, Key>... paramKeys)
{
return new MethodBindingProvider(this, type, methodName, paramKeys);
}
protected final Class>[] getTypes()
{
Class>[] types = new Class[keys.length];
int i = 0;
for (Key> key : keys)
{
types[i] = (Class>) key.getTypeLiteral().getType();
i++;
}
return types;
}
protected final Object[] getValues(Injector injector)
{
Object[] values = new Object[keys.length];
int i = 0;
for (Key> key : keys)
{
Object param = injector.getInstance(key);
values[i] = param;
i++;
}
return values;
}
protected final Binder binder;
protected final Class type;
protected final Key>[] keys;
/**
* Effectively immutable: Injected at end of bind-time,
* read-only thereafter, and there is (or should be) a
* happens-before edge between bind-time and subsequent reads.
*/
@Inject private Injector theInjector;
}
private static class ConstructorBindingProvider extends AbstractBindingProvider
{
ConstructorBindingProvider(Binder binder, Class type, Key>... keys)
{
super(binder, type, keys);
Constructor newConstructor = null;
try
{
newConstructor = type.getConstructor(getTypes());
}
catch (NoSuchMethodException e)
{
if (binder == null)
{
throw new IllegalArgumentException("no such constructor", e);
}
else
{
binder.addError(e);
}
}
this.constructor = newConstructor;
}
@Override
public T get(Injector injector)
{
try
{
return constructor.newInstance(getValues(injector));
}
catch (InstantiationException e)
{
throw new IllegalStateException(e);
}
catch (IllegalAccessException e)
{
throw new IllegalStateException(e);
}
catch (InvocationTargetException e)
{
throw new IllegalStateException(e);
}
}
private final Constructor constructor;
}
private static class MethodBindingProvider extends AbstractBindingProvider {
MethodBindingProvider(AbstractBindingProvider prev,
Class type, String methodName, Key>... keys)
{
super(prev.binder, type, keys);
Method newMethod = null;
try
{
newMethod = type.getMethod(methodName, getTypes());
}
catch (NoSuchMethodException e)
{
if (binder == null)
{
throw new IllegalArgumentException("no such method", e);
}
else
{
binder.addError(e);
}
}
this.prev = prev;
this.method = newMethod;
}
@Override
public T get(Injector injector)
{
T target = prev.get(injector);
try
{
method.invoke(target, getValues(injector));
}
catch (IllegalAccessException e)
{
throw new IllegalStateException(e);
}
catch (InvocationTargetException e)
{
throw new IllegalStateException(e);
}
return target;
}
private final AbstractBindingProvider prev;
private final Method method;
}
private static class FactoryMethodBindingProvider extends AbstractBindingProvider
{
FactoryMethodBindingProvider(Binder binder, Class providedType, Key> factoryKey, String methodName, Key>... keys)
{
super(binder, providedType, keys);
Method newMethod = null;
try
{
Class> factoryType = (Class>) factoryKey.getTypeLiteral().getType();
newMethod = factoryType.getMethod(methodName, getTypes());
newMethod.getReturnType().asSubclass(providedType);
}
catch (NoSuchMethodException e)
{
if (binder == null)
{
throw new IllegalArgumentException("no such method", e);
}
else
{
binder.addError(e);
}
}
catch (ClassCastException e)
{
if (binder == null)
{
throw new IllegalArgumentException("bad return type", e);
}
else
{
binder.addError(e);
}
}
this.method = newMethod;
this.factoryKey = factoryKey;
}
@Override
public T get(Injector injector)
{
try
{
Object target = null;
if (!isStatic(method.getModifiers()))
{
target = injector.getInstance(factoryKey);
}
@SuppressWarnings("unchecked")
T result = (T) method.invoke(target, getValues(injector));
return result;
}
catch (IllegalAccessException e)
{
throw new IllegalStateException(e);
}
catch (InvocationTargetException e)
{
throw new IllegalStateException(e);
}
}
private final Method method;
private final Key> factoryKey;
}
private Providers()
{
throw new AssertionError("uninstantiable");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy