com.google.devtools.build.lib.rules.java.JavaTargetAttributes.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.build.lib.rules.java.JavaTargetAttributes.java

Source

// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed 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 com.google.devtools.build.lib.rules.java;

import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.rules.cpp.CppFileTypes;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * An object that captures the temporary state we need to pass around while
 * the initialization hook for a java rule is running.
 */
public class JavaTargetAttributes {

    private static void checkJar(Artifact classPathEntry) {
        if (!JavaSemantics.JAR.matches(classPathEntry.getFilename())) {
            throw new IllegalArgumentException("not a jar file: " + classPathEntry.prettyPrint());
        }
    }

    /**
     * A builder class for JavaTargetAttributes.
     */
    public static class Builder {

        // The order of source files is important, and there must not be duplicates.
        // Unfortunately, there is no interface in Java that represents a collection
        // without duplicates that has a stable and deterministic iteration order,
        // but is not sorted according to a property of the elements. Thus we are
        // stuck with Set.
        private final Set<Artifact> sourceFiles = new LinkedHashSet<>();
        private final Set<Artifact> compileTimeJarFiles = new LinkedHashSet<>();

        private final NestedSetBuilder<Artifact> runtimeClassPath = NestedSetBuilder.naiveLinkOrder();

        private final NestedSetBuilder<Artifact> compileTimeClassPath = NestedSetBuilder.naiveLinkOrder();

        private final List<Artifact> bootClassPath = new ArrayList<>();
        private final List<Artifact> nativeLibraries = new ArrayList<>();

        private final Set<Artifact> processorPath = new LinkedHashSet<>();
        // Classpath directories can't be represented as artifacts (TreeArtifact isn't appropriate
        // here since all we need is a path string to apply to the command line).
        private final Set<PathFragment> processorPathDirs = new LinkedHashSet<>();
        private final Set<String> processorNames = new LinkedHashSet<>();

        private final Set<Artifact> apiGeneratingProcessorPath = new LinkedHashSet<>();
        private final Set<String> apiGeneratingProcessorNames = new LinkedHashSet<>();

        private final Map<PathFragment, Artifact> resources = new LinkedHashMap<>();
        private final NestedSetBuilder<Artifact> resourceJars = NestedSetBuilder.stableOrder();
        private final List<Artifact> messages = new ArrayList<>();
        private final List<Artifact> instrumentationMetadata = new ArrayList<>();
        private final List<Artifact> sourceJars = new ArrayList<>();

        private final List<Artifact> classPathResources = new ArrayList<>();

        private final Set<Artifact> additionalOutputs = new LinkedHashSet<>();

        private BuildConfiguration.StrictDepsMode strictJavaDeps = BuildConfiguration.StrictDepsMode.OFF;
        private final NestedSetBuilder<Artifact> directJars = NestedSetBuilder.naiveLinkOrder();
        private final List<Artifact> compileTimeDependencyArtifacts = new ArrayList<>();
        private String ruleKind;
        private Label targetLabel;

        private final NestedSetBuilder<Artifact> excludedArtifacts = NestedSetBuilder.naiveLinkOrder();

        private boolean built = false;

        private final JavaSemantics semantics;

        public Builder(JavaSemantics semantics) {
            this.semantics = semantics;
        }

        public Builder addSourceArtifacts(Iterable<Artifact> sourceArtifacts) {
            Preconditions.checkArgument(!built);
            for (Artifact srcArtifact : sourceArtifacts) {
                String srcFilename = srcArtifact.getExecPathString();
                if (JavaSemantics.SOURCE_JAR.matches(srcFilename)) {
                    sourceJars.add(srcArtifact);
                } else if (JavaSemantics.PROPERTIES.matches(srcFilename)) {
                    // output files of the message compiler
                    resources.put(semantics.getDefaultJavaResourcePath(srcArtifact.getRootRelativePath()),
                            srcArtifact);
                } else if (JavaSemantics.JAVA_SOURCE.matches(srcFilename)) {
                    sourceFiles.add(srcArtifact);
                } else {
                    // try specific cases from the semantics.
                    semantics.addArtifactToJavaTargetAttribute(this, srcArtifact);
                }
            }
            return this;
        }

