org.aspectj.util.LangUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjweaver Show documentation
Show all versions of aspectjweaver Show documentation
The AspectJ weaver introduces advices to java classes
/* *******************************************************************
* Copyright (c) 1999-2001 Xerox Corporation,
* 2002 Palo Alto Research Center, Incorporated (PARC).
* 2018 Contributors
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* Contributors:
* Xerox/PARC initial implementation
* ******************************************************************/
package org.aspectj.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.security.PrivilegedActionException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/**
*
*/
public class LangUtil {
public static final String EOL = System.lineSeparator();
public static final String JRT_FS = "jrt-fs.jar";
private static double vmVersion;
/**
* @return the vm version (1.1, 1.2, 1.3, 1.4, etc)
*/
public static String getVmVersionString() {
return Double.toString(vmVersion);
}
public static double getVmVersion() {
return vmVersion;
}
static {
// https://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html
// https://openjdk.java.net/jeps/223 "New Version-String Scheme"
// TODO: Use java.lang.Runtime class (since Java 9, now AspectJ needs Java 11+ due to JDT Core anyway)
final String JAVA_VERSION_NOT_FOUND = "System properties appear damaged, cannot find: java.version/java.runtime.version/java.vm.version";
try {
String vm = System.getProperty("java.version"); // JLS 20.18.7
if (vm == null) {
vm = System.getProperty("java.runtime.version");
}
if (vm == null) {
vm = System.getProperty("java.vm.version");
}
if (vm == null) {
new RuntimeException(JAVA_VERSION_NOT_FOUND).printStackTrace(System.err);
vmVersion = 1.5;
} else {
// Care about the first set of digits and second set if first digit is 1
try {
List numbers = getJavaMajorMinor(vm);
if (numbers.get(0) == 1) {
// Old school for 1.0 > 1.8
vmVersion = numbers.get(0)+(numbers.get(1)/10d);
} else {
// numbers.get(0) is the major version (9 and above)
// Note here the number will be 9 (or 10), *not* 1.9 or 1.10
vmVersion = numbers.get(0);
}
} catch (Throwable t) {
// Give up
vmVersion = 1.5;
}
}
} catch (Throwable t) {
new RuntimeException(JAVA_VERSION_NOT_FOUND, t).printStackTrace(System.err);
vmVersion = 1.5;
}
}
private static List getJavaMajorMinor(String vm) {
List result = new ArrayList<>();
// Can be something like '1.5', '11.0.16.1', '19+36-2238'
StringTokenizer st = new StringTokenizer(vm.replaceFirst("[+].*", ""), ".-_");
try {
result.add(Integer.parseInt(st.nextToken()));
result.add(Integer.parseInt(st.nextToken()));
} catch (Exception e) {
// NoSuchElementException if no more tokens
// NumberFormatException if not a number
}
// Always add a default minor, just in case a caller expects it
if (result.size() == 1)
result.add(0);
return result;
}
public static boolean isVMGreaterOrEqual(int javaVersion) {
return isVMGreaterOrEqual((double) javaVersion);
}
public static boolean isVMGreaterOrEqual(double javaVersion) {
return vmVersion >= javaVersion;
}
public static boolean isVMLessOrEqual(int javaVersion) {
return isVMLessOrEqual((double) javaVersion);
}
public static boolean isVMLessOrEqual(double javaVersion) {
return vmVersion <= javaVersion;
}
/**
* Shorthand for "if null, throw IllegalArgumentException"
*
* @throws IllegalArgumentException "null {name}" if o is null
*/
public static final void throwIaxIfNull(final Object o, final String name) {
if (null == o) {
String message = "null " + (null == name ? "input" : name);
throw new IllegalArgumentException(message);
}
}
/**
* Shorthand for "if not null or not assignable, throw IllegalArgumentException"
*
* @param c the Class to check - use null to ignore type check
* @throws IllegalArgumentException "null {name}" if o is null
*/
public static final void throwIaxIfNotAssignable(final Object ra[], final Class> c, final String name) {
throwIaxIfNull(ra, name);
String label = (null == name ? "input" : name);
for (int i = 0; i < ra.length; i++) {
if (null == ra[i]) {
String m = " null " + label + "[" + i + "]";
throw new IllegalArgumentException(m);
} else if (null != c) {
Class> actualClass = ra[i].getClass();
if (!c.isAssignableFrom(actualClass)) {
String message = label + " not assignable to " + c.getName();
throw new IllegalArgumentException(message);
}
}
}
}
/**
* Shorthand for "if not null or not assignable, throw IllegalArgumentException"
*
* @throws IllegalArgumentException "null {name}" if o is null
*/
public static final void throwIaxIfNotAssignable(final Object o, final Class> c, final String name) {
throwIaxIfNull(o, name);
if (null != c) {
Class> actualClass = o.getClass();
if (!c.isAssignableFrom(actualClass)) {
String message = name + " not assignable to " + c.getName();
throw new IllegalArgumentException(message);
}
}
}
// /**
// * Shorthand for
// "if any not null or not assignable, throw IllegalArgumentException"
// * @throws IllegalArgumentException "{name} is not assignable to {c}"
// */
// public static final void throwIaxIfNotAllAssignable(final Collection
// collection,
// final Class c, final String name) {
// throwIaxIfNull(collection, name);
// if (null != c) {
// for (Iterator iter = collection.iterator(); iter.hasNext();) {
// throwIaxIfNotAssignable(iter.next(), c, name);
//
// }
// }
// }
/**
* Shorthand for "if false, throw IllegalArgumentException"
*
* @throws IllegalArgumentException "{message}" if test is false
*/
public static final void throwIaxIfFalse(final boolean test, final String message) {
if (!test) {
throw new IllegalArgumentException(message);
}
}
// /** @return ((null == s) || (0 == s.trim().length())); */
// public static boolean isEmptyTrimmed(String s) {
// return ((null == s) || (0 == s.length())
// || (0 == s.trim().length()));
// }
/** @return ((null == s) || (0 == s.length())); */
public static boolean isEmpty(String s) {
return ((null == s) || (0 == s.length()));
}
/** @return ((null == ra) || (0 == ra.length)) */
public static boolean isEmpty(Object[] ra) {
return ((null == ra) || (0 == ra.length));
}
/** @return ((null == ra) || (0 == ra.length)) */
public static boolean isEmpty(byte[] ra) {
return ((null == ra) || (0 == ra.length));
}
/** @return ((null == collection) || (0 == collection.size())) */
public static boolean isEmpty(Collection> collection) {
return ((null == collection) || (0 == collection.size()));
}
/** @return ((null == map) || (0 == map.size())) */
public static boolean isEmpty(Map,?> map) {
return ((null == map) || (0 == map.size()));
}
/**
* Splits text
at whitespace.
*
* @param text String
to split.
*/
public static String[] split(String text) {
return strings(text).toArray(new String[0]);
}
/**
* Splits input
at commas, trimming any white space.
*
* @param input String
to split.
* @return List of String of elements.
*/
public static List commaSplit(String input) {
return anySplit(input, ",");
}
/**
* Split string as classpath, delimited at File.pathSeparator. Entries are not trimmed, but empty entries are ignored.
*
* @param classpath the String to split - may be null or empty
* @return String[] of classpath entries
*/
public static String[] splitClasspath(String classpath) {
if (LangUtil.isEmpty(classpath)) {
return new String[0];
}
StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator);
ArrayList result = new ArrayList<>(st.countTokens());
while (st.hasMoreTokens()) {
String entry = st.nextToken();
if (!LangUtil.isEmpty(entry)) {
result.add(entry);
}
}
return result.toArray(new String[0]);
}
/**
* Get System property as boolean, but use default value where the system property is not set.
*
* @return true if value is set to true, false otherwise
*/
public static boolean getBoolean(String propertyName, boolean defaultValue) {
if (null != propertyName) {
try {
String value = System.getProperty(propertyName);
if (null != value) {
return Boolean.parseBoolean(value);
}
} catch (Throwable t) {
// default below
}
}
return defaultValue;
}
/**
* Splits input
, removing delimiter and trimming any white space. Returns an empty collection if the input is null.
* If delimiter is null or empty or if the input contains no delimiters, the input itself is returned after trimming white
* space.
*
* @param input String
to split.
* @param delim String
separators for input.
* @return List of String of elements.
*/
public static List anySplit(String input, String delim) {
if (null == input) {
return Collections.emptyList();
}
List result = new ArrayList<>();
if (LangUtil.isEmpty(delim) || (!input.contains(delim))) {
result.add(input.trim());
} else {
StringTokenizer st = new StringTokenizer(input, delim);
while (st.hasMoreTokens()) {
result.add(st.nextToken().trim());
}
}
return result;
}
/**
* Splits strings into a List
using a StringTokenizer
.
*
* @param text String
to split.
*/
public static List strings(String text) {
if (LangUtil.isEmpty(text)) {
return Collections.emptyList();
}
List strings = new ArrayList<>();
StringTokenizer tok = new StringTokenizer(text);
while (tok.hasMoreTokens()) {
strings.add(tok.nextToken());
}
return strings;
}
/** @return a non-null unmodifiable List */
public static List safeList(List list) {
return (null == list ? Collections.emptyList() : Collections.unmodifiableList(list));
}
// /**
// * Select from input String[] based on suffix-matching
// * @param inputs String[] of input - null ignored
// * @param suffixes String[] of suffix selectors - null ignored
// * @param ignoreCase if true, ignore case
// * @return String[] of input that end with any input
// */
// public static String[] endsWith(String[] inputs, String[] suffixes,
// boolean ignoreCase) {
// if (LangUtil.isEmpty(inputs) || LangUtil.isEmpty(suffixes)) {
// return new String[0];
// }
// if (ignoreCase) {
// String[] temp = new String[suffixes.length];
// for (int i = 0; i < temp.length; i++) {
// String suff = suffixes[i];
// temp[i] = (null == suff ? null : suff.toLowerCase());
// }
// suffixes = temp;
// }
// ArrayList result = new ArrayList();
// for (int i = 0; i < inputs.length; i++) {
// String input = inputs[i];
// if (null == input) {
// continue;
// }
// if (!ignoreCase) {
// input = input.toLowerCase();
// }
// for (int j = 0; j < suffixes.length; j++) {
// String suffix = suffixes[j];
// if (null == suffix) {
// continue;
// }
// if (input.endsWith(suffix)) {
// result.add(input);
// break;
// }
// }
// }
// return (String[]) result.toArray(new String[0]);
// }
//
// /**
// * Select from input String[] if readable directories
// * @param inputs String[] of input - null ignored
// * @param baseDir the base directory of the input
// * @return String[] of input that end with any input
// */
// public static String[] selectDirectories(String[] inputs, File baseDir) {
// if (LangUtil.isEmpty(inputs)) {
// return new String[0];
// }
// ArrayList result = new ArrayList();
// for (int i = 0; i < inputs.length; i++) {
// String input = inputs[i];
// if (null == input) {
// continue;
// }
// File inputFile = new File(baseDir, input);
// if (inputFile.canRead() && inputFile.isDirectory()) {
// result.add(input);
// }
// }
// return (String[]) result.toArray(new String[0]);
// }
/**
* copy non-null two-dimensional String[][]
*
* @see extractOptions(String[], String[][])
*/
public static String[][] copyStrings(String[][] in) {
String[][] out = new String[in.length][];
for (int i = 0; i < out.length; i++) {
out[i] = new String[in[i].length];
System.arraycopy(in[i], 0, out[i], 0, out[i].length);
}
return out;
}
/**
* Extract options and arguments to input option list, returning remainder. The input options will be nullified if not found.
* e.g.,
*
*
* String[] options = new String[][] { new String[] { "-verbose" }, new String[] { "-classpath", null } };
* String[] args = extractOptions(args, options);
* boolean verbose = null != options[0][0];
* boolean classpath = options[1][1];
*
*
* @param args the String[] input options
* @param options the String[][]options to find in the input args - not null for each String[] component the first subcomponent
* is the option itself, and there is one String subcomponent for each additional argument.
* @return String[] of args remaining after extracting options to extracted
*/
public static String[] extractOptions(String[] args, String[][] options) {
if (LangUtil.isEmpty(args) || LangUtil.isEmpty(options)) {
return args;
}
BitSet foundSet = new BitSet();
String[] result = new String[args.length];
int resultIndex = 0;
for (int j = 0; j < args.length; j++) {
boolean found = false;
for (int i = 0; !found && (i < options.length); i++) {
String[] option = options[i];
LangUtil.throwIaxIfFalse(!LangUtil.isEmpty(option), "options");
String sought = option[0];
found = sought.equals(args[j]);
if (found) {
foundSet.set(i);
int doMore = option.length - 1;
if (0 < doMore) {
final int MAX = j + doMore;
if (MAX >= args.length) {
String s = "expecting " + doMore + " args after ";
throw new IllegalArgumentException(s + args[j]);
}
for (int k = 1; k < option.length; k++) {
option[k] = args[++j];
}
}
}
}
if (!found) {
result[resultIndex++] = args[j];
}
}
// unset any not found
for (int i = 0; i < options.length; i++) {
if (!foundSet.get(i)) {
options[i][0] = null;
}
}
// fixup remainder
if (resultIndex < args.length) {
String[] temp = new String[resultIndex];
System.arraycopy(result, 0, temp, 0, resultIndex);
args = temp;
}
return args;
}
//
// /**
// * Extract options and arguments to input parameter list, returning
// remainder.
// * @param args the String[] input options
// * @param validOptions the String[] options to find in the input args -
// not null
// * @param optionArgs the int[] number of arguments for each option in
// validOptions
// * (if null, then no arguments for any option)
// * @param extracted the List for the matched options
// * @return String[] of args remaining after extracting options to
// extracted
// */
// public static String[] extractOptions(String[] args, String[]
// validOptions,
// int[] optionArgs, List extracted) {
// if (LangUtil.isEmpty(args)
// || LangUtil.isEmpty(validOptions) ) {
// return args;
// }
// if (null != optionArgs) {
// if (optionArgs.length != validOptions.length) {
// throw new IllegalArgumentException("args must match options");
// }
// }
// String[] result = new String[args.length];
// int resultIndex = 0;
// for (int j = 0; j < args.length; j++) {
// boolean found = false;
// for (int i = 0; !found && (i < validOptions.length); i++) {
// String sought = validOptions[i];
// int doMore = (null == optionArgs ? 0 : optionArgs[i]);
// if (LangUtil.isEmpty(sought)) {
// continue;
// }
// found = sought.equals(args[j]);
// if (found) {
// if (null != extracted) {
// extracted.add(sought);
// }
// if (0 < doMore) {
// final int MAX = j + doMore;
// if (MAX >= args.length) {
// String s = "expecting " + doMore + " args after ";
// throw new IllegalArgumentException(s + args[j]);
// }
// if (null != extracted) {
// while (j < MAX) {
// extracted.add(args[++j]);
// }
// } else {
// j = MAX;
// }
// }
// break;
// }
// }
// if (!found) {
// result[resultIndex++] = args[j];
// }
// }
// if (resultIndex < args.length) {
// String[] temp = new String[resultIndex];
// System.arraycopy(result, 0, temp, 0, resultIndex);
// args = temp;
// }
// return args;
// }
// /** @return String[] of entries in validOptions found in args */
// public static String[] selectOptions(String[] args, String[]
// validOptions) {
// if (LangUtil.isEmpty(args) || LangUtil.isEmpty(validOptions)) {
// return new String[0];
// }
// ArrayList result = new ArrayList();
// for (int i = 0; i < validOptions.length; i++) {
// String sought = validOptions[i];
// if (LangUtil.isEmpty(sought)) {
// continue;
// }
// for (int j = 0; j < args.length; j++) {
// if (sought.equals(args[j])) {
// result.add(sought);
// break;
// }
// }
// }
// return (String[]) result.toArray(new String[0]);
// }
// /** @return String[] of entries in validOptions found in args */
// public static String[] selectOptions(List args, String[] validOptions) {
// if (LangUtil.isEmpty(args) || LangUtil.isEmpty(validOptions)) {
// return new String[0];
// }
// ArrayList result = new ArrayList();
// for (int i = 0; i < validOptions.length; i++) {
// String sought = validOptions[i];
// if (LangUtil.isEmpty(sought)) {
// continue;
// }
// for (Iterator iter = args.iterator(); iter.hasNext();) {
// String arg = (String) iter.next();
// if (sought.equals(arg)) {
// result.add(sought);
// break;
// }
// }
// }
// return (String[]) result.toArray(new String[0]);
// }
// /**
// * Generate variants of String[] options by creating an extra set for
// * each option that ends with "-". If none end with "-", then an
// * array equal to new String[][] { options }
is returned;
// * if one ends with "-", then two sets are returned,
// * three causes eight sets, etc.
// * @return String[][] with each option set.
// * @throws IllegalArgumentException if any option is null or empty.
// */
// public static String[][] optionVariants(String[] options) {
// if ((null == options) || (0 == options.length)) {
// return new String[][] { new String[0]};
// }
// // be nice, don't stomp input
// String[] temp = new String[options.length];
// System.arraycopy(options, 0, temp, 0, temp.length);
// options = temp;
// boolean[] dup = new boolean[options.length];
// int numDups = 0;
//
// for (int i = 0; i < options.length; i++) {
// String option = options[i];
// if (LangUtil.isEmpty(option)) {
// throw new IllegalArgumentException("empty option at " + i);
// }
// if (option.endsWith("-")) {
// options[i] = option.substring(0, option.length()-1);
// dup[i] = true;
// numDups++;
// }
// }
// final String[] NONE = new String[0];
// final int variants = exp(2, numDups);
// final String[][] result = new String[variants][];
// // variant is a bitmap wrt doing extra value when dup[k]=true
// for (int variant = 0; variant < variants; variant++) {
// ArrayList next = new ArrayList();
// int nextOption = 0;
// for (int k = 0; k < options.length; k++) {
// if (!dup[k] || (0 != (variant & (1 << (nextOption++))))) {
// next.add(options[k]);
// }
// }
// result[variant] = (String[]) next.toArray(NONE);
// }
// return result;
// }
//
// private static int exp(int base, int power) { // not in Math?
// if (0 > power) {
// throw new IllegalArgumentException("negative power: " + power);
// }
// int result = 1;
// while (0 < power--) {
// result *= base;
// }
// return result;
// }
// /**
// * Make a copy of the array.
// * @return an array with the same component type as source
// * containing same elements, even if null.
// * @throws IllegalArgumentException if source is null
// */
// public static final Object[] copy(Object[] source) {
// LangUtil.throwIaxIfNull(source, "source");
// final Class c = source.getClass().getComponentType();
// Object[] result = (Object[]) Array.newInstance(c, source.length);
// System.arraycopy(source, 0, result, 0, result.length);
// return result;
// }
/**
* Convert arrays safely. The number of elements in the result will be 1 smaller for each element that is null or not
* assignable. This will use sink if it has exactly the right size. The result will always have the same component type as sink.
*
* @return an array with the same component type as sink containing any assignable elements in source (in the same order).
* @throws IllegalArgumentException if either is null
*/
public static Object[] safeCopy(Object[] source, Object[] sink) {
final Class> sinkType = (null == sink ? Object.class : sink.getClass().getComponentType());
final int sourceLength = (null == source ? 0 : source.length);
final int sinkLength = (null == sink ? 0 : sink.length);
final int resultSize;
List