@Override public Binding<?> getAtInjectBinding( String key, String className, ClassLoader classLoader, boolean mustHaveInjections) { TypeElement type = resolveType(processingEnv.getElementUtils(), className); if (type == null) { // We've encountered a type that the compiler can't introspect. If this // causes problems in practice (due to incremental compiles, etc.) we // should return a new unresolved binding and warn about the possibility // of runtime failures. return null; } if (type.getKind() == ElementKind.INTERFACE) { return null; } return GraphAnalysisInjectBinding.create(type, mustHaveInjections); }
/** * Resolves the given class name into a {@link TypeElement}. The class name is a binary name, but * {@link Elements#getTypeElement(CharSequence)} wants a canonical name. So this method searches * the space of possible canonical names, starting with the most likely (since '$' is rarely used * in canonical class names). */ @VisibleForTesting static TypeElement resolveType(Elements elements, String className) { int index = nextDollar(className, className, 0); if (index == -1) { return getTypeElement(elements, className); } // have to test various possibilities of replacing '$' with '.' since '.' in a canonical name // of a nested type is replaced with '$' in the binary name. StringBuilder sb = new StringBuilder(className); return resolveType(elements, className, sb, index); }
/** * Recursively explores the space of possible canonical names for a given binary class name. * * @param elements used to resolve a name into a {@link TypeElement} * @param className binary class name * @param sb the current permutation of canonical name to attempt to resolve * @param index the index of a {@code '$'} which may be changed to {@code '.'} in a canonical name */ private static TypeElement resolveType(Elements elements, String className, StringBuilder sb, final int index) { // We assume '$' should be converted to '.'. So we search for classes with dots first. sb.setCharAt(index, '.'); int nextIndex = nextDollar(className, sb, index + 1); TypeElement type = nextIndex == -1 ? getTypeElement(elements, sb) : resolveType(elements, className, sb, nextIndex); if (type != null) { return type; } // if not found, change back to dollar and search. sb.setCharAt(index, '$'); nextIndex = nextDollar(className, sb, index + 1); return nextIndex == -1 ? getTypeElement(elements, sb) : resolveType(elements, className, sb, nextIndex); }