/* * Copyright 2014-present Facebook, Inc. * * 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.facebook.buck.cli.bootstrapper; import java.io.File; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Paths; import java.util.Arrays; /** * This class sets up a separate ClassLoader for most of Buck's implementation, leaving only the * bare minimum bootstrapping classes (and a few classes for compatibility with library code that is * not ClassLoader-aware) in the system ClassLoader. This is done so that annotation processors do * not have their classpaths polluted with Buck's dependencies when Buck is compiling Java code * in-process. * * <p>Under JSR-199, when the Java compiler is run in-process it uses a ClassLoader that is a child * of the system ClassLoader. In order for annotation processors to access the Compiler Tree API * (which lives in tools.jar with the compiler itself), they must be loaded with a ClassLoader * descended from the compiler's. If Buck used the system ClassLoader as a normal Java application * would, this would result in annotation processors getting Buck's versions of Guava, Jackson, etc. * instead of their own. */ public final class ClassLoaderBootstrapper { private static ClassLoader classLoader; private ClassLoaderBootstrapper() {} public static void main(String[] args) throws Exception { String classPath = System.getenv("BUCK_CLASSPATH"); if (classPath == null) { throw new RuntimeException("BUCK_CLASSPATH not set"); } String mainClassName = args[0]; String[] remainingArgs = Arrays.copyOfRange(args, 1, args.length); classLoader = createClassLoader(classPath); // Some things (notably Jetty) use the context class loader to load stuff Thread.currentThread().setContextClassLoader(classLoader); Class<?> mainClass = classLoader.loadClass(mainClassName); Method mainMethod = mainClass.getMethod("main", String[].class); mainMethod.invoke(null, (Object) remainingArgs); } public static Class<?> loadClass(String name) { try { return classLoader.loadClass(name); } catch (ClassNotFoundException e) { throw new NoClassDefFoundError(name); } } private static ClassLoader createClassLoader(String classPath) throws MalformedURLException { String[] strings = classPath.split(File.pathSeparator); URL[] urls = new URL[strings.length]; for (int i = 0; i < urls.length; i++) { urls[i] = Paths.get(strings[i]).toUri().toURL(); } return new URLClassLoader(urls); } }