class ClasspathEntry {
        /** The classpath entry object (a {@link String} path, {@link Path}, {@link URL} or {@link URI}). */
        public final Object classpathEntryObj;

        /** The classloader the classpath element was obtained from. */
        public final ClassLoader classLoader;

        /**
         * Constructor.
         *
         * @param classpathEntryObj
         *            the classpath entry object (a {@link String} or {@link URL} or {@link Path}).
         * @param classLoader
         *            the classloader the classpath element was obtained from.
         */
        public ClasspathEntry(final Object classpathEntryObj, final ClassLoader classLoader) {
            this.classpathEntryObj = classpathEntryObj;
            this.classLoader = classLoader;
        }

        @Override
        public int hashCode() {
            return Objects.hash(classpathEntryObj);
        }

        @Override
        public boolean equals(final Object obj) {
            if (obj == this) {
                return true;
            } else if (!(obj instanceof ClasspathEntry)) {
                return false;
            }
            final ClasspathEntry other = (ClasspathEntry) obj;
            return Objects.equals(this.classpathEntryObj, other.classpathEntryObj);
        }

        @Override
        public String toString() {
            return classpathEntryObj + " [" + classLoader + "]";
        }
    }

    /**
     * Constructor.
     *
     * @param scanSpec
     *            the scan spec
     */
    ClasspathOrder(final ScanSpec scanSpec, final ReflectionUtils reflectionUtils) {
        this.scanSpec = scanSpec;
        this.reflectionUtils = reflectionUtils;
    }

    /**
     * Get the order of classpath elements, uniquified and in order.
     *
     * @return the classpath order.
     */
    public List<ClasspathEntry> getOrder() {
        return order;
    }

    /**
     * Get the unique classpath entry strings.
     *
     * @return the classpath entry strings.
     */
    public Set<String> getClasspathEntryUniqueResolvedPaths() {
        return classpathEntryUniqueResolvedPaths;
    }

    /**
     * Test to see if a classpath element has been filtered out by the user.
     * 
     * @param classpathElementURL
     *            the classpath element URL
     * @param classpathElementPath
     *            the classpath element path
     * @return true, if not filtered out
     */
    private boolean filter(final URL classpathElementURL, final String classpathElementPath) {
        if (scanSpec.classpathElementFilters != null) {
            for (final Object filterObj : scanSpec.classpathElementFilters) {
                if ((classpathElementURL != null && filterObj instanceof ClasspathElementURLFilter
                        && !((ClasspathElementURLFilter) filterObj).includeClasspathElement(classpathElementURL))
                        || (classpathElementPath != null && filterObj instanceof ClasspathElementFilter
                                && !((ClasspathElementFilter) filterObj)
                                        .includeClasspathElement(classpathElementPath))) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Add a system classpath entry.
     *
     * @param pathEntry
     *            the system classpath entry -- the path string should already have been run through
     *            FastPathResolver.resolve(FileUtils.currDirPath(), path)
     * @param classLoader
     *            the classloader
     * @return true, if added and unique
     */
    boolean addSystemClasspathEntry(final String pathEntry, final ClassLoader classLoader) {
        if (classpathEntryUniqueResolvedPaths.add(pathEntry)) {
            order.add(new ClasspathEntry(pathEntry, classLoader));
            return true;
        }
        return false;
    }

    /**
     * Add a classpath entry.
     *
     * @param pathElement
     *            the {@link String} path, {@link File}, {@link Path}, {@link URL} or {@link URI} of the classpath
     *            element.
     * @param pathElementStr
     *            the path element in string format
     * @param classLoader
     *            the classloader
     * @param scanSpec
     *            the scan spec
     * @return true, if added and unique
     */
    private boolean addClasspathEntry(final Object pathElement, final String pathElementStr,
            final ClassLoader classLoader, final ScanSpec scanSpec) {<FILL_FUNCTION_BODY>

        // Check if classpath element path ends with an automatic package root. If so, strip it off to
        // eliminate duplication, since automatic package roots are detected automatically (#435)
        String pathElementStrWithoutSuffix = pathElementStr;
        boolean hasSuffix = false;
        for (final String suffix : AUTOMATIC_PACKAGE_ROOT_SUFFIXES) {
            if (pathElementStr.endsWith(suffix)) {
                // Strip off automatic package root suffix
                pathElementStrWithoutSuffix = pathElementStr.substring(0,
                        pathElementStr.length() - suffix.length());
                hasSuffix = true;
                break;
            }
        }
        if (pathElement instanceof URL || pathElement instanceof URI || pathElement instanceof Path
                || pathElement instanceof File) {
            Object pathElementWithoutSuffix = pathElement;
            if (hasSuffix) {
                try {
                    pathElementWithoutSuffix = pathElement instanceof URL ? new URL(pathElementStrWithoutSuffix)
                            : pathElement instanceof URI ? new URI(pathElementStrWithoutSuffix)
                                    : pathElement instanceof Path ? Paths.get(pathElementStrWithoutSuffix)
                                            // For File, just use path string
                                            : pathElementStrWithoutSuffix;
                } catch (MalformedURLException | URISyntaxException | InvalidPathException e) {
                    try {
                        pathElementWithoutSuffix = pathElement instanceof URL
                                ? new URL("file:" + pathElementStrWithoutSuffix)
                                : pathElement instanceof URI ? new URI("file:" + pathElementStrWithoutSuffix)
                                        : pathElementStrWithoutSuffix;
                    } catch (MalformedURLException | URISyntaxException | InvalidPathException e2) {
                        return false;
                    }
                }
            }
            // Deduplicate classpath elements
            if (classpathEntryUniqueResolvedPaths.add(pathElementStrWithoutSuffix)) {
                // Record classpath element in classpath order
                order.add(new ClasspathEntry(pathElementWithoutSuffix, classLoader));
                return true;
            }
        } else {
            final String pathElementStrResolved = FastPathResolver.resolve(FileUtils.currDirPath(),
                    pathElementStrWithoutSuffix);
            if (scanSpec.overrideClasspath == null //
                    && (SystemJarFinder.getJreLibOrExtJars().contains(pathElementStrResolved)
                            || pathElementStrResolved.equals(SystemJarFinder.getJreRtJarPath()))) {
                // JRE lib and ext jars are handled separately, so reject them as duplicates if they are 
                // returned by a system classloader
                return false;
            }
            if (classpathEntryUniqueResolvedPaths.add(pathElementStrResolved)) {
                order.add(new ClasspathEntry(pathElementStrResolved, classLoader));
                return true;
            }
        }
        return false;
    
<no_super_class>