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

io.github.ascopes.jct.utils.SpecialLocationUtils Maven / Gradle / Ivy

/*
 * Copyright (C) 2022 - 2024, 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 io.github.ascopes.jct.utils;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper methods that expose special JVM locations.
 *
 * @author Ashley Scopes
 * @since 0.0.1
 */
public final class SpecialLocationUtils extends UtilityClass {

  // Files we don't want to propagate by default as they may clash with the environment.
  private static final Set BLACKLISTED_FILE_NAMES = Set.of(
      // IntelliJ's idea_rt.jar causes problems on IDEA 2022.3:
      //  - [ERROR] compiler.err.package.clash.from.requires.in.unnamed
      //       the unnamed module reads package com.intellij.rt.execution.junit from both idea.rt
      //       and junit.rt
      //  - [ERROR] compiler.err.package.clash.from.requires
      //       module spring.core reads package com.intellij.rt.execution.junit from both idea.rt
      //       and junit.rt
      "idea_rt.jar"
  );

  private static final Logger log = LoggerFactory.getLogger(SpecialLocationUtils.class);
  private static final String NO_PATH = "";
  private static final URI JAVA_RUNTIME_URI = URI.create("jrt:/");
  private static final String JDK_MODULE_PROPERTY = "jdk.module.path";
  private static final StringSlicer SEPARATOR_SLICER = new StringSlicer(File.pathSeparator);

  private SpecialLocationUtils() {
    // Disallow initialisation.
  }

  /**
   * Get the paths that would be associated with {@link javax.tools.StandardLocation#SYSTEM_MODULES}
   * in the standard compiler implementation of OpenJDK.
   *
   * 

In Java 9 and above, these appear to be stored in a {@code JIMAGE} file located at * {@code ${JAVA_HOME}/lib/modules}. * *

See {@code com.sun.tools.javac.file.JRTIndex} within the {@code jdk.compiler} module to * read the OpenJDK equivalent of this. * * @return a list across the runtime paths. This is always a single element list. */ public static List javaRuntimeLocations() { // Had to do a load of digging around the OpenJDK compiler implementation to work this out, and // I don't know if this will work on all JDK installations yet. return List.of(Path.of(JAVA_RUNTIME_URI).toAbsolutePath()); } /** * Get the classpath of the current JVM. This will usually include any dependencies you may have * loaded into memory, and may refer to directories of {@code *.class} files, {@code *.war} files, * or {@code *.jar} files. * *

This corresponds to the {@link javax.tools.StandardLocation#CLASS_PATH} location. * * @return a list across the normalized, absolute paths. Any duplicates are removed. */ public static List currentClassPathLocations() { return createPaths(ManagementFactory.getRuntimeMXBean().getClassPath()); } /** * Get the module path of the current JVM. This will usually include any dependencies you may have * loaded into memory, and may refer to directories of {@code *.class} files, {@code *.war} files, * or {@code *.jar} files. * *

This corresponds to the {@link javax.tools.StandardLocation#MODULE_PATH} location, but * is also added in the {@link javax.tools.StandardLocation#CLASS_PATH} to handle some otherwise * confusing behaviours. * * @return a list across the normalized, absolute paths. Any duplicates are removed. */ public static List currentModulePathLocations() { return createPaths(System.getProperty(JDK_MODULE_PROPERTY, NO_PATH)); } private static List createPaths(String raw) { return SEPARATOR_SLICER .splitToStream(raw) .filter(SpecialLocationUtils::isNotBlank) .map(Path::of) .filter(SpecialLocationUtils::isNotBlacklistedFile) .map(Path::normalize) .map(Path::toAbsolutePath) // We have to check this, annoyingly, because some tools like Maven (Surefire) will report // paths that don't actually exist to the class path, and Java will just ignore this // normally. It will cause random failures during builds, however, if directories such as // src/main/java do not exist. .distinct() .filter(Files::exists) .collect(Collectors.toUnmodifiableList()); } private static boolean isNotBlank(String string) { return !string.isBlank(); } private static boolean isNotBlacklistedFile(Path path) { var fileName = path.getFileName().toString(); if (BLACKLISTED_FILE_NAMES.contains(fileName)) { log.debug("Excluding {} from path list as it is a blacklisted file", fileName); return false; } return true; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy