001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.lang3; 018 019import java.util.Objects; 020 021/** 022 * Operations regarding the classpath. 023 * 024 * <p> 025 * The methods of this class do not allow {@code null} inputs. 026 * </p> 027 * 028 * @since 3.3 029 */ 030//@Immutable 031public class ClassPathUtils { 032 033 /** 034 * Gets the package name of the context class. 035 * <p> 036 * Returns an empty string for an unnamed package, including when {@link Class#getPackage()} returns {@code null} on Java 8. 037 * </p> 038 * 039 * @param context The context class, must not be {@code null}. 040 * @return The package name, or an empty string for an unnamed package. 041 * @throws NullPointerException Thrown if {@code context} is null, represents an array, a primitive type or {@code void}, or represents a named class whose 042 * package is unavailable. 043 */ 044 private static String getPackageName(final Class<?> context) { 045 final Package contextPackage = context.getPackage(); 046 if (contextPackage == null && !context.isArray() && !context.isPrimitive() && context.getName().indexOf('.') < 0) { 047 return StringUtils.EMPTY; 048 } 049 return Objects.requireNonNull(contextPackage, "context").getName(); 050 } 051 052 /** 053 * Converts a package name to a Java path ('/'). 054 * 055 * @param path The source path. 056 * @return A package name. 057 * @throws NullPointerException Thrown if {@code path} is null. 058 * @since 3.13.0 059 */ 060 public static String packageToPath(final String path) { 061 return Objects.requireNonNull(path, "path").replace('.', '/'); 062 } 063 064 /** 065 * Converts a Java path ('/') to a package name. 066 * 067 * @param path The source path. 068 * @return A package name. 069 * @throws NullPointerException Thrown if {@code path} is null. 070 * @since 3.13.0 071 */ 072 public static String pathToPackage(final String path) { 073 return Objects.requireNonNull(path, "path").replace('/', '.'); 074 } 075 076 /** 077 * Qualifies a resource name with a prefix and separator. 078 * <p> 079 * Returns {@code resourceName} unchanged when the prefix is empty. 080 * </p> 081 * 082 * @param prefix The package name or path, must not be {@code null}. 083 * @param resourceName The resource name, validated as non-null by the caller. 084 * @param separator The separator between the prefix and resource name. 085 * @return The qualified resource name, or the unchanged resource name when the prefix is empty. 086 * @throws NullPointerException Thrown if {@code prefix} is null. 087 */ 088 private static String qualify(final String prefix, final String resourceName, final char separator) { 089 return prefix.isEmpty() ? resourceName : prefix + separator + resourceName; 090 } 091 092 /** 093 * Returns the fully qualified name for the resource with name {@code resourceName} relative to the given context. 094 * 095 * <p> 096 * Note that this method does not check whether the resource actually exists. It only constructs the name. Null inputs are not allowed. 097 * </p> 098 * 099 * <p> 100 * If the context class is in an unnamed package, returns {@code resourceName} unchanged. 101 * </p> 102 * 103 * <pre> 104 * ClassPathUtils.toFullyQualifiedName(StringUtils.class, "StringUtils.properties") = "org.apache.commons.lang3.StringUtils.properties" 105 * </pre> 106 * 107 * @param context The context for constructing the name. 108 * @param resourceName The resource name to construct the fully qualified name for. 109 * @return The fully qualified name of the resource with name {@code resourceName}. 110 * @throws NullPointerException Thrown if either {@code context} or {@code resourceName} is null, if {@code context} represents an array, a primitive 111 * type or {@code void}, or if it represents a named class whose package is unavailable. 112 */ 113 public static String toFullyQualifiedName(final Class<?> context, final String resourceName) { 114 Objects.requireNonNull(context, "context"); 115 Objects.requireNonNull(resourceName, "resourceName"); 116 return qualify(getPackageName(context), resourceName, '.'); 117 } 118 119 /** 120 * Returns the fully qualified name for the resource with name {@code resourceName} relative to the given context. 121 * 122 * <p> 123 * Note that this method does not check whether the resource actually exists. It only constructs the name. Null inputs are not allowed. 124 * </p> 125 * 126 * <p> 127 * If the context is an unnamed package, returns {@code resourceName} unchanged. 128 * </p> 129 * 130 * <pre> 131 * ClassPathUtils.toFullyQualifiedName(StringUtils.class.getPackage(), "StringUtils.properties") = "org.apache.commons.lang3.StringUtils.properties" 132 * </pre> 133 * 134 * @param context The context for constructing the name. 135 * @param resourceName The resource name to construct the fully qualified name for. 136 * @return The fully qualified name of the resource with name {@code resourceName}. 137 * @throws NullPointerException Thrown if either {@code context} or {@code resourceName} is null. 138 */ 139 public static String toFullyQualifiedName(final Package context, final String resourceName) { 140 Objects.requireNonNull(context, "context"); 141 Objects.requireNonNull(resourceName, "resourceName"); 142 return qualify(context.getName(), resourceName, '.'); 143 } 144 145 /** 146 * Returns the fully qualified path for the resource with name {@code resourceName} relative to the given context. 147 * 148 * <p> 149 * Note that this method does not check whether the resource actually exists. It only constructs the path. Null inputs are not allowed. 150 * </p> 151 * 152 * <p> 153 * If the context class is in an unnamed package, returns {@code resourceName} unchanged. 154 * </p> 155 * 156 * <pre> 157 * ClassPathUtils.toFullyQualifiedPath(StringUtils.class, "StringUtils.properties") = "org/apache/commons/lang3/StringUtils.properties" 158 * </pre> 159 * 160 * @param context The context for constructing the path. 161 * @param resourceName The resource name to construct the fully qualified path for. 162 * @return The fully qualified path of the resource with name {@code resourceName}. 163 * @throws NullPointerException Thrown if either {@code context} or {@code resourceName} is null, if {@code context} represents an array, a primitive 164 * type or {@code void}, or if it represents a named class whose package is unavailable. 165 */ 166 public static String toFullyQualifiedPath(final Class<?> context, final String resourceName) { 167 Objects.requireNonNull(context, "context"); 168 Objects.requireNonNull(resourceName, "resourceName"); 169 return qualify(packageToPath(getPackageName(context)), resourceName, '/'); 170 } 171 172 /** 173 * Returns the fully qualified path for the resource with name {@code resourceName} relative to the given context. 174 * 175 * <p> 176 * Note that this method does not check whether the resource actually exists. It only constructs the path. Null inputs are not allowed. 177 * </p> 178 * 179 * <p> 180 * If the context is an unnamed package, returns {@code resourceName} unchanged. 181 * </p> 182 * 183 * <pre> 184 * ClassPathUtils.toFullyQualifiedPath(StringUtils.class.getPackage(), "StringUtils.properties") = "org/apache/commons/lang3/StringUtils.properties" 185 * </pre> 186 * 187 * @param context The context for constructing the path. 188 * @param resourceName The resource name to construct the fully qualified path for. 189 * @return The fully qualified path of the resource with name {@code resourceName}. 190 * @throws NullPointerException Thrown if either {@code context} or {@code resourceName} is null. 191 */ 192 public static String toFullyQualifiedPath(final Package context, final String resourceName) { 193 Objects.requireNonNull(context, "context"); 194 Objects.requireNonNull(resourceName, "resourceName"); 195 return qualify(packageToPath(context.getName()), resourceName, '/'); 196 } 197 198 /** 199 * {@link ClassPathUtils} instances should NOT be constructed in standard programming. Instead, the class should be used as 200 * {@code ClassPathUtils.toFullyQualifiedName(MyClass.class, "MyClass.properties");}. 201 * 202 * <p> 203 * This constructor is public to permit tools that require a JavaBean instance to operate. 204 * </p> 205 * 206 * @deprecated TODO Make private in 4.0. 207 */ 208 @Deprecated 209 public ClassPathUtils() { 210 // empty 211 } 212 213}