        public Builder addSourceFiles(Iterable<Artifact> sourceFiles) {
            Preconditions.checkArgument(!built);
            for (Artifact artifact : sourceFiles) {
                if (JavaSemantics.JAVA_SOURCE.matches(artifact.getFilename())) {
                    this.sourceFiles.add(artifact);
                }
            }
            return this;
        }

        public Builder merge(JavaCompilationArgs context) {
            Preconditions.checkArgument(!built);
            addCompileTimeClassPathEntries(context.getCompileTimeJars());
            addRuntimeClassPathEntries(context.getRuntimeJars());
            addInstrumentationMetadataEntries(context.getInstrumentationMetadata());
            return this;
        }

        public Builder addSourceJars(Collection<Artifact> sourceJars) {
            Preconditions.checkArgument(!built);
            this.sourceJars.addAll(sourceJars);
            return this;
        }

        public Builder addSourceJar(Artifact sourceJar) {
            Preconditions.checkArgument(!built);
            this.sourceJars.add(sourceJar);
            return this;
        }

        public Builder addCompileTimeJarFiles(Iterable<Artifact> jars) {
            Preconditions.checkArgument(!built);
            Iterables.addAll(compileTimeJarFiles, jars);
            return this;
        }

        public Builder addRuntimeClassPathEntry(Artifact classPathEntry) {
            Preconditions.checkArgument(!built);
            checkJar(classPathEntry);
            runtimeClassPath.add(classPathEntry);
            return this;
        }

        public Builder addRuntimeClassPathEntries(NestedSet<Artifact> classPathEntries) {
            Preconditions.checkArgument(!built);
            runtimeClassPath.addTransitive(classPathEntries);
            return this;
        }

        public Builder addCompileTimeClassPathEntries(NestedSet<Artifact> entries) {
            Preconditions.checkArgument(!built);
            compileTimeClassPath.addTransitive(entries);
            return this;
        }

        public Builder setRuleKind(String ruleKind) {
            Preconditions.checkArgument(!built);
            this.ruleKind = ruleKind;
            return this;
        }

        public Builder setTargetLabel(Label targetLabel) {
            Preconditions.checkArgument(!built);
            this.targetLabel = targetLabel;
            return this;
        }

        /**
         * Sets the bootclasspath to be passed to the Java compiler.
         *
         * <p>If this method is called, then the bootclasspath specified in this JavaTargetAttributes
         * instance overrides the default bootclasspath.
         */
        public Builder setBootClassPath(List<Artifact> jars) {
            Preconditions.checkArgument(!built);
            Preconditions.checkArgument(!jars.isEmpty());
            Preconditions.checkState(bootClassPath.isEmpty());
            bootClassPath.addAll(jars);
            return this;
        }

        public Builder addExcludedArtifacts(NestedSet<Artifact> toExclude) {
            Preconditions.checkArgument(!built);
            excludedArtifacts.addTransitive(toExclude);
            return this;
        }

        /**
         * Controls how strict the javac compiler will be in checking correct use of
         * direct dependencies.
         *
         * @param strictDeps one of WARN, ERROR or OFF
         */
        public Builder setStrictJavaDeps(BuildConfiguration.StrictDepsMode strictDeps) {
            Preconditions.checkArgument(!built);
            strictJavaDeps = strictDeps;
            return this;
        }

        /**
         * In tandem with strictJavaDeps, directJars represents a subset of the compile-time, classpath
         * jars that were provided by direct dependencies. When strictJavaDeps is OFF, there is no need
         * to provide directJars, and no extra information is passed to javac. When strictJavaDeps is
         * set to WARN or ERROR, the compiler command line will include extra flags to indicate the
         * warning/error policy and to map the classpath jars to direct or transitive dependencies,
         * using the information in directJars. The extra flags are formatted like this (same for
         * --indirect_dependency): <pre>
         * --direct_dependency
         * foo/bar/lib.jar
         * //java/com/google/foo:bar
         * </pre>
         */
        public Builder addDirectJars(NestedSet<Artifact> directJars) {
            Preconditions.checkArgument(!built);
            this.directJars.addTransitive(directJars);
            return this;
        }

