
com.google.gwt.inject.rebind.util.NameGenerator Maven / Gradle / Ivy
/*
* 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.util;
import com.google.gwt.dev.util.Preconditions;
import com.google.gwt.inject.rebind.output.FragmentPackageName;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* Helper to generate various names for members of a {@code Ginjector}
* implementation.
*/
public class NameGenerator {
private class CacheKey {
private final String prefix;
private final Key> key;
CacheKey(String prefix, Key> key) {
this.prefix = prefix;
this.key = key;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof CacheKey) {
CacheKey other = (CacheKey) obj;
return other.prefix.equals(prefix) && other.key.equals(key);
}
return false;
}
@Override
public int hashCode() {
return prefix.hashCode() * 31 + key.hashCode();
}
}
/**
* "Mangled key name" cache: Key -> mangled name
*/
private final Map methodKeyCache = new LinkedHashMap();
/**
* Map of known method names.
*/
private final Set methodNames = new LinkedHashSet();
/**
* Returns the name of an assisted injection helper method.
*/
public String getAssistedInjectMethodName(Key> factoryKey, String methodName) {
return mangle("assistedInject_" + methodName, factoryKey);
}
/**
* Returns the name of a getter for a child injector.
*/
public String getChildInjectorGetterMethodName(String childInjectorClassName) {
return convertToValidMemberName("getChild_" + childInjectorClassName);
}
/**
* Returnst he name of a getter for an injector fragment.
*/
public String getFragmentGetterMethodName(FragmentPackageName fragmentPackageName) {
return "getFragment_" + fragmentPackageName.toString().replace(".", "_");
}
/**
* Returns the key's getter method name. The method with that name can be
* called to retrieve an instance of the type described by the key.
*
* @return getter method name
*/
public String getGetterMethodName(Key> key) {
return mangle("get_", key);
}
/**
* Computes the name of a single fragment of a Ginjector.
*
* @param injectorClassName the simple name of the injector's class (not
* including its package)
*/
public String getFragmentClassName(String injectorClassName,
FragmentPackageName fragmentPackageName) {
// Sanity check.
Preconditions.checkArgument(!injectorClassName.contains("."),
"The injector class must be a simple name, but it was \"%s\"", injectorClassName);
// Note that the fragment package name is not actually included in the
// fragment. This reduces the length of the fragment's class name, which is
// important because some systems have small limits on the maximum length of
// a file (e.g., ~256 characters). However, it means that other parts of
// Gin must reference the fragment using its canonical class name, to avoid
// ambiguity.
return injectorClassName + "_fragment";
}
/**
* Computes the canonical name (including package) of a single fragment of a
* Ginjector.
*/
public String getFragmentCanonicalClassName(String injectorClassName,
FragmentPackageName fragmentPackageName) {
return fragmentPackageName + "." + getFragmentClassName(injectorClassName, fragmentPackageName);
}
/**
* Computes the field name of a single fragment of an injector.
*/
public String getFragmentFieldName(FragmentPackageName fragmentPackageName) {
return convertToValidMemberName("fieldFragment_" + fragmentPackageName);
}
/**
* Computes the name of the field in which the Ginjector interface
* implementation is stored.
*/
public String getGinjectorInterfaceFieldName() {
return "fieldGinjectorInterface";
}
/**
* Computes the name of the method used to retrieve the Ginjector interface
* implementation.
*/
public String getGinjectorInterfaceGetterMethodName() {
return "getGinjectorInterface";
}
/**
* Returns the type's member inject method name. The method with that name
* can be called with a single parameter to inject members of that parameter.
*
* @return member inject method name
*/
public String getMemberInjectMethodName(TypeLiteral> type) {
return mangle("memberInject_", Key.get(type));
}
/**
* Returns the key's singleton field name.
*
* @return singleton field name
*/
public String getSingletonFieldName(Key> key) {
return mangle("singleton_", key);
}
/**
* Returns a new valid (i.e. unique) method name based on {@code base}.
*
* Note: Method names are considered "used" after being returned by this
* method, whether they're actually used to write a new method or not.
*
* @param base base on which method name gets created
* @return valid method name
*/
public String createMethodName(String base) {
while (methodNames.contains(base)) {
// TODO(schmitt): Make more efficient for repeated calls with same base?
base += "_";
}
methodNames.add(base);
return base;
}
/**
* Reserves the given name to prevent new methods to be created with it.
*
* @param name name to be reserved
*/
public void markAsUsed(String name) throws IllegalArgumentException {
methodNames.add(name);
}
private String mangle(String prefix, Key> key) {
CacheKey cacheKey = new CacheKey(prefix, key);
String cached = methodKeyCache.get(cacheKey);
if (cached != null) {
return cached;
}
// TODO(bstoler): This algorithm is kinda crazy because the annotation
// values are of unbounded length. One option
// is to use mangled(type) + mangled(annotation type) + counter, where
// counter is used just to distinguish different annotation values.
String name = prefix + key.toString();
name = convertToValidMemberName(name);
name = createMethodName(name);
methodKeyCache.put(cacheKey, name);
return name;
}
public String convertToValidMemberName(String name) {
name = name.replaceAll("\\s+", "_");
name = name.replaceAll("[^\\p{Alnum}_]", "\\$");
return name;
}
// Static for access from enum.
public static String replaceLast(String source, char toReplace, char with) {
StringBuilder sb = new StringBuilder(source);
int index = sb.lastIndexOf(String.valueOf(toReplace));
if (index != -1) {
sb.setCharAt(index, with);
}
return sb.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy