Explore the
Dynamic Proxy API
Tutorial Details:
Explore the Dynamic Proxy API
Explore the Dynamic Proxy API
By: By Jeremy Blosser
Use dynamic proxies to bring strong typing to abstract data types
ith the introduction of the Dynamic Proxy API in Java 1.3, a huge and often overlooked improvement has been made to the Java platform. The uses for dynamic proxies are sometimes hard concepts to grasp. In this article, I hope to introduce you first to the Proxy design pattern and then to the java.lang.reflect.Proxy class and the java.lang.reflect.InvocationHandler interface, which make up the heart of Dynamic Proxy's functionality.
The functionality discussed here combines the Java 1.3 dynamic proxies with abstract data types to bring strong typing to those types. I will also discuss the power of the dynamic proxy by introducing the concept of views in your Java programming. Lastly, I will introduce a powerful way to add access control to your Java objects with, of course, the use of the dynamic proxy.
Definition of a proxy
A proxy forces object method calls to occur indirectly through the proxy object, which acts as a surrogate or delegate for the underlying object being proxied. Proxy objects are usually declared so that the client objects have no indication that they have a proxy object instance.
Some common proxies are the access proxy, facades, remote proxies, and virtual proxies. An access proxy is used to enforce a security policy on access to a service or data-providing object. A facade is a single interface to multiple underlying objects. The remote proxy is used to mask or shield the client object from the fact that the underlying object is remote. A virtual proxy is used to perform lazy or just-in-time instantiation of the real object.
The proxy is a fundamental design pattern that is used quite often in programming. However, one of its drawbacks is the specificity or tight coupling of the proxy with its underlying object. Looking at the UML for the Proxy design pattern in Figure 1, you see that for the proxy to be useful and transparent, it usually needs to either implement an interface or inherit from a known superclass (with the exception of a facade, perhaps).
Figure 1. UML Diagram of the Proxy Design Pattern
Dynamic proxies
In Java 1.3, Sun introduced the Dynamic Proxy API. For the dynamic proxy to work, you must first have a proxy interface. The proxy interface is the interface that is implemented by the proxy class. Second, you need an instance of the proxy class.
Interestingly, you can have a proxy class that implements multiple interfaces. However, there are a few restrictions on the interfaces you implement. It is important to keep those restrictions in mind when creating your dynamic proxy:
The proxy interface must be an interface. In other words, it cannot be a class (or an abstract class) or a primitive.
The array of interfaces passed to the proxy constructor must not contain duplicates of the same interface. Sun specifies that, and it makes sense that you wouldn't be trying to implement the same interface twice at the same time. For example, an array { IPerson.class, IPerson.class } would be illegal, but the code { IPerson.class, IEmployee.class } would not. The code calling the constructor should check for that case and filter out duplicates.
All the interfaces must be visible to the ClassLoader specified during the construction call. Again, that makes sense. The ClassLoader must be able to load the interfaces for the proxy.
All the nonpublic interfaces must be from the same package. You cannot have a private interface from package com.xyz and the proxy class in package com.abc . If you think about it, it is the same way when programming a regular Java class. You couldn't implement a nonpublic interface from another package with a regular class either.
The proxy interfaces cannot have a conflict of methods. You can't have two methods that take the same parameters but return different types. For example, the methods public void foo() and public String foo() cannot be defined in the same class because they have the same signature, but return different types (see The Java Language Specification ). Again, that is the same for a regular class.
The resulting proxy class cannot exceed the limits of the VM, such as the limitation on the number of interfaces that can be implemented.
To create an actual dynamic proxy class, all you need to do is implement the java.lang.reflect.InvocationHandler interface:
public Class MyDynamicProxyClass implements
java.lang.reflect.InvocationHandler
{
Object obj;
public MyDynamicProxyClass(Object obj)
{ this.obj = obj; }
public Object invoke(Object proxy, Method m, Object[] args) throws
Throwable
{
try {
// do something
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw e;
}
// return something
}
}
That's all there is to it! Really! I'm not lying! Okay, well, you also have to have your actual proxy interface:
public interface MyProxyInterface
{
public Object MyMethod();
}
Then to actually use that dynamic proxy, the code looks like this:
MyProxyInterface foo = (MyProxyInterface)
java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(),
Class[] { MyProxyInterface.class },
new MyDynamicProxyClass(obj));
Knowing that the above code is just horribly ugly, I'd like to hide it in some type of factory method. So instead of having that messy code in the client code, I'll add that method to my MyDynamicProxyClass :
static public Object newInstance(Object obj, Class[] interfaces)
{
return
java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(),
interfaces,
new
MyDynamicProxyClass(obj));
}
That allows me to use the following client code instead:
MyProxyInterface foo = (MyProxyInterface)
MyDynamicProxyClass.newInstance(obj, new Class[]
{ MyProxyInterface.class });
That is much cleaner code. It might be a good idea in the future to have a factory class that completely hides the entire code from the client, so that the client code looks more like:
MyProxyInterface foo = Builder.newProxyInterface();
Overall, implementing a dynamic proxy is fairly simple. However, behind that simplicity is great power. That great power is derived from the fact that your dynamic proxy can implement any interface or interface group. I'll explore that concept in the next section.
Abstract data
The best example of abstract data is in the Java collection classes such as java.util.ArrayList , java.util.HashMap , or java.util.Vector . Those collection classes are capable of holding any Java object. They are invaluable in their use in Java. The concept of abstract data types is a powerful one, and those classes bring the power of collections to any data type.
Tying the two together
By combining the concept of dynamic proxies with abstract data types, you can gain all the benefits of abstract data types with strong typing. In addition, you can easily use the proxy class to implement access control, virtual proxies, or any other useful proxy type. By masking the actual creation and use of proxies from the client code, you can make changes to the underlying proxy code without affecting the client code.
The concept of a view
When architecting a Java program, it is common to run into design problems in which a class must display multiple, different interfaces to client code. Take Figure 2 for example:
Figure 2. Class Diagram of Person
public class Person {
private String name;
private String address;
private String phoneNumber;
public String getName() { return name; }
public String getAddress() { return address; }
public String getPhoneNumber() { return phoneNumber; }
public void setName(String name) { this.name = name; }
public void setAddress(String address) { this.address = address; }
public void setPhoneNumber(String phoneNumber) { this.phoneNumber =
phoneNumber; }
}
public class Employee extends Person {
private String SSN;
private String department;
private float salary;
public String getSSN() { return ssn; }
public String getDepartment() { return department; }
public float getSalary() { return salary; }
public void setSSN(String ssn) { this.ssn = ssn; }
public void setDepartment(String department) { this.department =
department; }
public void setSalary(float salary) { this.salary = salary; }
}
public class Manager extends Employee {
String title;
String[] departments;
public String getTitle() { return title; }
public String[] getDepartments() { return departments; }
public void setTitle(String title) { this.title = title; }
public void setDepartments(String[] departments) { this.departments =
departments; }
}
In that example, a Person class contains the properties Name , Address , and PhoneNumber . Then, there is the Employee class, which is a Person subclass and contains the additional properties SSN , Department , and Salary . From the Employee class, you have the subclass Manager , which adds the properties Title and one or more Departments for which Manager is responsible.
After you've designed that, you should take a step back and think about how the architecture is to be used. Promotion is one idea that you might want to implement in your design. How would you take a person object and make it an employee object, and how would you take an employee object and make it a manager object? What about the reverse? Also, it might not be necessary to expose a manager object as anything more than a person object to a particular client.
A real-life example might be a car. A car has your typical interface such as a pedal for accelerating, another pedal for braking, a wheel for turning left or right, and so forth. However, another interface is revealed when you think of a mechanic working on your car. He has a completely different interface to the car, such as tuning the engine or changing the oil. In that case, to expect the car's driver to know the car's mechanic interfac
Read
Tutorial at: Click here to view the tutorial
Rate Tutorial: Explore the
Dynamic Proxy API
View Tutorial: Explore the
Dynamic Proxy API
Related
Tutorials:
Java Tip 56: How to
eliminate debugging problems for RMI-based applications - JavaWorld - July 1998
Java Tip 56: How to
eliminate debugging problems for RMI-based applications - JavaWorld - July 1998 |
Java Tip 71: Use
dynamic messaging in Java - JavaWorld - April
1999
Java Tip 71: Use
dynamic messaging in Java - JavaWorld - April
1999 |
Create automated and distributed
management applications with Jiro
technology, Part 1 - JavaWorld February
Create automated and distributed
management applications with Jiro
technology, Part 1 - JavaWorld February 2000 |
Make room for JavaSpaces, Part 3 - JavaWorld March
2000
Make room for JavaSpaces, Part 3 - JavaWorld March
2000 |
Take control of the servlet environment, Part 1 - JavaWorld November 2000
Take control of the servlet environment, Part 1 - JavaWorld November 2000 |
Clean up your wire protocol with SOAP, Part 4 - JavaWorld July
2001
Clean up your wire protocol with SOAP, Part 4 - JavaWorld July
2001 |
Explore the
Dynamic Proxy API
Explore the
Dynamic Proxy API |
Implement Design
by Contract for Java using dynamic proxies
Implement Design
by Contract for Java using dynamic proxies |
Take control with the Proxy design pattern
Take control with the Proxy design pattern |
Integrate Java and C++ with Jace
Integrate Java and C++ with Jace |
Discover and publish Web services with JAXR
Discover and publish Web services with JAXR |
J2SE 1.4
breathes new life into the CORBA community, Part
1
J2SE 1.4
breathes new life into the CORBA community, Part
1 |
Very
interesting
Very
interesting |
Second-generation aspect-oriented
programming
Second-generation aspect-oriented
programming |
HA-JDBC: High-Availability JDBC
HA-JDBC: High-Availability JDBC
Summary
HA-JDBC is a JDBC driver proxy that provides light-weight, transparent clustering capability to any underlying JDBC driver.
|
Java validation with dynamic proxies
Decouple validation processes from your business object implementations. |
Develop aspect-oriented Java applications with Eclipse and AJDT
AspectJ is an aspect-oriented extension of the Javaâ„¢ language that enables a modular implementation of crosscutting concerns. This crosscutting behavior, which can be static or dynamic, presents an extra challenge to tools that support AspectJ. The AJDT |
Dynamic Delegation and Its Applications
Dynamic Delegation and Its Applications
The Proxy pattern is an important and widely used design pattern in object-oriented programming. Do you ever use Proxy in Java since its introduction in JDK 1.3? A dynamic proxy class is a class that implements a l |
Java Tech: Acquire Images with TWAIN and SANE, Part 1
Scanners, digital cameras, and other image-acquisition devices are part of the computing landscape. Despite their ubiquity, however, Java does not provide a standard API for interacting with these devices. And yet there certainly is a desire to have a sta |
Mock Objects in Unit Tests
EasyMock is a well-known mock tool that can create a mock object for a given interface at runtime. |
|
|
|