/*
* 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.core.ext.Generator;
import com.google.gwt.inject.rebind.GinjectorBindings;
import com.google.gwt.inject.rebind.reflect.NoSourceNameException;
import com.google.gwt.inject.rebind.reflect.ReflectUtil;
import com.google.gwt.inject.rebind.util.InjectorMethod;
import com.google.gwt.inject.rebind.util.NameGenerator;
import com.google.gwt.inject.rebind.util.Preconditions;
import com.google.gwt.inject.rebind.util.SourceSnippet;
import com.google.gwt.inject.rebind.util.SourceSnippetBuilder;
import com.google.gwt.inject.rebind.util.SourceSnippets;
import com.google.inject.Key;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Binding for a constant value.
*/
public class BindConstantBinding<T> extends AbstractBinding implements Binding {
private final String valueToOutput;
private final Key<?> key;
/**
* Returns true if the provided key is a valid constant key, i.e. if a
* constant binding can be legally created for it.
*
* @param key key to check
* @return true if constant key
*/
public static boolean isConstantKey(Key<?> key) {
Type type = key.getTypeLiteral().getType();
if (!(type instanceof Class)) {
return false;
}
Class clazz = (Class) type;
return clazz == String.class || clazz == Class.class || clazz.isPrimitive()
|| Number.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz)
|| Boolean.class.isAssignableFrom(clazz) || clazz.isEnum();
}
BindConstantBinding(Key<T> key, T instance, Context context) {
super(context, key);
this.key = Preconditions.checkNotNull(key);
this.valueToOutput = getValueToOutput(key, Preconditions.checkNotNull(instance));
}
private static <T> String getValueToOutput(Key<T> key, T instance) {
Type type = key.getTypeLiteral().getType();
if (type == String.class) {
return "\"" + Generator.escape(instance.toString()) + "\"";
} else if (type == Class.class) {
return toClassReference((Class<?>) instance);
} else if (type == Character.class) {
return "'" + (Character.valueOf('\'').equals(instance) ? "\\" : "") + instance + "'";
} else if (type == Float.class) {
return instance.toString() + "f";
} else if (type == Long.class) {
return instance.toString() + "L";
} else if (type == Double.class) {
return instance.toString() + "d";
} else if (instance instanceof Number || instance instanceof Boolean) {
return instance.toString(); // Includes int & short.
} else if (instance instanceof Enum) {
return toEnumReference(((Enum<?>) instance));
} else {
throw new IllegalArgumentException("Attempted to create a constant binding with a "
+ "non-constant type: " + type);
}
}
public SourceSnippet getCreationStatements(NameGenerator nameGenerator,
List<InjectorMethod> methodsOutput) throws NoSourceNameException {
String type = ReflectUtil.getSourceName(key.getTypeLiteral());
return new SourceSnippetBuilder()
.append(type).append(" result = ").append(valueToOutput).append(";")
.build();
}
public Collection<Dependency> getDependencies() {
return Collections.singletonList(
new Dependency(Dependency.GINJECTOR, key, getContext().toString()));
}
private static String toEnumReference(Enum<?> instance) {
return instance.getDeclaringClass().getCanonicalName() + "." + instance.name();
}
private static String toClassReference(Class<?> instance) {
String canonicalName = instance.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Attempted to create a constant binding with a "
+ "a local or anonymous class: " + instance);
}
return canonicalName + ".class";
}
}