        public Builder addCompileTimeDependencyArtifacts(Iterable<Artifact> dependencyArtifacts) {
            Preconditions.checkArgument(!built);
            Iterables.addAll(this.compileTimeDependencyArtifacts, dependencyArtifacts);
            return this;
        }

        public Builder addInstrumentationMetadataEntries(Iterable<Artifact> metadataEntries) {
            Preconditions.checkArgument(!built);
            Iterables.addAll(instrumentationMetadata, metadataEntries);
            return this;
        }

        public Builder addNativeLibrary(Artifact nativeLibrary) {
            Preconditions.checkArgument(!built);
            String name = nativeLibrary.getFilename();
            if (CppFileTypes.INTERFACE_SHARED_LIBRARY.matches(name)) {
                return this;
            }
            if (!(CppFileTypes.SHARED_LIBRARY.matches(name)
                    || CppFileTypes.VERSIONED_SHARED_LIBRARY.matches(name))) {
                throw new IllegalArgumentException("not a shared library :" + nativeLibrary.prettyPrint());
            }
            nativeLibraries.add(nativeLibrary);
            return this;
        }

        public Builder addNativeLibraries(Iterable<Artifact> nativeLibraries) {
            Preconditions.checkArgument(!built);
            for (Artifact nativeLibrary : nativeLibraries) {
                addNativeLibrary(nativeLibrary);
            }
            return this;
        }

        public Builder addMessages(Collection<Artifact> messages) {
            Preconditions.checkArgument(!built);
            this.messages.addAll(messages);
            return this;
        }

        public Builder addMessage(Artifact messagesArtifact) {
            Preconditions.checkArgument(!built);
            this.messages.add(messagesArtifact);
            return this;
        }

        public Builder addResource(PathFragment execPath, Artifact resource) {
            Preconditions.checkArgument(!built);
            this.resources.put(execPath, resource);
            return this;
        }

        public Builder addResourceJars(NestedSet<Artifact> resourceJars) {
            Preconditions.checkArgument(!built);
            this.resourceJars.addTransitive(resourceJars);
            return this;
        }

        public Builder addProcessorName(String processor) {
            Preconditions.checkArgument(!built);
            processorNames.add(processor);
            return this;
        }

        public Builder addProcessorPath(Iterable<Artifact> jars) {
            Preconditions.checkArgument(!built);
            Iterables.addAll(processorPath, jars);
            return this;
        }

        public Builder addProcessorPathDir(PathFragment dir) {
            Preconditions.checkArgument(!built);
            processorPathDirs.add(dir);
            return this;
        }

        public Builder addApiGeneratingProcessorName(String processor) {
            Preconditions.checkArgument(!built);
            apiGeneratingProcessorNames.add(processor);
            return this;
        }

        public Builder addApiGeneratingProcessorPath(Iterable<Artifact> jars) {
            Preconditions.checkArgument(!built);
            Iterables.addAll(apiGeneratingProcessorPath, jars);
            return this;
        }

        public Builder addClassPathResources(List<Artifact> classPathResources) {
            Preconditions.checkArgument(!built);
            this.classPathResources.addAll(classPathResources);
            return this;
        }

        public Builder addClassPathResource(Artifact classPathResource) {
            Preconditions.checkArgument(!built);
            this.classPathResources.add(classPathResource);
            return this;
        }

        /**
         * Adds additional outputs to this target's compile action.
         */
        public Builder addAdditionalOutputs(Iterable<Artifact> outputs) {
            Preconditions.checkArgument(!built);
            Iterables.addAll(additionalOutputs, outputs);
            return this;
        }

        public JavaTargetAttributes build() {
            built = true;
            return new JavaTargetAttributes(sourceFiles, compileTimeJarFiles, runtimeClassPath,
                    compileTimeClassPath, bootClassPath, nativeLibraries, processorPath, processorPathDirs,
                    processorNames, apiGeneratingProcessorPath, apiGeneratingProcessorNames, resources,
                    resourceJars.build(), messages, sourceJars, classPathResources, additionalOutputs,
                    directJars.build(), compileTimeDependencyArtifacts, ruleKind, targetLabel, excludedArtifacts,
                    strictJavaDeps);
        }

