| ↑ Table of Contents ↑ | §6.2 Other API Elements >> |
§6.1 Reflection
Object Teams supports reflection with respect to teams, roles, and role-base relationships.
(a) Interface to the role registry
Each team instance internally has a registry of known role objects indexed by their base object.
Programmers may make use of this registry using the following reflective methods defined in
org.objectteams.ITeam:
boolean hasRole ( Object aBase ) ;- This method checks whether a role for the passed base object already exists in the target team.
boolean hasRole ( Object aBase, Class roleType ) ;- This method checks whether a instance of type
roleTypeas a role for the passed base objectaBasealready exists in the target team. The role may also be of any subtype of the specified role type.
IfroleTypeis not a member type of the current team anIllegalArgumentExceptionis thrown. Object getRole ( Object aBase ) ;- If the passed base object
aBasealready has a role in the target team, this role is returned. Otherwisenullis returned. <T> T getRole ( Object aBase, Class<T> roleType ) ;- If the passed base object
aBasealready has a role in the target team that is assignable to the type represented byroleType, this role is returned. Otherwisenullis returned.
IfroleTypeis not a member type of the current team anIllegalArgumentExceptionis thrown. Object[] getAllRoles () ;- Retrieves all existing (registered) bound roles (§2.1.(a)) in the target team.
This method uses internal structures of weak references. For that reason it may return role instances which were about to be reclaimed by the garbage collector. If performance permits, it is thus advisable to always callSystem.gc()prior to callinggetAllRoles()in order to achieve deterministic results (see also §2.1.(f)). <T> T[] getAllRoles ( Class<T> roleType ) ;- Retrieves all existing (registered) bound roles (§2.1.(a)) in the target team that are assignable to the type represented by
roleType.
IfroleTypeis not a member type of the current team anIllegalArgumentExceptionis thrown.
See the note about garbage collection above. void unregisterRole ( Object aRole ) ;- This method unregisters the passed role object from the target team. Thus the corresponding base looses this role. After calling this method the role should no longer be used.
void unregisterRole ( Object aRole, Class roleType ) ;- This method unregisters the passed role object from the target team. Thus the corresponding base loses this role.
After calling this method the role should no longer be used.
The only difference to the previous method is improved speed because no search for the corresponding registry
has to be performed.
IfroleTypeis not a member type of the current team anIllegalArgumentExceptionis thrown.
It is desirable and possible to use these methods within guards (see §5.4). These methods allow to write the specification of guards in a more concise and more expressive way. Determined by the signature, the first four methods can only be used in a base-level guard (§5.4.2) because they require a reference to a base object.
Example code (Guards and Reflection):
| 1 | public team class SpecialConditions { |
| 2 | public void participate(Account as BonusAccount ba) {} |
| 3 | public class BonusAccount playedBy Account |
| 4 | base when(SpecialConditions.this.hasRole(base, BonusAccount.class)) |
| 5 | { |
| 6 | callin void creditBonus(int amount) { |
| 7 | base.creditBonus(amount + bonus); |
| 8 | } |
| 9 | void creditBonus(int amount) <- replace void credit(int i) |
| 10 | base when (i > 1000); |
| 11 | } |
| 12 | } |
(b) Behavioral reflection
The following reflective methods defined in org.objectteams.ITeam can be used to inspect the dynamic behavior of a team:
boolean isExecutingCallin () ;- This method is used to inspect whether a control flow has already been intercepted by at least one callin binding of the current team. It can be used to avoid undesirable re-entrance to a team.
boolean isActive () ;- This method checks whether the team instance is active for the current thread.
boolean isActive ( Thread aThread ) ;- This method checks whether the team instance is active for the thread
aThread.
(c) Class literals for roles
The Java syntax for so-called class literals, MyClass.class
(see JLS §15.8.2)
can be used for role types with slightly changed semantics: Role types are virtual types (§1.3.1)
that are bound dynamically (§1.3.1.(e)). This applies to role class literals, too.
From this follows the constraint that a role class literal can only be used within the non-static context of a team,
ie., for evaluating a role class literal an enclosing team instance must be in scope.
Unlike regular type checking for role types, the class literal itself does not have a dependent type.
Thus type checking of calls to methods like hasRole(Object, Class) cannot detect, whether the Class instance
has actually been obtained from the correct team instance. Any attempt to pass a class that is not known
as a bound role within the given team results in an IllegalArgumentException at run-time.
| ↑ Table of Contents ↑ | §6.2 Other API Elements >> |
Effects:
This teams provides a bonus system for registeredAccounts. Every time an amount of more than 1000 is deposited to a registered account, additional 1% of the amount is credited.participatein line 2 uses declared lifting (see §2.3.2) to allow the passedAccountobject to participate the bonus system provided by theSpecialConditionsteam.hasRoleto check whether the base object already has a role of typeBonusAccountin the surrounding team. The expressionBonusAccount.classreturns thejava.lang.Classobject representing the roleBonusAccount(see JLS §15.8.2). This guard ensures, that only accounts explicitly registered viaparticipateare ever decorated with a role of typeBonusAccount.creditBonusto calls where the base method argumentamountis greater than 1000.