Compare commits
2 Commits
be2dfae824
...
d3a767806b
Author | SHA1 | Date |
---|---|---|
Robinson | d3a767806b | |
Robinson | 27921e22ff |
92
LICENSE
92
LICENSE
|
@ -75,12 +75,6 @@
|
|||
The Netty Project
|
||||
Contributors. See source NOTICE
|
||||
|
||||
- TypeTools - A simple, zero-dependency library for working with types. Supports Java 1.6+ and Android.
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/jhalterman/typetools
|
||||
Copyright 2023
|
||||
Jonathan Halterman and friends
|
||||
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
|
@ -95,92 +89,6 @@
|
|||
Copyright 2023
|
||||
JetBrains s.r.o.
|
||||
|
||||
- Collections - Niche collections to augment what is already available.
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
Copyright 2023
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- Bias, BinarySearch -
|
||||
[MIT License]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
https://github.com/timboudreau/util
|
||||
Copyright 2013
|
||||
Tim Boudreau
|
||||
|
||||
- ConcurrentEntry -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
Copyright 2016
|
||||
bennidi
|
||||
dorkbox
|
||||
|
||||
- Collection Utilities (Array, ArrayMap, BooleanArray, ByteArray, CharArray, FloatArray, IdentityMap, IntArray, IntFloatMap, IntIntMap, IntMap, IntSet, LongArray, LongMap, ObjectFloatMap, ObjectIntMap, ObjectMap, ObjectSet, OrderedMap, OrderedSet) -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
|
||||
Copyright 2011
|
||||
LibGDX
|
||||
Mario Zechner (badlogicgames@gmail.com)
|
||||
Nathan Sweet (nathan.sweet@gmail.com)
|
||||
|
||||
- Predicate -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
|
||||
Copyright 2011
|
||||
LibGDX
|
||||
Mario Zechner (badlogicgames@gmail.com)
|
||||
Nathan Sweet (nathan.sweet@gmail.com)
|
||||
xoppa
|
||||
|
||||
- Select, QuickSelect -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
|
||||
Copyright 2011
|
||||
LibGDX
|
||||
Mario Zechner (badlogicgames@gmail.com)
|
||||
Nathan Sweet (nathan.sweet@gmail.com)
|
||||
Jon Renner
|
||||
|
||||
- TimSort, ComparableTimSort -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
|
||||
Copyright 2008
|
||||
The Android Open Source Project
|
||||
|
||||
- ConcurrentWeakIdentityHashMap - Concurrent WeakIdentity HashMap
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/spring-projects/spring-loaded/blob/master/springloaded/src/main/java/org/springsource/loaded/support/ConcurrentWeakIdentityHashMap.java
|
||||
Copyright 2016
|
||||
zhanhb
|
||||
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- Updates - Software Update Management
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Updates
|
||||
Copyright 2021
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- Executor - Shell, JVM, and SSH command execution on Linux, MacOS, or Windows for Java 8+
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Executor
|
||||
|
|
|
@ -35,7 +35,7 @@ object Extras {
|
|||
// set for the project
|
||||
const val description = "Utilities for use within Java projects"
|
||||
const val group = "com.dorkbox"
|
||||
const val version = "1.43"
|
||||
const val version = "1.44"
|
||||
|
||||
// set as project.ext
|
||||
const val name = "Utilities"
|
||||
|
@ -129,7 +129,6 @@ tasks.jar.get().apply {
|
|||
dependencies {
|
||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
|
||||
|
||||
api("com.dorkbox:Collections:1.6")
|
||||
api("com.dorkbox:Executor:3.13")
|
||||
api("com.dorkbox:OS:1.6")
|
||||
api("com.dorkbox:Updates:1.1")
|
||||
|
@ -150,13 +149,11 @@ dependencies {
|
|||
// runtime "com.koloboke:koloboke-impl-jdk8:1.0.0"
|
||||
|
||||
compileOnly("io.netty:netty-buffer:4.1.94.Final")
|
||||
compileOnly("net.jodah:typetools:0.6.3")
|
||||
// compileOnly("net.jodah:typetools:0.6.3")
|
||||
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
// testImplementation("ch.qos.logback:logback-classic:1.4.5")
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
// implementation(kotlin("stdlib-jdk8"))
|
||||
}
|
||||
|
||||
publishToSonatype {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018 dorkbox, llc
|
||||
* Copyright 2023 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -27,7 +27,7 @@ object Sys {
|
|||
/**
|
||||
* Gets the version number.
|
||||
*/
|
||||
val version = "1.43"
|
||||
val version = "1.44"
|
||||
|
||||
init {
|
||||
// Add this project to the updates system, which verifies this class + UUID + version information
|
||||
|
|
|
@ -1,199 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 dorkbox, llc.
|
||||
*
|
||||
* 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 dorkbox.util.classes;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.jodah.typetools.TypeResolver;
|
||||
|
||||
public final
|
||||
class ClassHelper {
|
||||
|
||||
/**
|
||||
* Retrieves the generic type parameter for the PARENT (super) class of the specified class or lambda expression.
|
||||
*
|
||||
* Because of how type erasure works in java, this will work on lambda expressions and ONLY parent/super classes.
|
||||
*
|
||||
* @param genericTypeClass this class is what you are looking for
|
||||
* @param classToCheck class to actually get the parameter from
|
||||
* @param genericParameterToGet 0-based index of parameter as class to get
|
||||
*
|
||||
* @return null if the generic type could not be found.
|
||||
*/
|
||||
@SuppressWarnings({"StatementWithEmptyBody", "UnnecessaryLocalVariable"})
|
||||
public static
|
||||
Class<?> getGenericParameterAsClassForSuperClass(Class<?> genericTypeClass, Class<?> classToCheck, int genericParameterToGet) {
|
||||
Class<?> loopClassCheck = classToCheck;
|
||||
|
||||
// this will ALWAYS return something, if it is unknown, it will return TypeResolver.Unknown.class
|
||||
Class<?>[] classes = TypeResolver.resolveRawArguments(genericTypeClass, loopClassCheck);
|
||||
if (classes.length > genericParameterToGet && classes[genericParameterToGet] != TypeResolver.Unknown.class) {
|
||||
return classes[genericParameterToGet];
|
||||
}
|
||||
|
||||
// case of multiple inheritance, we are trying to get the first available generic info
|
||||
// don't check for Object.class (this is where superclass is null)
|
||||
while (loopClassCheck != Object.class) {
|
||||
// check to see if we have what we are looking for on our CURRENT class
|
||||
Type superClassGeneric = loopClassCheck.getGenericSuperclass();
|
||||
|
||||
classes = TypeResolver.resolveRawArguments(superClassGeneric, loopClassCheck);
|
||||
if (classes.length > genericParameterToGet) {
|
||||
Class<?> aClass = classes[genericParameterToGet];
|
||||
if (aClass != TypeResolver.Unknown.class) {
|
||||
return classes[genericParameterToGet];
|
||||
}
|
||||
}
|
||||
|
||||
// NO MATCH, so walk up.
|
||||
loopClassCheck = loopClassCheck.getSuperclass();
|
||||
}
|
||||
|
||||
// NOTHING! now check interfaces!
|
||||
loopClassCheck = classToCheck;
|
||||
while (loopClassCheck != Object.class) {
|
||||
// check to see if we have what we are looking for on our CURRENT class interfaces
|
||||
Type[] genericInterfaces = loopClassCheck.getGenericInterfaces();
|
||||
|
||||
for (Type genericInterface : genericInterfaces) {
|
||||
classes = TypeResolver.resolveRawArguments(genericInterface, loopClassCheck);
|
||||
if (classes.length > genericParameterToGet) {
|
||||
Class<?> aClass = classes[genericParameterToGet];
|
||||
if (aClass != TypeResolver.Unknown.class) {
|
||||
return aClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NO MATCH, so walk up.
|
||||
loopClassCheck = loopClassCheck.getSuperclass();
|
||||
}
|
||||
|
||||
// couldn't find it.
|
||||
return null;
|
||||
}
|
||||
|
||||
// from: https://github.com/square/retrofit/blob/108fe23964b986107aed352ba467cd2007d15208/retrofit/src/main/java/retrofit2/Utils.java
|
||||
public static Class<?> getRawType(Type type) {
|
||||
Objects.requireNonNull(type, "type == null");
|
||||
|
||||
if (type instanceof Class<?>) {
|
||||
// Type is a normal class.
|
||||
return (Class<?>) type;
|
||||
}
|
||||
if (type instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
|
||||
// I'm not exactly sure why getRawType() returns Type instead of Class. Neal isn't either but
|
||||
// suspects some pathological case related to nested classes exists.
|
||||
Type rawType = parameterizedType.getRawType();
|
||||
if (!(rawType instanceof Class)) throw new IllegalArgumentException();
|
||||
return (Class<?>) rawType;
|
||||
}
|
||||
if (type instanceof GenericArrayType) {
|
||||
Type componentType = ((GenericArrayType) type).getGenericComponentType();
|
||||
return Array.newInstance(getRawType(componentType), 0).getClass();
|
||||
}
|
||||
if (type instanceof TypeVariable) {
|
||||
// We could use the variable's bounds, but that won't work if there are multiple. Having a raw
|
||||
// type that's more general than necessary is okay.
|
||||
return Object.class;
|
||||
}
|
||||
if (type instanceof WildcardType) {
|
||||
return getRawType(((WildcardType) type).getUpperBounds()[0]);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Expected a Class, ParameterizedType, or "
|
||||
+ "GenericArrayType, but <"
|
||||
+ type
|
||||
+ "> is of type "
|
||||
+ type.getClass().getName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if clazz or interface directly has one of the interfaces defined by requiredClass
|
||||
* <p/>
|
||||
* If the class DOES NOT directly have the interface it will fail.
|
||||
*/
|
||||
public static
|
||||
boolean hasInterface(Class<?> requiredClass, Class<?> clazz) {
|
||||
if (requiredClass == clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Class<?>[] interfaces = clazz.getInterfaces();
|
||||
for (Class<?> iface : interfaces) {
|
||||
if (iface == requiredClass) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// now walk up to see if we can find it.
|
||||
for (Class<?> iface : interfaces) {
|
||||
boolean b = hasInterface(requiredClass, iface);
|
||||
if (b) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
// nothing, so now we check the PARENT of this class
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
|
||||
// case of multiple inheritance, we are trying to get the first available generic info
|
||||
// don't check for Object.class (this is where superclass is null)
|
||||
while (superClass != null && superClass != Object.class) {
|
||||
// check to see if we have what we are looking for on our CURRENT class
|
||||
if (hasInterface(requiredClass, superClass)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// NO MATCH, so walk up.
|
||||
superClass = superClass.getSuperclass();
|
||||
}
|
||||
|
||||
// if we don't find it.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the clazz is a subclass of a parent class.
|
||||
*/
|
||||
@SuppressWarnings("SimplifiableIfStatement")
|
||||
public static
|
||||
boolean hasParentClass(Class<?> parentClazz, Class<?> clazz) {
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
if (parentClazz == superClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (superClass != null && superClass != Object.class) {
|
||||
return hasParentClass(parentClazz, superClass);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private
|
||||
ClassHelper() {
|
||||
}
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 dorkbox, llc
|
||||
*
|
||||
* 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 dorkbox.util.classes;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
||||
|
||||
import dorkbox.collections.IdentityMap;
|
||||
|
||||
/**
|
||||
* @author dorkbox
|
||||
* Date: 4/1/15
|
||||
*/
|
||||
public final
|
||||
class ClassHierarchy {
|
||||
|
||||
private volatile IdentityMap<Class<?>, Class<?>> arrayCache;
|
||||
private volatile IdentityMap<Class<?>, Class<?>[]> superClassesCache;
|
||||
|
||||
// Recommended for best performance while adhering to the "single writer principle". Must be static-final
|
||||
private static final AtomicReferenceFieldUpdater<ClassHierarchy, IdentityMap> arrayREF =
|
||||
AtomicReferenceFieldUpdater.newUpdater(ClassHierarchy.class,
|
||||
IdentityMap.class,
|
||||
"arrayCache");
|
||||
|
||||
private static final AtomicReferenceFieldUpdater<ClassHierarchy, IdentityMap> superClassesREF =
|
||||
AtomicReferenceFieldUpdater.newUpdater(ClassHierarchy.class,
|
||||
IdentityMap.class,
|
||||
"superClassesCache");
|
||||
|
||||
/**
|
||||
* These data structures are never reset because the class hierarchy doesn't change at runtime. This class uses the "single writer
|
||||
* principle" for storing data, EVEN THOUGH it's not accessed by a single writer. This DOES NOT MATTER because duplicates DO NOT matter
|
||||
*/
|
||||
public
|
||||
ClassHierarchy(float loadFactor) {
|
||||
this.arrayCache = new IdentityMap<Class<?>, Class<?>>(32, loadFactor);
|
||||
this.superClassesCache = new IdentityMap<Class<?>, Class<?>[]>(32, loadFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* will return the class + parent classes as an array.
|
||||
* if parameter clazz is of type array, then the super classes are of array type as well
|
||||
* <p>
|
||||
* race conditions will result in DUPLICATE answers, which we don't care if happens
|
||||
* never returns null
|
||||
* never reset (class hierarchy never changes during runtime)
|
||||
*/
|
||||
public
|
||||
Class<?>[] getClassAndSuperClasses(final Class<?> clazz) {
|
||||
// access a snapshot of the subscriptions (single-writer-principle)
|
||||
final IdentityMap<Class<?>, Class<?>[]> cache = cast(superClassesREF.get(this));
|
||||
|
||||
Class<?>[] classes = cache.get(clazz);
|
||||
|
||||
// duplicates DO NOT MATTER
|
||||
if (classes == null) {
|
||||
// publish all super types of class
|
||||
final Iterator<Class<?>> superTypesIterator = getSuperTypes(clazz);
|
||||
final ArrayList<Class<?>> newList = new ArrayList<Class<?>>(16);
|
||||
|
||||
Class<?> c;
|
||||
final boolean isArray = clazz.isArray();
|
||||
|
||||
// have to add the original class to the front of the list
|
||||
newList.add(clazz);
|
||||
|
||||
if (isArray) {
|
||||
// super-types for an array ALSO must be an array.
|
||||
while (superTypesIterator.hasNext()) {
|
||||
c = superTypesIterator.next();
|
||||
c = getArrayClass(c);
|
||||
|
||||
if (c != clazz) {
|
||||
newList.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (superTypesIterator.hasNext()) {
|
||||
c = superTypesIterator.next();
|
||||
|
||||
if (c != clazz) {
|
||||
newList.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
classes = new Class<?>[newList.size()];
|
||||
newList.toArray(classes);
|
||||
cache.put(clazz, classes);
|
||||
|
||||
// save this snapshot back to the original (single writer principle)
|
||||
superClassesREF.lazySet(this, cache);
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* race conditions will result in DUPLICATE answers, which we don't care if happens
|
||||
* never returns null
|
||||
* never resets (class hierarchy never changes during runtime)
|
||||
*
|
||||
* https://bugs.openjdk.java.net/browse/JDK-6525802 (fixed this in 2007, so Array.newInstance is just as fast (via intrinsics) new [])
|
||||
* Cache is in place to keep GC down.
|
||||
*/
|
||||
public
|
||||
Class<?> getArrayClass(final Class<?> c) {
|
||||
// access a snapshot of the subscriptions (single-writer-principle)
|
||||
final IdentityMap<Class<?>, Class<?>> cache = cast(arrayREF.get(this));
|
||||
|
||||
Class<?> clazz = cache.get(c);
|
||||
|
||||
if (clazz == null) {
|
||||
// messy, but the ONLY way to do it. Array super types are also arrays
|
||||
final Object[] newInstance = (Object[]) Array.newInstance(c, 0);
|
||||
clazz = newInstance.getClass();
|
||||
cache.put(c, clazz);
|
||||
|
||||
// save this snapshot back to the original (single writer principle)
|
||||
arrayREF.lazySet(this, cache);
|
||||
}
|
||||
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all directly and indirectly related super types (classes and interfaces) of a given class.
|
||||
*
|
||||
* @param from The root class to start with
|
||||
* @return An array of classes, each representing a super type of the root class
|
||||
*/
|
||||
public static
|
||||
Iterator<Class<?>> getSuperTypes(Class<?> from) {
|
||||
// This must be a 'set' because there can be duplicates, depending on the object hierarchy
|
||||
final IdentityMap<Class<?>, Boolean> superclasses = new IdentityMap<Class<?>, Boolean>();
|
||||
collectInterfaces(from, superclasses);
|
||||
|
||||
while (!from.equals(Object.class) && !from.isInterface()) {
|
||||
superclasses.put(from.getSuperclass(), Boolean.TRUE);
|
||||
from = from.getSuperclass();
|
||||
collectInterfaces(from, superclasses);
|
||||
}
|
||||
|
||||
return superclasses.keys();
|
||||
}
|
||||
|
||||
private static
|
||||
void collectInterfaces(Class<?> from, IdentityMap<Class<?>, Boolean> accumulator) {
|
||||
for (Class<?> intface : from.getInterfaces()) {
|
||||
accumulator.put(intface, Boolean.TRUE);
|
||||
collectInterfaces(intface, accumulator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears the caches, should only be called on shutdown
|
||||
*/
|
||||
public
|
||||
void shutdown() {
|
||||
this.arrayCache.clear();
|
||||
this.superClassesCache.clear();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static
|
||||
<T> T cast(Object obj) {
|
||||
return (T) obj;
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 dorkbox, llc
|
||||
*
|
||||
* 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 dorkbox.util.classes;
|
||||
|
||||
public abstract class ClassResolver {
|
||||
/**
|
||||
* A helper class to get the call context. It subclasses SecurityManager to make getClassContext() accessible. An instance of
|
||||
* CallerResolver only needs to be created, not installed as an actual security manager.
|
||||
*/
|
||||
private static final class CallerResolver extends SecurityManager {
|
||||
@Override
|
||||
protected Class<?>[] getClassContext() {
|
||||
return super.getClassContext();
|
||||
}
|
||||
}
|
||||
|
||||
private static final int CALL_CONTEXT_OFFSET = 3; // may need to change if this class is redesigned
|
||||
private static final CallerResolver CALLER_RESOLVER;
|
||||
|
||||
static {
|
||||
try {
|
||||
// This can fail if the current SecurityManager does not allow
|
||||
// RuntimePermission ("createSecurityManager"):
|
||||
CALLER_RESOLVER = new CallerResolver();
|
||||
} catch (SecurityException se) {
|
||||
throw new RuntimeException("ClassLoaderResolver: could not create CallerResolver: " + se);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexes into the current method call context with a given offset.
|
||||
*/
|
||||
public static Class<?> getCallerClass(final int callerOffset) {
|
||||
return CALLER_RESOLVER.getClassContext()[CALL_CONTEXT_OFFSET + callerOffset];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 Benjamin Diedrichsen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
* Copyright 2015 dorkbox, llc
|
||||
*
|
||||
* 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 dorkbox.util.classes;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import dorkbox.collections.IdentityMap;
|
||||
|
||||
/**
|
||||
* @author bennidi
|
||||
* Date: 2/16/12
|
||||
* Time: 12:14 PM
|
||||
* @author dorkbox
|
||||
* Date: 2/2/15
|
||||
*/
|
||||
public final
|
||||
class ReflectionUtils {
|
||||
|
||||
private static final Method[] EMPTY_METHODS = new Method[0];
|
||||
|
||||
private
|
||||
ReflectionUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get methods annotated with the specified annotation.
|
||||
*
|
||||
* @param target the class that you are looking for the methods on
|
||||
* @param annotationClass the annotations that define the method you are looking for
|
||||
* @param <A> the annotation type
|
||||
*
|
||||
* @return the array of methods that match the target + annotation
|
||||
*/
|
||||
public static
|
||||
<A extends Annotation> Method[] getMethods(Class<?> target, Class<A> annotationClass) {
|
||||
ArrayList<Method> methods = new ArrayList<Method>();
|
||||
|
||||
getMethods(target, annotationClass, methods);
|
||||
return methods.toArray(EMPTY_METHODS);
|
||||
}
|
||||
|
||||
private static
|
||||
<A extends Annotation> void getMethods(Class<?> target, Class<A> annotationClass, ArrayList<Method> methods) {
|
||||
try {
|
||||
for (Method method : target.getDeclaredMethods()) {
|
||||
if (getAnnotation(method, annotationClass) != null) {
|
||||
methods.add(method);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
// recursively go until root
|
||||
if (!target.equals(Object.class)) {
|
||||
getMethods(target.getSuperclass(), annotationClass, methods);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the class hierarchy upwards, starting at the given subclass, looking
|
||||
* for an override of the given methods -> finds the bottom most override of the given
|
||||
* method if any exists
|
||||
*/
|
||||
public static
|
||||
Method getOverridingMethod(final Method overridingMethod, final Class<?> subclass) {
|
||||
Class<?> current = subclass;
|
||||
while (!current.equals(overridingMethod.getDeclaringClass())) {
|
||||
try {
|
||||
return current.getDeclaredMethod(overridingMethod.getName(), overridingMethod.getParameterTypes());
|
||||
} catch (NoSuchMethodException e) {
|
||||
current = current.getSuperclass();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
boolean containsOverridingMethod(final Method[] allMethods, final Method methodToCheck) {
|
||||
final int length = allMethods.length;
|
||||
Method method;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
method = allMethods[i];
|
||||
|
||||
if (isOverriddenBy(methodToCheck, method)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for an Annotation of the given type on the class. Supports meta annotations.
|
||||
*
|
||||
* @param from AnnotatedElement (class, method...)
|
||||
* @param annotationType Annotation class to look for.
|
||||
* @param <A> Class of annotation type
|
||||
* @return Annotation instance or null
|
||||
*/
|
||||
private static
|
||||
<A extends Annotation> A getAnnotation(AnnotatedElement from, Class<A> annotationType, IdentityMap<AnnotatedElement, Boolean> visited) {
|
||||
if (visited.containsKey(from)) {
|
||||
return null;
|
||||
}
|
||||
visited.put(from, Boolean.TRUE);
|
||||
A ann = from.getAnnotation(annotationType);
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
}
|
||||
for (Annotation metaAnn : from.getAnnotations()) {
|
||||
ann = getAnnotation(metaAnn.annotationType(), annotationType, visited);
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static
|
||||
<A extends Annotation> A getAnnotation(AnnotatedElement from, Class<A> annotationType) {
|
||||
return getAnnotation(from, annotationType, new IdentityMap<AnnotatedElement, Boolean>());
|
||||
}
|
||||
|
||||
|
||||
private static
|
||||
boolean isOverriddenBy(final Method superclassMethod, final Method subclassMethod) {
|
||||
// if the declaring classes are the same or the subclass method is not defined in the subclass
|
||||
// hierarchy of the given superclass method or the method names are not the same then
|
||||
// subclassMethod does not override superclassMethod
|
||||
if (superclassMethod.getDeclaringClass().equals(subclassMethod.getDeclaringClass()) ||
|
||||
!superclassMethod.getDeclaringClass().isAssignableFrom(subclassMethod.getDeclaringClass()) ||
|
||||
!superclassMethod.getName().equals(subclassMethod.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Class<?>[] superClassMethodParameters = superclassMethod.getParameterTypes();
|
||||
final Class<?>[] subClassMethodParameters = subclassMethod.getParameterTypes();
|
||||
|
||||
// method must specify the same number of parameters
|
||||
//the parameters must occur in the exact same order
|
||||
for (int i = 0; i < subClassMethodParameters.length; i++) {
|
||||
if (!superClassMethodParameters[i].equals(subClassMethodParameters[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 dorkbox, llc
|
||||
*
|
||||
* 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 dorkbox.util.classes;
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 dorkbox, llc
|
||||
*
|
||||
* 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 dorkbox.util.classes;
|
||||
|
||||
/**
|
||||
* Required for intellij to not complain regarding `module-info` for a multi-release jar.
|
||||
* This file is completely ignored by the gradle build process
|
||||
*/
|
||||
public
|
||||
class EmptyClass {}
|
|
@ -2,7 +2,6 @@ module dorkbox.utilities {
|
|||
exports dorkbox.exit;
|
||||
exports dorkbox.urlHandler;
|
||||
exports dorkbox.util;
|
||||
exports dorkbox.util.classes;
|
||||
exports dorkbox.util.entropy;
|
||||
exports dorkbox.util.exceptions;
|
||||
exports dorkbox.util.gwt;
|
||||
|
|
Loading…
Reference in New Issue