Proxies Core Java

In the final section of this chapter, we discuss proxies, a feature that became available with Java SE 1.3. You use a proxy to create at runtime new classes that implement a given set of interfaces. Proxies are only necessary when you don’t yet know at compile time which interfaces you need to implement. This is not a common situation for application programmers, and you should feel free to skip this section if you are not interested in advanced wizardry. However, for certain system programming applications, the flexibility that proxies offer can be very important.

Suppose you want to construct an object of a class that implements one or more interfaces whose exact nature you may not know at compile time. This is a difficult problem.

To construct an actual class, you can simply use the newInstance method or use reflection to find a constructor. But you can’t instantiate an interface. You need to define a new class in a running program.

To overcome this problem, some programs generate code, place it into a file, invoke the compiler, and then load the resulting class file. Naturally, this is slow, and it also requires deployment of the compiler together with the program. The proxy mechanism is a better solution. The proxy class can create brand-new classes at runtime. Such a proxy class implements the interfaces that you specify. In particular, the proxy class has the following methods:

  • All methods required by the specified interfaces; and
  • All methods defined in the Object class (toString, equals, and so on).

However, you cannot define new code for these methods at runtime. Instead, you must supply an invocation handler. An invocation handler is an object of any class that implements the Invocation Handler interface. That interface has a single method:

Object invoke(Object proxy, Method method, Object[] args) Whenever a method is called on the proxy object, the invoke method of the invocation handler gets called, with the Method object and parameters of the original call. The invocation handler must then figure out how to handle the call.

To create a proxy object, you use the newProxyInstance method of the Proxy class. The method has three parameters:

  • A class loader. As part of the Java security model, different class loaders for system classes, classes that are downloaded from the Internet, and so on, can be used. We discuss class loaders later. For now, we specify null to use the default class loader.
  • An array of Class objects, one for each interface to be implemented.
  • An invocation handler.
    There are two remaining questions. How do we define the handler? And what can we do with the resulting proxy object? The answers depend, of course, on the problem that we want to solve with the proxy mechanism. Proxies can be used for many purposes, such as
  • Routing method calls to remote servers;
  • Associating user interface events with actions in a running program; and
  • Tracing method calls for debugging purposes.

In our example program, we use proxies and invocation handlers to trace method calls.

We define a TraceHandler wrapper class that stores a wrapped object. Its invoke method simply prints the name and parameters of the method to be called and then calls the method with the wrapped object as the implicit parameter.

Here is how you construct a proxy object that causes the tracing behavior whenever one of its methods is called:

Now, whenever a method from one of the interfaces is called on proxy, the method name and parameters are printed out and the method is then invoked on value.

In the program shown in Listing below, we use proxy objects to trace a binary search. We fill an array with proxies to the integers 1 . . . 1000. Then we invoke the binarySearchmethod of the Arrays class to search for a random integer in the array. Finally, we print the matching element.

The Integer class implements the Comparable interface. The proxy objects belong to a class that is defined at runtime. (It has a name such as $Proxy0.) That class also implements the Comparable interface. However, its compare To method calls the invoke method of the proxy object’s handler.

NOTE: As you saw earlier in this section, as of Java SE 5.0, the Integer class actually implements Comparable<Integer>. However, at runtime, all generic types are erased and the proxy is constructed with the class object for the raw Comparable class. The binarySearch method makes calls like this:

Because we filled the array with proxy objects, the compareTo calls call the invoke method of the Trace Handler class. That method prints the method name and parameters and then invokes compareTo on the wrapped Integer object.

Finally, at the end of the sample program, we call

The println method calls toString on the proxy object, and that call is also redirected to the invocation handler.

Here is the complete trace of a program run: 500.compareTo(288) 250.compareTo(288) 375.compareTo(288) 312.compareTo(288) 281.compareTo(288) 296.compareTo(288) 288.compareTo(288) 288.toString()

You can see how the binary search algorithm homes in on the key by cutting the search interval in half in every step. Note that the toString method is proxied even though it does not belong to the Comparable interface—as you will see in the next section, certain Object methods are always proxied.

ProxyTest.java

Properties of Proxy Classes

Now that you have seen proxy classes in action, we want to go over some of their properties. Remember that proxy classes are created on the fly in a running program. However, once they are created, they are regular classes, just like any other classes in the virtual machine.

All proxy classes extend the class Proxy. A proxy class has only one instance field—the invocation handler, which is defined in the Proxy superclass. Any additional data that are required to carry out the proxy objects’ tasks must be stored in the invocation handler. For example, when we proxied Comparable objects in the program shown in Listing above, the TraceHandler wrapped the actual objects.

All proxy classes override the toString, equals, and hashCode methods of the Object class. Like all proxy methods, these methods simply call invoke on the invocation handler. The other methods of the Object class (such as clone and getClass) are not redefined.

The names of proxy classes are not defined. The Proxy class in Sun’s virtual machine generates class names that begin with the string $Proxy.

There is only one proxy class for a particular class loader and ordered set of interfaces. That is, if you call the newProxyInstance method twice with the same class loader and interface array, then you get two objects of the same class. You can also obtain that class withthe getProxyClass method:

A proxy class is always public and final. If all interfaces that the proxy class implements are public, then the proxy class does not belong to any particular package. Otherwise, all non-public interfaces must belong to the same package, and then the proxy class also belongs to that package.

You can test whether a particular Class object represents a proxy class by calling the is ProxyClass method of the Proxy class.

java.lang.reflect.InvocationHandler

  • Object invoke(Object proxy, Method method, Object[] args)
    define this method to contain the action that you want carried out whenever a method was invoked on the proxy object.
  • static Class getProxyClass(ClassLoader loader, Class[] interfaces)
    returns the proxy class that implements the given interfaces.
  • static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler handler)
    constructs a new instance of the proxy class that implements the given interfaces.
  • All methods call the invoke method of the given handler object.

  • static boolean isProxyClass(Class c)
    returns true if c is a proxy class.

This ends our final section on the fundamentals of the Java programming language.

Interfaces and inner classes are concepts that you will encounter frequently. However, as we already mentioned, proxies are an advanced technique that is of interest mainly to tool builders, not application programmers. You are now ready to go on to learn about

graphics and user interfaces, starting with next section.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Core Java Topics