org.apache.brooklyn.util.javalang.JavaClassNames Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of brooklyn-utils-common Show documentation
Show all versions of brooklyn-utils-common Show documentation
Utility classes and methods developed for Brooklyn but not dependendent on Brooklyn or much else
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.brooklyn.util.javalang;
import java.util.Iterator;
import java.util.Map;
import org.apache.brooklyn.util.net.Urls;
import org.apache.brooklyn.util.text.Strings;
import com.google.common.base.Preconditions;
import com.google.common.reflect.TypeToken;
public class JavaClassNames {
private static final StackTraceSimplifier STACK_TRACE_SIMPLIFIER_EXCLUDING_UTIL_JAVALANG =
StackTraceSimplifier.newInstance(StackTraceSimplifier.class.getPackage().getName()+".");
/** returns the Class of anything which isn't a class; if input is class it is pass-through */
public static Class type(Object x) {
if (x==null) return null;
if (x instanceof Class) return (Class)x;
if (x instanceof TypeToken) return ((TypeToken)x).getRawType();
return x.getClass();
}
/** like type, but removes any array modifiers */
public static Class componentType(Object x) {
Class c = type(x);
if (c==null) return null;
while (c.isArray()) {
c = c.getComponentType();
}
return c;
}
/** as {@link #simpleClassName(Class)} but returning json types if appropriate,
* e.g. `map`, `string`, etc; else falling back to detailed type */
public static String superSimpleClassName(Class t) {
if (Map.class.isAssignableFrom(t)) return "map";
if (Iterable.class.isAssignableFrom(t) || Iterator.class.isAssignableFrom(t) ||
t.isArray()) return "list";
if (CharSequence.class.isAssignableFrom(t)) return "string";
if (Number.class.isAssignableFrom(t)) return "number";
if (Boolean.class.isAssignableFrom(t)) return "boolean";
return simpleClassName(t);
}
/** as {@link #simpleClassName(Object)} but looking up the type if needed */
public static String superSimpleClassName(Object o) {
return superSimpleClassName(type(o));
}
/** returns a simplified name of the class, just the simple name if it seems useful, else the full name */
public static String simpleClassName(Class t) {
if (t==null) return null;
int arrayCount = 0;
while (t.isArray()) {
arrayCount++;
t = t.getComponentType();
}
Class ct = componentType(t);
String result = ct.getSimpleName();
if (Strings.isBlank(result) || result.length()<=4) {
result = ct.getName();
}
return result+Strings.repeat("[]", arrayCount);
}
/** as {@link #simpleClassName(Class)} but if something is an inner class it drops everything before the $ */
public static String verySimpleClassName(Class t) {
t = componentType(t);
String result = t.getSimpleName();
result = result.substring(result.lastIndexOf('.')+1);
result = result.substring(result.lastIndexOf('$')+1);
if (Strings.isBlank(result)) {
result = t.getName();
}
return result;
}
/** as {@link #simpleClassName(Class)} but taking the type of the object if it is not already a class
* or a type-token; callers should usually do the getClass themselves, unless they aren't sure whether
* it is already a Class-type object */
public static String simpleClassName(Object x) {
return simpleClassName(type(x));
}
/** as {@link #simpleClassName(Class)} but taking a string rep'n of the class name,
* and doing best effort to simplify it (without instantiating) */
public static String simplifyClassName(String className) {
if (className==null) return null;
int lastDot = className.lastIndexOf('.');
if (lastDot < className.length()-5)
return className.substring(lastDot+1);
return className;
}
/** as {@link #simpleClassName(Object)} but making the result clean for use on filesystems and as java identifiers */
public static String cleanSimpleClassName(Object x) {
return Strings.makeValidFilename(simpleClassName(x));
}
/** as {@link #simpleClassName(Object)} but making the result clean for use on filesystems and as java identifiers */
public static String cleanSimpleClassName(Class x) {
return Strings.makeValidFilename(simpleClassName(x));
}
public static String packageName(Object x) {
return componentType(x).getPackage().getName();
}
/** returns e.g. "/com/acme/" for an object in package com.acme */
public static String packagePath(Object x) {
return Urls.mergePaths("/", componentType(x).getPackage().getName().replace('.', '/'), "/");
}
/** returns path relative to the package of x, unless path is absolute.
* useful to mimic Class.getResource(path) behaviour, cf Class.resolveName where the first argument below is the class. */
public static String resolveName(Object context, String path) {
Preconditions.checkNotNull(path, "path must not be null");
if (path.startsWith("/") || Urls.isUrlWithProtocol(path)) return path;
Preconditions.checkNotNull(context, "context must not be null when path is relative");
return packagePath(context)+path;
}
/** returns a "classpath:" URL given a context object and a file to be found in that directory or a sub-directory
* (ignoring the context object if the given path is absolute, i.e. starting with "/" or "protocol:")
* e.g. "classpath://com/acme/foo.txt" given a context object com.acme.SomeClass and "foo.txt" */
public static String resolveClasspathUrl(Object context, String path) {
if (Urls.isUrlWithProtocol(path)) return path;
// additional / comes from resolve name
return "classpath:/"+resolveName(context, path);
}
/** returns a cleaned stack trace; caller is usually at the top */
public static StackTraceElement[] currentStackTraceCleaned() {
return STACK_TRACE_SIMPLIFIER_EXCLUDING_UTIL_JAVALANG.clean(
Thread.currentThread().getStackTrace());
}
/** returns top of cleaned stack trace; usually the caller's location */
public static StackTraceElement currentStackElement() {
return STACK_TRACE_SIMPLIFIER_EXCLUDING_UTIL_JAVALANG.nthUseful(0,
Thread.currentThread().getStackTrace());
}
/** returns element in cleaned stack trace; usually the caller's location is at the top,
* and caller of that is up one, etc */
public static StackTraceElement callerStackElement(int depth) {
return STACK_TRACE_SIMPLIFIER_EXCLUDING_UTIL_JAVALANG.nthUseful(depth,
Thread.currentThread().getStackTrace());
}
/** returns nice class name and method for the given element */
public static String niceClassAndMethod(StackTraceElement st) {
return simplifyClassName(st.getClassName())+"."+st.getMethodName();
}
/** returns nice class name and method for the caller, going up the stack (filtered to remove invocation etc),
* with 0 typically being the context where this method is called, 1 being its caller, etc */
public static String callerNiceClassAndMethod(int depth) {
return niceClassAndMethod(callerStackElement(depth));
}
/** convenience for {@link #callerNiceClassAndMethod(int)} with depth 0
*
* useful for tests and other debug-facing log messages! */
public static String niceClassAndMethod() {
return callerNiceClassAndMethod(0);
}
}