class SymbolLookup {

    public Descriptor<?> findDescriptor(Class<?> type, String symbol) {
        try {
            Key k = new Key("findDescriptor",type,symbol);
            Object i = cache.get(k);
            if (i!=null)    return (Descriptor)i;

            // not allowing @Symbol to use an invalid identifier.
            // TODO: compile time check
            if (!Utilities.isJavaIdentifier(symbol))
                return null;

            // Check for an explicit no-response with the plugin, after confirming no new plugins
            checkPluginsForChangeAndRefresh();
            Object miss = noHitCache.get(k);
            if (miss == NO_HIT) {
                return null;
            }

            for (Class<?> e : Index.list(Symbol.class, pluginManager.uberClassLoader, Class.class)) {
                if (Descriptor.class.isAssignableFrom(e)) {
                    Descriptor<?> d = jenkins.getDescriptorByType(e.asSubclass(Descriptor.class));
                    if (d == null) {
                        LOGGER.fine(() -> e.getName() + " is not registered as an extension, so will be ignored");
                        continue;
                    }
                    Symbol s = e.getAnnotation(Symbol.class);
                    if (s != null) {
                        for (String t : s.value()) {
                            if (t.equals(symbol)) {
                                if (type.isAssignableFrom(d.clazz)) {
                                    cache.put(k, d);
                                    return d;
                                }
                            }
                        }
                    }
                }
            }

            noHitCache.put(k, NO_HIT);
            return null;
        } catch (IOException e) {
            LOGGER.log(Level.WARNING, "Unable to find @Symbol",e);
            return null;
        }
    }

}