|
|
@@ -11,127 +11,389 @@ import java.util.Arrays;
|
|
|
import java.util.List;
|
|
|
import java.util.Optional;
|
|
|
|
|
|
+import net.ranides.assira.annotations.Meta;
|
|
|
import net.ranides.assira.reflection.impl.FClass;
|
|
|
import net.ranides.assira.reflection.impl.NClass;
|
|
|
import net.ranides.assira.reflection.impl.SClass;
|
|
|
import net.ranides.assira.reflection.util.ClassUtils;
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ * This interface is extension of standard "Class" interface.
|
|
|
+ * It allows inspection in a bit more fluent way and it supports generics.
|
|
|
+ *
|
|
|
+ * It can represent:
|
|
|
+ * - ordinary raw "Class"
|
|
|
+ * - generic class with resolved parameters
|
|
|
+ * - TypeToken
|
|
|
+ * - wildcard type
|
|
|
+ * - symbolic class
|
|
|
+ *
|
|
|
* @author Ranides Atterwim {@literal <ranides@gmail.com>}
|
|
|
+ * @param <T> T
|
|
|
*/
|
|
|
@SuppressWarnings("PMD.TooManyDifferentMethods")
|
|
|
public interface IClass<T> extends IElement, Comparable<IClass<?>> {
|
|
|
|
|
|
+ /**
|
|
|
+ * Constant representing "empty value"
|
|
|
+ */
|
|
|
@SuppressWarnings("rawtypes")
|
|
|
IClass NULL = NClass.getInstance();
|
|
|
|
|
|
- IClass<Object> OBJECT = typeinfo(Object.class);
|
|
|
- IClass<Void> VOID = typeinfo(void.class);
|
|
|
- IClass<Byte> BYTE = typeinfo(byte.class);
|
|
|
- IClass<Short> SHORT = typeinfo(short.class);
|
|
|
- IClass<Integer> INT = typeinfo(int.class);
|
|
|
- IClass<Long> LONG = typeinfo(long.class);
|
|
|
- IClass<Float> FLOAT = typeinfo(float.class);
|
|
|
- IClass<Double> DOUBLE = typeinfo(double.class);
|
|
|
- IClass<Character> CHAR = typeinfo(char.class);
|
|
|
- IClass<Boolean> BOOL = typeinfo(boolean.class);
|
|
|
- IClass<String> STRING = typeinfo(String.class);
|
|
|
- IClass<Number> NUMBER = typeinfo(Number.class);
|
|
|
-
|
|
|
- /**
|
|
|
- * Collect information using java.reflection API
|
|
|
+ /**
|
|
|
+ * Constant representing Object.class
|
|
|
+ */
|
|
|
+ IClass<Object> OBJECT = typeinfo(Object.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing primitive void.class
|
|
|
+ */
|
|
|
+ IClass<Void> VOID = typeinfo(void.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing primitive byte.class
|
|
|
+ */
|
|
|
+ IClass<Byte> BYTE = typeinfo(byte.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing primitive short.class
|
|
|
+ */
|
|
|
+ IClass<Short> SHORT = typeinfo(short.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing primitive int.class
|
|
|
+ */
|
|
|
+ IClass<Integer> INT = typeinfo(int.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing primitive long.class
|
|
|
+ */
|
|
|
+ IClass<Long> LONG = typeinfo(long.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing primitive float.class
|
|
|
+ */
|
|
|
+ IClass<Float> FLOAT = typeinfo(float.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing primitive double.class
|
|
|
+ */
|
|
|
+ IClass<Double> DOUBLE = typeinfo(double.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing primitive char.class
|
|
|
+ */
|
|
|
+ IClass<Character> CHAR = typeinfo(char.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing primitive boolean.class
|
|
|
+ */
|
|
|
+ IClass<Boolean> BOOL = typeinfo(boolean.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing String.class
|
|
|
+ */
|
|
|
+ IClass<String> STRING = typeinfo(String.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constant representing Number.class
|
|
|
+ */
|
|
|
+ IClass<Number> NUMBER = typeinfo(Number.class);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Factory: creates IClass from java.reflection type
|
|
|
+ *
|
|
|
* @param type type
|
|
|
* @return IClass
|
|
|
*/
|
|
|
static IClass<?> typeinfo(Type type) {
|
|
|
return IContext.getDefault().typeinfo(type);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Factory: creates IClass from java.reflection class
|
|
|
+ *
|
|
|
+ * @param type type
|
|
|
+ * @param <R> R
|
|
|
+ * @return IClass
|
|
|
+ */
|
|
|
static <R> IClass<R> typeinfo(Class<R> type) {
|
|
|
return IContext.getDefault().typeinfo(type);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Factory: creates IClass for class stored in provided StackTraceElement
|
|
|
+ *
|
|
|
+ * @param frame frame
|
|
|
+ * @return IClass
|
|
|
+ */
|
|
|
static IClass<?> typeinfo(StackTraceElement frame) {
|
|
|
return typeinfo(frame.getClassName());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Factory: creates IClass for class with provided fully qualified name
|
|
|
+ *
|
|
|
+ * TODO: #92 support syntax for generics
|
|
|
+ *
|
|
|
+ * @param type type
|
|
|
+ * @return IClass
|
|
|
+ */
|
|
|
static IClass<?> typeinfo(String type) {
|
|
|
return ClassUtils.forName(type)
|
|
|
.map(IContext.getDefault()::typeinfo)
|
|
|
.orElseThrow(() -> new IReflectiveException("Unknown class name: " + type));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Factory: creates IClass for provided object.
|
|
|
+ *
|
|
|
+ * Please remember about type-erasure, this method has almost no way to deduce generic parameters.
|
|
|
+ *
|
|
|
+ * @param object object
|
|
|
+ * @param <R> R
|
|
|
+ * @return IClass
|
|
|
+ */
|
|
|
+ @Meta.Alias("typefor")
|
|
|
static <R> IClass<R> typeof(R object) {
|
|
|
return IContext.getDefault().typefor(object);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Factory: creates IClass for provided object.
|
|
|
+ *
|
|
|
+ * Please remember about type-erasure, this method has almost no way to deduce generic parameters.
|
|
|
+ *
|
|
|
+ * @param object object
|
|
|
+ * @param <R> R
|
|
|
+ * @return IClass
|
|
|
+ */
|
|
|
+ @Meta.Alias("typeof")
|
|
|
static <R> IClass<R> typefor(R object) {
|
|
|
return IContext.getDefault().typefor(object);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Factory: creates generic IClass from provided types and parameters
|
|
|
+ *
|
|
|
+ * @param type type
|
|
|
+ * @param params params
|
|
|
+ * @param <R> R
|
|
|
+ * @return IClass
|
|
|
+ */
|
|
|
static <R> IClass<R> generic(Class<R> type, IClass<?>... params) {
|
|
|
return FClass.newClass(type, params);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Factory: creates generic IClass from provided types and parameters
|
|
|
+ *
|
|
|
+ * @param type type
|
|
|
+ * @param params params
|
|
|
+ * @param <R> R
|
|
|
+ * @return IClass
|
|
|
+ */
|
|
|
static <R> IClass<R> generic(Class<R> type, Class<?>... params) {
|
|
|
return FClass.newClass(type, Arrays.stream(params).map(IClass::typeinfo).toArray(IClass<?>[]::new));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Factory: creates symbolic IClass representing type with provided name
|
|
|
+ *
|
|
|
+ * Symbolic types could be used for example, in bytecode generators,
|
|
|
+ * where you don't need more that fully qualified name.
|
|
|
+ *
|
|
|
+ * It does not give information about inheritance, but tries to resolve information
|
|
|
+ * about outer classes by parsing name (JDK uses $ character inside inner class names)
|
|
|
+ *
|
|
|
+ * It throws exception if you try to get some materialized reflective data.
|
|
|
+ *
|
|
|
+ * @param name name
|
|
|
+ * @return IClass
|
|
|
+ */
|
|
|
static IClass<?> symbolic(String name) {
|
|
|
return new SClass(name);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
IClasses collect();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns list of generic parameters.
|
|
|
+ *
|
|
|
+ * If it is impossible to resolve parameters, returned list contains wildcard types
|
|
|
+ * with at least type bounds defined as in generic class declaration.
|
|
|
+ *
|
|
|
+ * @return List
|
|
|
+ */
|
|
|
List<IClass<?>> params();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns all fields inside class
|
|
|
+ *
|
|
|
+ * Strategy for members scan:
|
|
|
+ * - by default returns all public fields (including inherited)
|
|
|
+ * - if you use non-public hints, inherited members are still included
|
|
|
+ * - if you add DECLARED hint, inherited members will be discarded.
|
|
|
+ *
|
|
|
+ * @return IFields
|
|
|
+ */
|
|
|
IFields fields();
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns first field with specified name.
|
|
|
+ *
|
|
|
+ * It searches for private and inherited fields too.
|
|
|
+ *
|
|
|
+ * @param name name
|
|
|
+ * @return Optional
|
|
|
+ */
|
|
|
Optional<IField> field(String name);
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns all constructors
|
|
|
+ *
|
|
|
+ * By default returns only public constructors.
|
|
|
+ *
|
|
|
+ * @return IConstructors
|
|
|
+ */
|
|
|
IConstructors<T> constructors();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns all methods of class.
|
|
|
+ *
|
|
|
+ * Strategy for members scan:
|
|
|
+ * - by default returns all public methods (including inherited)
|
|
|
+ * - if you use non-public hints, inherited members are still included
|
|
|
+ * - if you add DECLARED hint, inherited members will be discarded.
|
|
|
+ *
|
|
|
+ * @return IMethods
|
|
|
+ */
|
|
|
IMethods methods();
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns first method with specified name.
|
|
|
+ *
|
|
|
+ * It searches for private and inherited methods too.
|
|
|
+ *
|
|
|
+ * @param name name
|
|
|
+ * @return Optional
|
|
|
+ */
|
|
|
Optional<IMethod> method(String name);
|
|
|
|
|
|
/**
|
|
|
- * only parent class
|
|
|
+ * Returns base class
|
|
|
+ * If there is not base class, returns {@link #NULL} constant.
|
|
|
+ *
|
|
|
+ * For wildcard types deduces base class from upper bound.
|
|
|
+ * For symbolic types returns {@link #OBJECT}
|
|
|
+ *
|
|
|
* @return IClass
|
|
|
*/
|
|
|
@Override
|
|
|
IClass<?> parent();
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
- * @return only parent classes
|
|
|
+ * Returns all classes from inheritance chain
|
|
|
+ *
|
|
|
+ * @return IClasses
|
|
|
*/
|
|
|
IClasses parents();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns all implemented interfaces
|
|
|
+ *
|
|
|
+ * Strategy for members scan:
|
|
|
+ * - by default all implemented interfaces
|
|
|
+ * - if you use DECLARED hint, inherited interfaces will be discarded
|
|
|
+ *
|
|
|
+ * @return IClasses
|
|
|
+ */
|
|
|
IClasses interfaces();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns outer class, if this class is inner class.
|
|
|
+ * Returns {@link #NULL} otherwise.
|
|
|
+ *
|
|
|
+ * @return IClass
|
|
|
+ */
|
|
|
IClass<?> outer();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns all inner classes inside this class.
|
|
|
+ *
|
|
|
+ * Strategy for members scan:
|
|
|
+ * - by default returns all declared, public and non-public classes
|
|
|
+ * - inherited inner classes are not returned
|
|
|
+ *
|
|
|
+ * @return IClasses
|
|
|
+ */
|
|
|
IClasses inner();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns raw class (type erasured generic).
|
|
|
+ *
|
|
|
+ * For wildcard types it returns {@code Object.class}
|
|
|
+ *
|
|
|
+ * It throws exception for non-reflective types (e.g. symbolic).
|
|
|
+ *
|
|
|
+ * @return Class
|
|
|
+ */
|
|
|
Class<T> raw();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns short name, which means class name without package name or outer class
|
|
|
+ *
|
|
|
+ * @return String
|
|
|
+ */
|
|
|
String shortName();
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns package name for this class
|
|
|
+ *
|
|
|
+ * @return String
|
|
|
+ */
|
|
|
String packageName();
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns component type if type is an array.
|
|
|
+ * Throws IReflectiveException otherwise
|
|
|
+ *
|
|
|
+ * @return IClass
|
|
|
+ */
|
|
|
IClass<?> component();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns reflective type assocciated with this type.
|
|
|
+ * Some type are not reflective and will throw IReflectiveException
|
|
|
+ *
|
|
|
+ * @return Type
|
|
|
+ */
|
|
|
Type reflective();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates new object of this type.
|
|
|
+ *
|
|
|
+ * It uses constructor even if it is non-public.
|
|
|
+ *
|
|
|
+ * @return object
|
|
|
+ */
|
|
|
T construct();
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates new object of this type.
|
|
|
+ *
|
|
|
+ * It searches for constructor matching arguments.
|
|
|
+ * It uses matched constructor even if it is non-public.
|
|
|
+ *
|
|
|
+ * @param arguments arguments
|
|
|
+ * @return object
|
|
|
+ */
|
|
|
T construct(Object... arguments);
|
|
|
|
|
|
/**
|
|
|
* Checks if {@code this} is superclass of {@code type} (or equals)
|
|
|
+ *
|
|
|
* @param type type
|
|
|
* @return bool
|
|
|
*/
|
|
|
@@ -139,6 +401,7 @@ public interface IClass<T> extends IElement, Comparable<IClass<?>> {
|
|
|
|
|
|
/**
|
|
|
* Checks if {@code this} is superclass of {@code type} (or equals)
|
|
|
+ *
|
|
|
* @param type type
|
|
|
* @return bool
|
|
|
*/
|
|
|
@@ -146,6 +409,7 @@ public interface IClass<T> extends IElement, Comparable<IClass<?>> {
|
|
|
|
|
|
/**
|
|
|
* Checks if {@code this} is a subclass of {@code type} (or equals)
|
|
|
+ *
|
|
|
* @param type type
|
|
|
* @return bool
|
|
|
*/
|
|
|
@@ -153,43 +417,155 @@ public interface IClass<T> extends IElement, Comparable<IClass<?>> {
|
|
|
|
|
|
/**
|
|
|
* Checks if {@code this} is a subclass of {@code type} (or equals)
|
|
|
+ *
|
|
|
* @param type type
|
|
|
* @return bool
|
|
|
*/
|
|
|
boolean isSubclass(IClass<?> type);
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns true if (this is instance of type) and (type is instance of this)
|
|
|
+ *
|
|
|
+ * It uses autoboxing
|
|
|
+ *
|
|
|
+ * @param type type
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
boolean isEquivalent(Class<?> type);
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns true if (this is instance of type) and (type is instance of this)
|
|
|
+ *
|
|
|
+ * It uses autoboxing
|
|
|
+ * It uses generic parameters.
|
|
|
+ *
|
|
|
+ * @param type
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
boolean isEquivalent(IClass<?> type);
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns true if value is instance of this type.
|
|
|
+ *
|
|
|
+ * @param value value
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
boolean isInstance(Object value);
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Casts provided value to this type.
|
|
|
+ * Throws ClassCastException if impossible
|
|
|
+ *
|
|
|
+ * If you prefer using optional instead of try/catch, lets look at
|
|
|
+ * {@link ClassUtils#cast(IClass, Object)}.
|
|
|
+ *
|
|
|
+ * @param value value
|
|
|
+ * @return value
|
|
|
+ */
|
|
|
T cast(Object value);
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.INTERFACE)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(INTERFACE)")
|
|
|
boolean isInterface();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.ABSTRACT)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(ABSTRACT)")
|
|
|
boolean isAbstract();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.ANNOTATION)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(ANNOTATION)")
|
|
|
boolean isAnnotation();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.ENUM)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(ENUM)")
|
|
|
boolean isEnum();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.PARAMETERIZED)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(PARAMETERIZED)")
|
|
|
boolean isParameterized();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.ARRAY)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(ARRAY)")
|
|
|
boolean isArray();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code isArray() && component().isPrimitive()}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("isArray() && component().isPrimitive()")
|
|
|
boolean isPrimitiveArray();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.PRIMITIVE)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(PRIMITIVE)")
|
|
|
boolean isPrimitive();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.NUMBER)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(NUMBER)")
|
|
|
boolean isNumber();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.INTEGER)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(INTEGER)")
|
|
|
boolean isInteger();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.BOXED)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(BOXED)")
|
|
|
boolean isBoxed();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.VOID)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(VOID)")
|
|
|
boolean isVoid();
|
|
|
|
|
|
+ /**
|
|
|
+ * Alias for {@code attribute(IAttribute.BOOLEAN)}.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ @Meta.Alias("attribute(BOOLEAN)")
|
|
|
boolean isBoolean();
|
|
|
|
|
|
}
|