Download JavaCloak: Reflecting on Java Typing for Class Reuse using Proxies

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Computational electromagnetics wikipedia , lookup

Computational fluid dynamics wikipedia , lookup

Transcript
JavaCloak: Reecting on Java Typing for Class
Reuse using Proxies
Karen Renaud1 & Huw Evans2
1
University of South Africa ( [email protected])
2
University of Glasgow ( [email protected])
We discuss problems caused by the limitations of Java's reection mechanism in supporting the specialisation of run-time program behaviour in JavaCloak. JavaCloak allows programmers to specialise the run-time behaviour of
externally-developed code by using pre-generated source-level proxy objects.
These proxy objects are of the same type as the original objects that they wrap.
The runtime specialisation is achieved in two phases. Firstly, the programmer
generates the proxies and tailors them to their local needs. The programmer then
generates a JAR le of these proxy classes which is placed at the very start of
the application's CLASSPATH variable. The virtual machine is thus diverted into
loading the proxy classes instead of the original classes. At runtime the JavaCloak runtime system accesses the wrapped classes and mediates object creation
and method calls across the proxy/original boundary.
When code in the application requests a wrapped type, e.g., package1.T, the
Java VM will load this from the JAR le. To gain access to the implementation in
the original class, a specialised JavaCloak classloader, accessible from the proxy,
loads the wrapped class from a location specied when the virtual machine is
started. When a method is invoked on the proxy, the Java reection mechanism
is used to forward this call onto the wrapped class and to handle the return of
any result or exception objects.
However, a number of implementation problems arise. For example, if the
programmer is using a specialised classloader, they can bypass the JavaCloak
facilities, and load the wrapped class from a dierent location than the JAR
le. Java does not provide any support in its reection mechanism to divert all
classloader requests via a central point, which would be possible if Java supported
a meta-object protocol. Without this separation of concerns between the base
and meta levels, it is not possible for the JavaCloak mechanism to integrate with
other code in the general case.
The second problem occurs because the proxy denes a number of extra methods, over and above those dened by the original class. If the original application
reects over what it thinks is the original class and retrieves the signatures of all
its methods, the list of methods that is passed back will be a superset of those
expected. This may cause the application to fail. It is not possible to solve this
problem inside JavaCloak as there is no way to programmatically control the
information returned by the reection mechanism.
Thirdly, if the original class denes a public, non-static eld, then this eld
should be directly reachable from the proxy. However, the eld is actually dened
on the real class and not on the proxy. Unfortunately, Java does not model eld
access as method invocation, so there is no opportunity to redirect all accesses
to the public eld via the proxy. This forces JavaCloak to assume a clean objectoriented programming model where the programmer only accesses class elds
via method invocations, which reduces its exibility.
By working at the Java-level, JavaCloak is forced to implement the proxy
class and the wrapped class separately. This leads to two problems, the well
known self problem and the encapsulation problem. The meaning of self (or
this in Java programs) is dierent in the proxy and the real instance. Therefore,
JavaCloak must adopt a forwarding model, whereas a delegation model would
be preferable so that calls originating in the original object would be delegated
to the proxy object. In terms of the encapsulation problem, the wrapping is only
logical and this can therefore be broken. For example, the real object may pass
back a direct reference to itself as part of the state of another object. A method
can then be invoked on this object to obtain this direct reference, thus bypassing
the proxy. This occurs because JavaCloak cannot reinterpret the meaning of this
in the original object. Therefore, in the general case, the two instances must be
treated dierently.
Another problem is the forwarding of method calls from the proxy to the
real object. In JavaCloak, all invocations on the public methods of an object
are forwarded, including hashCode and equals. This means it is not possible
to call these methods on the proxies themselves. Therefore, at the JavaCloak
implementation level, these methods cannot be used to manage the proxy. This
has required additional objects to be registered with the JavaCloak mechanism to
operate as tokens for the proxy when calling across the proxy/wrapped boundary.
In certain circumstances, the hashCode and equals could be applied to the proxy
as the source code could be edited. However, this is not a solution in the general
case as this cannot be guaranteed.
In conclusion, the problems identied above highlight the inexibility of
Java's reection mechanism. Java's reection mechanism is really an introspection mechanism, allowing the programmer to gain access to certain information
about objects and classes. However, it does not allow the programmer to associate new behaviour with the basic building blocks of the language, such as
method dispatch or redening the meaning of this. The above mentioned problems, when programming at the Java source-level, are insurmountable given the
current denition of Java and current virtual machine implementations. It is not
possible to provide a system to specialise the run-time behaviour of programs
using source-code level proxy objects. Therefore, the programmer is forced to operate at the bytecode level. However, even operating at this level does not solve
all problems as some policies are hard-wired into the virtual machine itself, e.g.,
bytecode verication policy.
Therefore, to be truly exible, and to facilitate runtime specialisation at the
Java-level, Java needs to dene a behavioural reection mechanism and future
Java virtual machines need to give the programmer access, via this reection
mechanism, to the internal policy decisions. The conclusion of this work is that
providing this kind of facility at the Java level does not work in the general case
and that the only solution currently available is to work at the bytecode level.