ClasspathFunctionResolver extends BaseFunctionResolver { @Override @SuppressWarnings("unchecked") public Set<Class<? extends StellarFunction>> resolvables() { ClassLoader[] cls = null; if (this.classLoaders.size() == 0) { LOG.warn("Using System classloader"); cls = new ClassLoader[]{getClass().getClassLoader()}; } else { List<ClassLoader> classLoaderList = new ArrayList<>(); for (int i = 0; i < this.classLoaders.size(); ++i) { ClassLoader cl = this.classLoaders.get(i); if (null != cl) { LOG.debug("Using classloader: {}", cl.getClass().getCanonicalName()); classLoaderList.add(cl); } else { LOG.error( "This should not happen, so report a bug if you see this error - Classloader {} of {} was null. Classloader list is: {}", i, this.classLoaders.size(), this.classLoaders); } } cls = classLoaderList.toArray(new ClassLoader[0]); } FilterBuilder filterBuilder = new FilterBuilder(); excludes.forEach(excl -> { if (excl != null) { filterBuilder.exclude(excl); } }); includes.forEach(incl -> { if (incl != null) { filterBuilder.include(incl); } }); Set<String> classes = new HashSet<>(); Set<Class<? extends StellarFunction>> ret = new HashSet<>(); for (ClassLoader cl : cls) { for (Class<?> c : getStellarClasses(cl)) { try { LOG.debug("{}: Found class: {}", cl.getClass().getCanonicalName(), c.getCanonicalName()); if (includeClass(c, filterBuilder)) { String className = c.getName(); if (!classes.contains(className)) { LOG.debug("{}: Added class: {}", cl.getClass().getCanonicalName(), className); ret.add((Class<? extends StellarFunction>) c); classes.add(className); } } } catch (Error le) { try { LOG.error("Skipping class " + c.getName() + ": " + le.getMessage() + ", please check that there are not old versions of stellar functions on the classpath.", le); } catch (Error ie) { LOG.error("Skipping class: " + le.getMessage() + ", please check that there are not old versions of stellar functions on the classpath.", le); } } } } return ret; } ClasspathFunctionResolver(); void classLoaders(ClassLoader... classloaders); void include(String... toInclude); void exclude(String... toExclude); @Override @SuppressWarnings("unchecked") void initialize(Context context); @Override @SuppressWarnings("unchecked") Set<Class<? extends StellarFunction>> resolvables();  }
@Test public void testInvalidStellarClass() { StellarFunction goodFunc = mock(StellarFunction.class); StellarFunction badFunc = mock(StellarFunction.class); ClasspathFunctionResolver resolver = new ClasspathFunctionResolver() { @Override protected Iterable<Class<?>> getStellarClasses(ClassLoader cl) { return ImmutableList.of(goodFunc.getClass(), badFunc.getClass()); } @Override protected boolean includeClass(Class<?> c, FilterBuilder filterBuilder) { if(c != goodFunc.getClass()) { throw new LinkageError("failed!"); } return true; } }; Set<Class<? extends StellarFunction>> funcs = resolver.resolvables(); assertEquals(1, funcs.size()); assertEquals(goodFunc.getClass(), Iterables.getFirst(funcs, null)); }