        // TODO(bazel-team): Remove these 5 methods.
        @Deprecated
        public Set<Artifact> getSourceFiles() {
            return sourceFiles;
        }

        @Deprecated
        public boolean hasSourceFiles() {
            return !sourceFiles.isEmpty();
        }

        @Deprecated
        public List<Artifact> getInstrumentationMetadata() {
            return instrumentationMetadata;
        }

        @Deprecated
        public boolean hasSourceJars() {
            return !sourceJars.isEmpty();
        }
    }

    //
    // -------------------------- END OF BUILDER CLASS -------------------------
    //

    private final ImmutableSet<Artifact> sourceFiles;
    private final ImmutableSet<Artifact> compileTimeJarFiles;

    private final NestedSet<Artifact> runtimeClassPath;
    private final NestedSet<Artifact> compileTimeClassPath;

    private final ImmutableList<Artifact> bootClassPath;
    private final ImmutableList<Artifact> nativeLibraries;

    private final ImmutableSet<Artifact> processorPath;
    private final ImmutableSet<PathFragment> processorPathDirs;
    private final ImmutableSet<String> processorNames;

    private final ImmutableSet<Artifact> apiGeneratingProcessorPath;
    private final ImmutableSet<String> apiGeneratingProcessorNames;

    private final ImmutableMap<PathFragment, Artifact> resources;
    private final NestedSet<Artifact> resourceJars;

    private final ImmutableList<Artifact> messages;
    private final ImmutableList<Artifact> sourceJars;

    private final ImmutableList<Artifact> classPathResources;

    private final ImmutableSet<Artifact> additionalOutputs;

    private final NestedSet<Artifact> directJars;
    private final ImmutableList<Artifact> compileTimeDependencyArtifacts;
    private final String ruleKind;
    private final Label targetLabel;

    private final NestedSet<Artifact> excludedArtifacts;
    private final BuildConfiguration.StrictDepsMode strictJavaDeps;

    /** Constructor of JavaTargetAttributes. */
    private JavaTargetAttributes(Set<Artifact> sourceFiles, Set<Artifact> compileTimeJarFiles,
            NestedSetBuilder<Artifact> runtimeClassPath, NestedSetBuilder<Artifact> compileTimeClassPath,
            List<Artifact> bootClassPath, List<Artifact> nativeLibraries, Set<Artifact> processorPath,
            Set<PathFragment> processorPathDirs, Set<String> processorNames,
            Set<Artifact> apiGeneratingProcessorPath, Set<String> apiGeneratingProcessorNames,
            Map<PathFragment, Artifact> resources, NestedSet<Artifact> resourceJars, List<Artifact> messages,
            List<Artifact> sourceJars, List<Artifact> classPathResources, Set<Artifact> additionalOutputs,
            NestedSet<Artifact> directJars, List<Artifact> compileTimeDependencyArtifacts, String ruleKind,
            Label targetLabel, NestedSetBuilder<Artifact> excludedArtifacts,
            BuildConfiguration.StrictDepsMode strictJavaDeps) {
        this.sourceFiles = ImmutableSet.copyOf(sourceFiles);
        this.compileTimeJarFiles = ImmutableSet.copyOf(compileTimeJarFiles);
        this.runtimeClassPath = runtimeClassPath.build();
        this.directJars = directJars;
        this.compileTimeClassPath = NestedSetBuilder.<Artifact>naiveLinkOrder().addTransitive(directJars)
                .addTransitive(compileTimeClassPath.build()).build();
        this.bootClassPath = ImmutableList.copyOf(bootClassPath);
        this.nativeLibraries = ImmutableList.copyOf(nativeLibraries);
        this.processorPath = ImmutableSet.copyOf(processorPath);
        this.processorPathDirs = ImmutableSet.copyOf(processorPathDirs);
        this.processorNames = ImmutableSet.copyOf(processorNames);
        this.apiGeneratingProcessorPath = ImmutableSet.copyOf(apiGeneratingProcessorPath);
        this.apiGeneratingProcessorNames = ImmutableSet.copyOf(apiGeneratingProcessorNames);
        this.resources = ImmutableMap.copyOf(resources);
        this.resourceJars = resourceJars;
        this.messages = ImmutableList.copyOf(messages);
        this.sourceJars = ImmutableList.copyOf(sourceJars);
        this.classPathResources = ImmutableList.copyOf(classPathResources);
        this.additionalOutputs = ImmutableSet.copyOf(additionalOutputs);
        this.compileTimeDependencyArtifacts = ImmutableList.copyOf(compileTimeDependencyArtifacts);
        this.ruleKind = ruleKind;
        this.targetLabel = targetLabel;
        this.excludedArtifacts = excludedArtifacts.build();
        this.strictJavaDeps = strictJavaDeps;
    }

