/* * Copyright 2012-2017 the original author or authors. * * 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 org.springframework.boot.gradle.tasks.bundling; import java.io.File; import java.util.Collections; import java.util.concurrent.Callable; import org.gradle.api.Action; import org.gradle.api.file.CopySpec; import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileCopyDetails; import org.gradle.api.file.FileTreeElement; import org.gradle.api.internal.file.copy.CopyAction; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.bundling.Jar; /** * A custom {@link Jar} task that produces a Spring Boot executable jar. * * @author Andy Wilkinson * @since 2.0.0 */ public class BootJar extends Jar implements BootArchive { private BootArchiveSupport support = new BootArchiveSupport( "org.springframework.boot.loader.JarLauncher", this::resolveZipCompression); private FileCollection classpath; private String mainClass; /** * Creates a new {@code BootJar} task. */ public BootJar() { CopySpec bootInf = getRootSpec().addChildBeforeSpec(getMainSpec()) .into("BOOT-INF"); bootInf.into("lib", classpathFiles(File::isFile)); bootInf.into("classes", classpathFiles(File::isDirectory)); } private Action<CopySpec> classpathFiles(Spec<File> filter) { return copySpec -> copySpec .from((Callable<Iterable<File>>) () -> this.classpath == null ? Collections.emptyList() : this.classpath.filter(filter)); } @Override public void copy() { this.support.configureManifest(this, getMainClass()); super.copy(); } @Override protected CopyAction createCopyAction() { return this.support.createCopyAction(this); } @Override public String getMainClass() { return this.mainClass; } @Override public void setMainClass(String mainClass) { this.mainClass = mainClass; } @Override public void requiresUnpack(String... patterns) { this.support.requiresUnpack(patterns); } @Override public void requiresUnpack(Spec<FileTreeElement> spec) { this.support.requiresUnpack(spec); } @Override public LaunchScriptConfiguration getLaunchScript() { return this.support.getLaunchScript(); } @Override public void launchScript(Action<LaunchScriptConfiguration> action) { action.execute(getLaunchScript()); } @Override public FileCollection getClasspath() { return this.classpath; } @Override public void classpath(Object... classpath) { FileCollection existingClasspath = this.classpath; this.classpath = getProject().files( existingClasspath == null ? Collections.emptyList() : existingClasspath, classpath); } @Override public boolean isExcludeDevtools() { return this.support.isExcludeDevtools(); } @Override public void setExcludeDevtools(boolean excludeDevtools) { this.support.setExcludeDevtools(excludeDevtools); } /** * Returns the {@link ZipCompression} that should be used when adding the file * represented by the given {@code details} to the jar. * <p> * By default, any file in {@code BOOT-INF/lib/} is stored and all other files are * deflated. * * @param details the details * @return the compression to use */ protected ZipCompression resolveZipCompression(FileCopyDetails details) { if (details.getRelativePath().getPathString().startsWith("BOOT-INF/lib/")) { return ZipCompression.STORED; } return ZipCompression.DEFLATED; } }