All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.api.java.source.ClasspathInfo Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.netbeans.api.java.source;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.event.ChangeListener;
import javax.swing.text.Document;
import javax.tools.JavaFileManager;
import javax.tools.StandardLocation;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.annotations.common.NullUnknown;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.classpath.JavaClassPathConstants;
import org.netbeans.api.java.platform.JavaPlatformManager;
import org.netbeans.modules.java.source.classpath.CacheClassPath;
import org.netbeans.modules.java.source.parsing.ProxyFileManager;
import org.netbeans.modules.java.preprocessorbridge.spi.JavaFileFilterImplementation;
import org.netbeans.modules.java.source.classpath.AptSourcePath;
import org.netbeans.modules.java.source.classpath.SourcePath;
import org.netbeans.modules.java.source.indexing.JavaIndex;
import org.netbeans.modules.java.source.indexing.TransactionContext;
import org.netbeans.modules.java.source.parsing.*;
import org.netbeans.modules.java.source.usages.ClasspathInfoAccessor;
import org.netbeans.modules.parsing.impl.Utilities;
import org.netbeans.modules.parsing.impl.indexing.PathRegistry;
import org.netbeans.spi.java.classpath.ClassPathFactory;
import org.netbeans.spi.java.classpath.ClassPathImplementation;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.BaseUtilities;
import org.openide.util.ChangeSupport;
import org.openide.util.Parameters;
import org.openide.util.WeakListeners;

/** Class which contains info about classpath
 *
 * @author Tomas Zezula, Petr Hrebejk
 */
public final class ClasspathInfo {

    private static final Logger log = Logger.getLogger(ClasspathInfo.class.getName());

    static {
        ClasspathInfoAccessor.setINSTANCE(new ClasspathInfoAccessorImpl());
        try {
            Class.forName(ClassIndex.class.getName(), true, CompilationInfo.class.getClassLoader());
        } catch (ClassNotFoundException ex) {
            if (log.isLoggable(Level.SEVERE))
                log.log(Level.SEVERE, ex.getMessage(), ex);
        }
    }

    private final ClassPath srcClassPath;
    private final ClassPath moduleSrcPath;
    private final ClassPath bootClassPath;
    private final ClassPath moduleBootPath;
    private final ClassPath compileClassPath;
    private final ClassPath moduleCompilePath;
    private final ClassPath moduleClassPath;
    private final ClassPath cachedAptSrcClassPath;
    private final ClassPath cachedSrcClassPath;
    private final ClassPath cachedBootClassPath;
    private final ClassPath cachedCompileClassPath;
    private final ClassPath cachedModuleCompilePath;
    private final ClassPath cachedModuleClassPath;
    private final ClassPath outputClassPath;

    private final ClassPathListener cpListener;
    private final boolean useModifiedFiles;
    private final boolean ignoreExcludes;
    private final JavaFileFilterImplementation filter;
    private final MemoryFileManager memoryFileManager;
    private final ChangeSupport listenerList;
    private final FileManagerTransaction fmTx;
    private final ProcessorGenerated pgTx;
    private final Map>> peerProviders;
    private final Function jfmProvider;

    //@GuardedBy("this")
    private ClassIndex usagesQuery;