    public NestedSet<Artifact> getDirectJars() {
        return directJars;
    }

    public List<Artifact> getCompileTimeDependencyArtifacts() {
        return compileTimeDependencyArtifacts;
    }

    public List<Artifact> getSourceJars() {
        return sourceJars;
    }

    public Map<PathFragment, Artifact> getResources() {
        return resources;
    }

    public NestedSet<Artifact> getResourceJars() {
        return resourceJars;
    }

    public List<Artifact> getMessages() {
        return messages;
    }

    public ImmutableList<Artifact> getClassPathResources() {
        return classPathResources;
    }

    public ImmutableSet<Artifact> getAdditionalOutputs() {
        return additionalOutputs;
    }

    private NestedSet<Artifact> getExcludedArtifacts() {
        return excludedArtifacts;
    }

    /**
     * Returns the artifacts needed on the runtime classpath of this target.
     *
     * See also {@link #getRuntimeClassPathForArchive()}.
     */
    public NestedSet<Artifact> getRuntimeClassPath() {
        return runtimeClassPath;
    }

    /**
     * Returns the classpath artifacts needed in a deploy jar for this target.
     *
     * This excludes the artifacts made available by jars in the deployment
     * environment.
     */
    public Iterable<Artifact> getRuntimeClassPathForArchive() {
        Iterable<Artifact> runtimeClasspath = getRuntimeClassPath();

        if (getExcludedArtifacts().isEmpty()) {
            return runtimeClasspath;
        } else {
            return Iterables.filter(runtimeClasspath,
                    Predicates.not(Predicates.in(getExcludedArtifacts().toSet())));
        }
    }

    public NestedSet<Artifact> getCompileTimeClassPath() {
        return compileTimeClassPath;
    }

    public ImmutableList<Artifact> getBootClassPath() {
        return bootClassPath;
    }

    public ImmutableSet<Artifact> getProcessorPath() {
        return processorPath;
    }

    public ImmutableSet<PathFragment> getProcessorPathDirs() {
        return processorPathDirs;
    }

    public Collection<Artifact> getApiGeneratingProcessorPath() {
        return apiGeneratingProcessorPath;
    }

    public ImmutableSet<String> getApiGeneratingProcessorNames() {
        return apiGeneratingProcessorNames;
    }

    public Set<Artifact> getSourceFiles() {
        return sourceFiles;
    }

    public Set<Artifact> getCompileTimeJarFiles() {
        return compileTimeJarFiles;
    }

    public List<Artifact> getNativeLibraries() {
        return nativeLibraries;
    }

    public Collection<String> getProcessorNames() {
        return processorNames;
    }

    public boolean hasSourceFiles() {
        return !sourceFiles.isEmpty();
    }

    public boolean hasSourceJars() {
        return !sourceJars.isEmpty();
    }

    public boolean hasResources() {
        return !resources.isEmpty();
    }

    public boolean hasMessages() {
        return !messages.isEmpty();
    }

    public boolean hasClassPathResources() {
        return !classPathResources.isEmpty();
    }

    public String getRuleKind() {
        return ruleKind;
    }

    public Label getTargetLabel() {
        return targetLabel;
    }

    public BuildConfiguration.StrictDepsMode getStrictJavaDeps() {
        return strictJavaDeps;
    }
}