Hierarchy and subtypes
A ResolvedClass knows every supertype, each resolved against the type you started from. That is the ground everything inherited stands on.
Order
The type, its interfaces, then upwards
hierarchy starts with the type itself, then its interfaces, then the superclass with its interfaces, up to but not including Object.
scala
package example
trait Named { def name: String }
abstract class Repository[E] extends Named
class UserRepository extends Repository[User] { def name = "users" }
TypeResolver.resolve(classOf[UserRepository]).hierarchy
.foreach(entry => println(entry.underlying.getTypeName))
Output
example.UserRepository
example.Repository<example.User>
example.Named
Resolved, not declared
Repository appears as Repository<User>, not as Repository<E>. Every member found through this entry is typed accordingly.
Checks
Subtypes with generics
<:< compares full types, not only raw classes. Primitive types are wrapped first, so int and Integer behave alike.
scala
val users = TypeResolver.resolve(classOf[UserRepository])
val repository = TypeResolver.resolve(classOf[Repository[?]])
val items = users.findField("items").fieldType
val collection = TypeResolver.resolve(classOf[java.util.Collection[?]])
println(users <:< repository) // true
println(items <:< collection) // true
Inheritance
What the hierarchy feeds
Four collections walk the hierarchy; their declared counterparts stay on the class itself.
- fields · declaredFields
- All visible fields, hidden ones removed · the class's own.
- methods · declaredMethods
- All methods, overridden ones removed · the class's own.
- constructors · declaredConstructors
- Constructors of every class in the hierarchy · the class's own.
- annotations · declaredAnnotations
- Annotations of every supertype · the class's own.
constructors crosses class boundaries
constructors includes the superclasses' constructors, which cannot create the subclass. Use declaredConstructors or findConstructor to create instances.