    /** Creates a new instance of ClasspathInfo (private use the factory methods) */
    private ClasspathInfo(final @NonNull ClassPath bootCp,
                          final @NonNull ClassPath moduleBootP,
                          final @NonNull ClassPath compileCp,
                          final @NonNull ClassPath moduleCompileP,
                          final @NonNull ClassPath moduleClassP,
                          final @NullAllowed ClassPath srcCp,
                          final @NullAllowed ClassPath moduleSrcCp,
                          final @NullAllowed JavaFileFilterImplementation filter,
                          final boolean backgroundCompilation,
                          final boolean ignoreExcludes,
                          final boolean hasMemoryFileManager,
                          final boolean useModifiedFiles,
                          final boolean requiresSourceRoots,
                          @NullAllowed final Function jfmProvider) {
        assert bootCp != null;
        assert compileCp != null;
        this.cpListener = new ClassPathListener ();
        this.bootClassPath = bootCp;
        this.moduleBootPath = moduleBootP;
        this.compileClassPath = compileCp;
        this.moduleCompilePath = moduleCompileP;
        this.moduleClassPath = moduleClassP;
        this.listenerList = new ChangeSupport(this);
        this.cachedBootClassPath = CacheClassPath.forBootPath(this.bootClassPath,backgroundCompilation);
        this.cachedCompileClassPath = CacheClassPath.forClassPath(this.compileClassPath,backgroundCompilation);
        this.cachedModuleCompilePath = CacheClassPath.forClassPath(this.moduleCompilePath,backgroundCompilation);
        this.cachedModuleClassPath = CacheClassPath.forClassPath(this.moduleClassPath,backgroundCompilation);
        if (!backgroundCompilation) {
            this.cachedBootClassPath.addPropertyChangeListener(WeakListeners.propertyChange(this.cpListener,this.cachedBootClassPath));
            this.cachedCompileClassPath.addPropertyChangeListener(WeakListeners.propertyChange(this.cpListener,this.cachedCompileClassPath));
        }
        if (srcCp == null || srcCp == ClassPath.EMPTY) {
            this.cachedSrcClassPath = this.srcClassPath = this.outputClassPath = this.cachedAptSrcClassPath = ClassPath.EMPTY;
        } else {
            this.srcClassPath = srcCp;
            final ClassPathImplementation noApt = AptSourcePath.sources(srcCp);
            this.cachedSrcClassPath = ClassPathFactory.createClassPath(SourcePath.filtered(noApt, backgroundCompilation));
            this.cachedAptSrcClassPath = ClassPathFactory.createClassPath(
                    SourcePath.filtered(AptSourcePath.aptCache(srcCp), backgroundCompilation));
            this.outputClassPath = CacheClassPath.forSourcePath (ClassPathFactory.createClassPath(noApt),backgroundCompilation);
            if (!backgroundCompilation) {
                this.cachedSrcClassPath.addPropertyChangeListener(WeakListeners.propertyChange(this.cpListener,this.cachedSrcClassPath));
            }
        }
        if (requiresSourceRoots && this.cachedSrcClassPath.entries().isEmpty()) {
            throw new OutputFileManager.InvalidSourcePath();
        }
        if (moduleSrcCp == null) {
            this.moduleSrcPath = ClassPath.EMPTY;
        } else {
            this.moduleSrcPath = moduleSrcCp;
        }
        this.ignoreExcludes = ignoreExcludes;
        this.useModifiedFiles = useModifiedFiles;
        this.filter = filter;
        if (hasMemoryFileManager) {
            if (srcCp == null) {
                throw new IllegalStateException ();
            }
            this.memoryFileManager = new MemoryFileManager();
        } else {
            this.memoryFileManager = null;
        }
        if (backgroundCompilation) {
            final TransactionContext txCtx = TransactionContext.get();
            fmTx = txCtx.get(FileManagerTransaction.class);
            pgTx = txCtx.get(ProcessorGenerated.class);
        } else {
            //No real transaction, read-only mode.
            fmTx = FileManagerTransaction.treeLoaderOnly();
            pgTx = ProcessorGenerated.nullWrite();
        }
        this.peerProviders = new IdentityHashMap<>();
        this.peerProviders.put(cachedModuleCompilePath, new Peers(this.moduleCompilePath));
        assert fmTx != null : "No file manager transaction.";   //NOI18N
        assert pgTx != null : "No processor generated transaction.";   //NOI18N
        this.jfmProvider = jfmProvider;
    }

    @Override
    public String toString() {
        return String.format(
            "ClasspathInfo [boot: %s, module boot: %s, compile: %s, module compile: %s, module class: %s, src: %s, internal boot: %s, internal compile: %s, internal module class: %s, internal src: %s, internal out: %s]", //NOI18N
                bootClassPath,
                moduleBootPath,
                compileClassPath,
                moduleCompilePath,
                moduleClassPath,
                srcClassPath,
                cachedBootClassPath,
                cachedCompileClassPath,
                cachedModuleClassPath,
                cachedSrcClassPath,
                outputClassPath);
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(toURIs(this.srcClassPath));
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof ClasspathInfo)) {
            return false;
        }
        final ClasspathInfo other = (ClasspathInfo) obj;
        return Arrays.equals(toURIs(this.srcClassPath), toURIs(other.srcClassPath)) &&
            Arrays.equals(toURIs(this.compileClassPath), toURIs(other.compileClassPath)) &&
            Arrays.equals(toURIs(this.bootClassPath), toURIs(other.bootClassPath)) &&
            Arrays.equals(toURIs(this.moduleBootPath), toURIs(other.moduleBootPath)) &&
            Arrays.equals(toURIs(this.moduleCompilePath), toURIs(other.moduleCompilePath)) &&
            Arrays.equals(toURIs(this.moduleClassPath), toURIs(other.moduleClassPath));
    }
    // Factory methods ---------------------------------------------------------


    /** Creates new interface to the compiler
     * @param file for which the CompilerInterface should be created
     * @return ClasspathInfo or null if the file does not exist on the
     * local file system or it has no classpath associated
     */
    @NullUnknown
    public static ClasspathInfo create (@NonNull final File file) {
        if (file == null) {
            throw new IllegalArgumentException ("Cannot pass null as parameter of ClasspathInfo.create(java.io.File)");     //NOI18N
        }
        final FileObject fo = FileUtil.toFileObject(file);
        if (fo == null) {
            return null;
        }
        else {
            return create (fo);
        }
    }

    /**
     * Creates a new instance of the ClasspathInfo for given Document.
     * 
*

* It uses the {@link Document#StreamDescriptionProperty} to obtain the * DataObject for the {@link Document} and creates a {@link ClasspathInfo} * for the primary file of the DataObject *

*
* @param doc a document for which the {@link ClasspathInfo} should be created * @return a {@link ClasspathInfo} or null when the document source cannot be * found. * @since 0.42 */ @NullUnknown public static ClasspathInfo create(@NonNull final Document doc) { Parameters.notNull("doc", doc); FileObject fileObject = Utilities.getFileObject(doc); if (fileObject != null) { return create(fileObject); } return null; } /** Creates new interface to the compiler * @param fo for which the CompilerInterface should be created */ @NonNull public static ClasspathInfo create(@NonNull final FileObject fo) { return create (fo, null, false, false, false, true); } @NonNull public static ClasspathInfo create( @NonNull final ClassPath bootPath, @NonNull final ClassPath classPath, @NullAllowed final ClassPath sourcePath) { Parameters.notNull("bootPath", bootPath); //NOI18N Parameters.notNull("classPath", classPath); //NOI18N return new Builder(bootPath) .setClassPath(classPath) .setSourcePath(sourcePath) .build(); } /** * Builder for {@link ClasspathInfo}. * @since 2.23 */ public static final class Builder { private final ClassPath bootPath; private ClassPath moduleBootPath = ClassPath.EMPTY; private ClassPath classPath = ClassPath.EMPTY; private ClassPath moduleCompilePath = ClassPath.EMPTY; private ClassPath moduleClassPath = ClassPath.EMPTY; private ClassPath sourcePath = ClassPath.EMPTY; private ClassPath moduleSourcePath = ClassPath.EMPTY; public Builder(@NonNull final ClassPath bootPath) { Parameters.notNull("bootPath", bootPath); //NOI18N this.bootPath = bootPath; } @NonNull public Builder setModuleBootPath(@NullAllowed ClassPath moduleBootPath) { if (moduleBootPath == null) { moduleBootPath = ClassPath.EMPTY; } this.moduleBootPath = moduleBootPath; return this; } @NonNull public Builder setClassPath(@NullAllowed ClassPath classPath) { if (classPath == null) { classPath = ClassPath.EMPTY; } this.classPath = classPath; return this; } @NonNull public Builder setModuleCompilePath(@NullAllowed ClassPath moduleCompilePath) { if (moduleCompilePath == null) { moduleCompilePath = ClassPath.EMPTY; } this.moduleCompilePath = moduleCompilePath; return this; } @NonNull public Builder setModuleClassPath(@NullAllowed ClassPath moduleClassPath) { if (moduleClassPath == null) { moduleClassPath = ClassPath.EMPTY; } this.moduleClassPath = moduleClassPath; return this; } @NonNull public Builder setSourcePath(@NullAllowed ClassPath sourcePath) { if (sourcePath == null) { sourcePath = ClassPath.EMPTY; } this.sourcePath = sourcePath; return this; } @NonNull public Builder setModuleSourcePath(@NullAllowed ClassPath moduleSourcePath) { if (moduleSourcePath == null) { moduleSourcePath = ClassPath.EMPTY; } this.moduleSourcePath = moduleSourcePath; return this; } /** * Creates a new {@link ClasspathInfo}. * @return the {@link ClasspathInfo} */ @NonNull public ClasspathInfo build() { return create ( bootPath, moduleBootPath, classPath, moduleCompilePath, moduleClassPath, sourcePath, moduleSourcePath, null, false, false, false, true, false, null); } } @NonNull private static ClasspathInfo create ( @NonNull final FileObject fo, @NullAllowed final JavaFileFilterImplementation filter, final boolean backgroundCompilation, final boolean ignoreExcludes, final boolean hasMemoryFileManager, final boolean useModifiedFiles) { ClassPath bootPath = ClassPath.getClassPath(fo, ClassPath.BOOT); if (bootPath == null) { //javac requires at least java.lang bootPath = JavaPlatformManager.getDefault().getDefaultPlatform().getBootstrapLibraries(); } ClassPath moduleBootPath = ClassPath.getClassPath(fo, JavaClassPathConstants.MODULE_BOOT_PATH); if (moduleBootPath == null) { moduleBootPath = ClassPath.EMPTY; } ClassPath compilePath = ClassPath.getClassPath(fo, ClassPath.COMPILE); if (compilePath == null) { compilePath = ClassPath.EMPTY; } ClassPath moduleCompilePath = ClassPath.getClassPath(fo, JavaClassPathConstants.MODULE_COMPILE_PATH); if (moduleCompilePath == null) { moduleCompilePath = ClassPath.EMPTY; } ClassPath moduleClassPath = ClassPath.getClassPath(fo, JavaClassPathConstants.MODULE_CLASS_PATH); if (moduleClassPath == null) { moduleClassPath = ClassPath.EMPTY; } ClassPath srcPath = ClassPath.getClassPath(fo, ClassPath.SOURCE); ClassPath moduleSrcPath = ClassPath.getClassPath(fo, JavaClassPathConstants.MODULE_SOURCE_PATH); return create (bootPath, moduleBootPath, compilePath, moduleCompilePath, moduleClassPath, srcPath, moduleSrcPath, filter, backgroundCompilation, ignoreExcludes, hasMemoryFileManager, useModifiedFiles, false, null); } @NonNull private static ClasspathInfo create( @NonNull final ClassPath bootPath, @NonNull final ClassPath moduleBootPath, @NonNull final ClassPath classPath, @NonNull final ClassPath moduleCompilePath, @NonNull final ClassPath moduleClassPath, @NullAllowed final ClassPath sourcePath, @NullAllowed final ClassPath moduleSourcePath, @NullAllowed final JavaFileFilterImplementation filter, final boolean backgroundCompilation, final boolean ignoreExcludes, final boolean hasMemoryFileManager, final boolean useModifiedFiles, final boolean requiresSourceRoots, @NullAllowed final Function jfmProvider) { return new ClasspathInfo( bootPath, moduleBootPath, classPath, moduleCompilePath, moduleClassPath, sourcePath, moduleSourcePath, filter, backgroundCompilation, ignoreExcludes, hasMemoryFileManager, useModifiedFiles, requiresSourceRoots, jfmProvider); } // Public methods ---------------------------------------------------------- /** Registers ChangeListener which will be notified about the changes in the classpath. * @param listener The listener to register. */ public void addChangeListener(@NonNull final ChangeListener listener) { listenerList.addChangeListener(listener); } /**Removes ChangeListener from the list of listeners. * @param listener The listener to remove. */ public synchronized void removeChangeListener(@NonNull final ChangeListener listener) { listenerList.removeChangeListener(listener); } public ClassPath getClassPath (@NonNull PathKind pathKind) { switch( pathKind ) { case BOOT: return this.bootClassPath; case MODULE_BOOT: return this.moduleBootPath; case COMPILE: return this.compileClassPath; case MODULE_COMPILE: return this.moduleCompilePath; case MODULE_CLASS: return this.moduleClassPath; case SOURCE: return this.srcClassPath; case MODULE_SOURCE: return this.moduleSrcPath; default: assert false : "Unknown path type"; //NOI18N return null; } } ClassPath getCachedClassPath (PathKind pathKind) { switch( pathKind ) { case BOOT: return this.cachedBootClassPath; case COMPILE: return this.cachedCompileClassPath; case MODULE_COMPILE: return this.cachedModuleCompilePath; case MODULE_CLASS: return this.cachedModuleClassPath; case SOURCE: return this.cachedSrcClassPath; case OUTPUT: return this.outputClassPath; default: assert false : "Unknown path type"; //NOI18N return null; } } public synchronized @NonNull ClassIndex getClassIndex () { if ( usagesQuery == null ) { usagesQuery = new ClassIndex ( this.bootClassPath, this.compileClassPath, this.cachedSrcClassPath); } return usagesQuery; } // Package private methods ------------------------------------------------- @NonNull private synchronized JavaFileManager createFileManager(@NullAllowed final String sourceLevel) { final SiblingSource siblings = SiblingSupport.create(); final ProxyFileManager.Configuration cfg = ProxyFileManager.Configuration.create( moduleBootPath, cachedModuleCompilePath, cachedBootClassPath, moduleCompilePath.entries().isEmpty() ? cachedCompileClassPath : cachedModuleClassPath, srcClassPath, cachedSrcClassPath, moduleSrcPath, outputClassPath, cachedAptSrcClassPath, siblings, fmTx, pgTx); cfg.setFilter(filter); cfg.setIgnoreExcludes(ignoreExcludes); cfg.setUseModifiedFiles(useModifiedFiles); cfg.setCustomFileManagerProvider(jfmProvider); for (Map.Entry>> e : peerProviders.entrySet()) { cfg.setPeers(e.getKey(), e.getValue()); } cfg.setSourceLevel(sourceLevel); return new ProxyFileManager(cfg); } // Private methods --------------------------------------------------------- private void fireChangeListenerStateChanged() { listenerList.fireChange(); } @CheckForNull private static URI[] toURIs(@NullAllowed final ClassPath cp) { if (cp == null) { return null; } final List entries = cp.entries(); final List roots = new ArrayList<>(entries.size()); for (ClassPath.Entry entry : entries) { try { roots.add(entry.getURL().toURI()); } catch (URISyntaxException ex) { log.log( Level.INFO, "Cannot convert {0} to URI.", //NOI18N entry.getURL()); } } return roots.toArray(new URI[0]); } // Innerclasses ------------------------------------------------------------ public static enum PathKind { BOOT, MODULE_BOOT, COMPILE, MODULE_COMPILE, MODULE_CLASS, SOURCE, MODULE_SOURCE, OUTPUT, } private class ClassPathListener implements PropertyChangeListener { @Override public void propertyChange (PropertyChangeEvent event) { if (ClassPath.PROP_ROOTS.equals(event.getPropertyName())) { fireChangeListenerStateChanged(); } } } private static final class Peers implements Function>, PropertyChangeListener { private final ClassPath base; private volatile Map> cache; Peers(@NonNull final ClassPath base) { assert base != null; this.base = base; this.base.addPropertyChangeListener(WeakListeners.propertyChange(this, this.base)); } @Override public Collection apply(URL t) { return getCache().getOrDefault(t, Collections.singleton(t)); } @Override public void propertyChange(PropertyChangeEvent evt) { if (ClassPath.PROP_ENTRIES.equals(evt.getPropertyName())) { cache = null; } } private Map> getCache() { Map> res = cache; if (res == null) { res = new HashMap<>(); final PathRegistry pr = PathRegistry.getDefault(); for (ClassPath.Entry e : base.entries()) { URL[] srcs = pr.sourceForBinaryQuery(e.getURL(), base, false); if (srcs != null) { final Collection cfs = Arrays.stream(srcs) .map((u) -> { try { return BaseUtilities.toURI(JavaIndex.getClassFolder(u)).toURL(); } catch (IOException ioe) { return null; } }) .filter((u) -> u != null) .collect(Collectors.toList()); if (cfs.size() > 1) { for (URL u : cfs) { res.put(u, cfs); } } } } cache = res; } return res; } } private static class ClasspathInfoAccessorImpl extends ClasspathInfoAccessor { @Override @NonNull public JavaFileManager createFileManager( @NonNull final ClasspathInfo cpInfo, @NullAllowed final String sourceLevel) { return cpInfo.createFileManager(sourceLevel); } @Override @NonNull public FileManagerTransaction getFileManagerTransaction(@NonNull ClasspathInfo cpInfo) { return cpInfo.fmTx; } @Override public ClassPath getCachedClassPath(final ClasspathInfo cpInfo, final PathKind kind) { return cpInfo.getCachedClassPath(kind); } @Override public ClasspathInfo create ( @NonNull final ClassPath bootPath, @NonNull final ClassPath moduleBootPath, @NonNull final ClassPath classPath, @NonNull final ClassPath moduleCompilePath, @NonNull final ClassPath moduleClassPath, @NullAllowed final ClassPath sourcePath, @NullAllowed final ClassPath moduleSourcePath, @NullAllowed final JavaFileFilterImplementation filter, final boolean backgroundCompilation, final boolean ignoreExcludes, final boolean hasMemoryFileManager, final boolean useModifiedFiles, final boolean requiresSourceRoots, @NullAllowed final Function jfmProvider) { return ClasspathInfo.create( bootPath, moduleBootPath, classPath, moduleCompilePath, moduleClassPath, sourcePath, moduleSourcePath, filter, backgroundCompilation, ignoreExcludes, hasMemoryFileManager, useModifiedFiles, requiresSourceRoots, jfmProvider); } @Override public ClasspathInfo create (final @NonNull FileObject fo, final JavaFileFilterImplementation filter, final boolean backgroundCompilation, final boolean ignoreExcludes, final boolean hasMemoryFileManager, final boolean useModifiedFiles) { return ClasspathInfo.create(fo, filter, backgroundCompilation, ignoreExcludes, hasMemoryFileManager, useModifiedFiles); } @Override public boolean registerVirtualSource(final ClasspathInfo cpInfo, final InferableJavaFileObject jfo) throws UnsupportedOperationException { if (cpInfo.memoryFileManager == null) { throw new UnsupportedOperationException ("The ClassPathInfo doesn't support memory JavacFileManager"); //NOI18N } return cpInfo.memoryFileManager.register(jfo); } @Override public boolean unregisterVirtualSource(final ClasspathInfo cpInfo, final String fqn) throws UnsupportedOperationException { if (cpInfo.memoryFileManager == null) { throw new UnsupportedOperationException(); } return cpInfo.memoryFileManager.unregister(fqn); } } /** Interface for {@link Task}s that want to provide {@link ClasspathInfo}. The interface is to be implemented * on a {@link Task}, which needs to provide its own classpath information. When the task is run, reinitializes the parser * to use that classpath. * * @since 2.20 */ public interface Provider { public ClasspathInfo getClasspathInfo (); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy