Home > Articles > Programming > Java

This chapter is from the book

3.4 Dynamic Proxies

Dynamic proxies, available since SDK 1.3, are the exact opposite of reflective invocation. With reflective invocation, a client uses a generic API to call methods (on a server class) that are not known at compile time. With dynamic proxies, a server uses a generic API to implement methods on a server class that is manufactured at runtime to meet a client's specification. Dynamic proxies are chameleons that take the shape of any set of interfaces desired by the client. When combined with reflective invocation, dynamic proxies can implement generic interceptors. An interceptor is a piece of code that sits between a client and a server and adds an additional service, such as transaction enlistment, auditing, security checking, or parameter marshalling. A generic interceptor requires no compile-time knowledge of the client or server APIs being intercepted.

3.4.1 Delegation instead of Implementation Inheritance

Generic interception makes it possible to use an object-oriented style based not just on inheritance, but also on delegation. Consider an entity class that accesses employee information from a database. If you wanted to use inheritance to layer in transaction enlistment, auditing, and security checks, you would need to use multiple inheritance. After pointing out that multiple implementation inheritance does not exist in Java, you might also object to the fact that this design would require eight different concrete subclasses of Employee, one each for every possible service being turned on or off, as shown in Figure 3–3. In general, adding another service doubles the number of concrete subclasses you need.

Figure 3–3 Implementation inheritance causes class proliferation.

With delegation, each new service adds only one class, and classes are simply chained together to provide the exact mix of services needed, as shown in Figure 3–4.

Figure 3–4 Delegation requires only one class per service.

3.4.2 Dynamic Proxies Make Delegation Generic

Historically, the problem with the delegation model was how to make each service generic. For example, an Audit class would need to implement EmployeeItf when it was dealing with an Employee entity, but it would need to implement InventoryItf when it was dealing with the Inventory entity. Also, the service classes would need to implement interfaces that had not even been designed yet. Dynamic proxies neatly solve this problem by allowing the transaction class to manufacture an implementation of whatever interface the client expects at runtime.

To manufacture a dynamic proxy, you need only call Proxy.newProxyInstance, passing in an implementation of the InvocationHandler interface. Summaries of these classes appear in Listing 3–20. The newProxyInstance method manufactures a new binary class in memory. This special class implements all the interfaces passed in the itfs array by forwarding every single method to an instance of InvocationHandler. Then, the new class is loaded into the virtual machine by the class loader specified by ldr, and it is used to construct a proxy instance that forwards to handler.

Listing 3–20 Key Elements of Proxy and InvocationHandler

package java.lang.reflect;
public class Proxy { 
 static Object newProxyInstance(ClassLoader ldr, 
		Class[] itfs, InvocationHandler handler)
        throws IllegalArgumentException;
 //remainder omitted for clarity
}
public interface InvocationHandler {
 public Object invoke(Object proxy, Method method, 
            Object[] args) throws Throwable;
}

3.4.3 Implementing InvocationHandler

Dynamic proxies allow you to implement a single invoke method on the invocation handler and then use it to service any interface you choose at runtime. For example, consider an InvocationHandler that logs method calls, shown in Listing 3–21. This LoggingHandler class provides a trivial implementation of any interface that simply logs method calls as they are made. DemoLogging demonstrates using the LoggingHandler to log calls to DataOutput. One possible use for LoggingHandler is during development, when you need to stub out an interface that you have not yet implemented.

Notice that the toString method is treated specially. In addition to any interface methods, dynamic proxies always forward the Object methods toString, hashCode, and equals to the handler. In this case, the proxy's toString method is invoked by the handler's call to System.out.println. If the toString method were not special-cased, the call to toString would trigger the invoke method of LoggingHandler, which triggers another call to toString, and so on, recursing until the stack overflowed.

Listing 3–21 LoggingHandler

import java.lang.reflect.*;
public class LoggingHandler implements InvocationHandler {
 public Object invoke(Object proxy, Method method, 
            Object[] args) throws Throwable 
{
  if (method.getName().equals("toString")) {
   return super.toString();
  }
  System.out.println("Method " + method + 
            " called on " + proxy);
  return null;
 }
}
import java.lang.reflect.*;
import java.io.*;
public class DemoLogging {
 public static void main(String [] args) 
  throws IOException
 {
  ClassLoader cl = DemoLogging.class.getClassLoader();
  DataOutput d = (DataOutput) Proxy.newProxyInstance(cl, 
                new Class[] {DataOutput.class},
                new LoggingHandler());
  d.writeChar('a');
  d.writeUTF("stitch in time");
 }
}

3.4.4 Implementing a Forwarding Handler

Although "standalone" dynamic proxies such as LoggingHandler are useful, they suffer from a major limitation in dealing with return values. Because they are totally generic, InvocationHandlers have no idea how to generate a legitimate return value for a method call. LoggingHandler finesses this issue by always returning null, which the generated proxy class will coerce to the return type of the interface method. In Listing 3–21, the DataOutput methods happen to return void, so the generated proxy simply ignores the return from LoggingHandler's invoke method. This coincidence will not hold up in more complex cases, those in which methods might return any type, and the compile-time type might need to be further constrained at runtime in accordance with the documented semantics of the method. In order to reasonably mimic any arbitrary interface, a dynamic proxy will either need to know the semantics of the interface, or it will need to forward the method call to some other object that does. Since the raison d'être of a proxy is to be generic, knowing the specifics on an interface is not an option. Instead, most dynamic proxies are used to forward calls to other objects.

The strength of dynamic proxies is method call forwarding. A dynamic proxy can intercept a method call, examine or modify the parameters, pass the call to some other object, examine or modify the result, and return that result to the caller. When correctly configured, dynamic proxies work transparently without the knowledge of either the client or server code.

Figure 3–5 shows how a dynamic proxy enables generic services. A generic service implements only one method, InvocationHandler.invoke, and forwards the call using only one method, Method.invoke. Without changing, or even reading, any existing implementation code, you can insert a dynamic proxy between two objects to inject some additional service.

Figure 3–5 Dynamic proxies enable generic services.

3.4.5 The InvocationHandler as Generic Service

To appreciate the power and simplicity of this model for reuse, imagine the following scenario: A large server application has been ported to Java and continues to access legacy code through a bridge that presents the legacy code as a set of Java interfaces. Unfortunately, the legacy code was written in a pointer-based language and experiences occasional memory corruption. The specific symptom is that methods sometimes return the java.util.Date "Thu Dec 25 07:42:41 EST 1969."5 Your task is to guarantee that this bug does not introduce corrupt data into the application.

With dynamic proxies, you can add an interceptor that traps all attempts to return the offending value, as is shown in Listing 3–22. Here, a TrappingHandler forwards all method calls to its delegate. If the delegate functions unexceptionally and returns an object, the handler checks to see if it is a Date instance indicative of the memory corruption bug. If it is, then the handler might throw an error, as the example shows, or it might take whatever other action may be necessary.

Listing 3–22 TrappingHandler

import java.lang.reflect.*;
import java.util.*;
public class TrappingHandler implements InvocationHandler {
 //BAD_DATE is "Thu Dec 25 07:42:41 EST 1969"
 //This value corresponds to an error code on some systems
 public static final Date BAD_DATE = new Date(-559038737);
 private Object delegate;
 public TrappingHandler(Object delegate) {
  this.delegate = delegate;
 }
  public Object invoke(Object proxy, Method method, 
		    Object[] args) throws Throwable {
  Object result = null;
  try {
   result = method.invoke(delegate, args);
  } catch (InvocationTargetException e) {
   throw e.getTargetException();
  }
  if (result instanceof Date) {
   Date d = (Date) result;
   if (d.equals(BAD_DATE)) {
	  throw new Error("Corrupted date " + d);
   }
  }
  return result;
 }
}

3.4.6 Handling Exceptions in an InvocationHandler

It is important to code carefully against the possibility that the delegate will itself throw an exception. Because the handler is generic, you have no compile-time knowledge of what particular exceptions the delegate might throw. However, since the delegate's methods are invoked via reflection, any exception will be wrapped by an InvocationTargetException. You should not let this exception percolate out of the dynamic proxy code.

The dynamic proxy provides some help here. Since a proxy wants to be transparent to the client, it will only permit exceptions that the client expects. To enforce this, a proxy compares any thrown exception to the list of checked exceptions for the current method. If an exception is not in the list, a proxy will wrap it in an UndeclaredThrowableException, which is a RuntimeException subclass that signals a programmer error.

To complete the illusion of transparency, your InvocationHandler must not give the proxy any reason to throw an UndeclaredThrowable Exception. Therefore, the canonical implementation of a forwarding proxy includes a try/catch block that catches the InvocationTargetException and then extracts and throws the underlying exception, which is the one the client expects. Refer back to Listing 3–22, which demonstrates this.

3.4.7 Either Client or Server Can Install a Proxy

Either the client or the server code can wrap suspicious objects with the TrappingHandler before using them. In the TestTrappingHandler example (Listing 3–23), the client wraps an instance of the Test interface. If either getGoodDateValue or getBadDateValue of the Test interface return a bad date, the handler will protect the client by throwing an exception. More importantly, the same TrappingHandler can be used throughout a system to protect any number of different interfaces and implementation classes.

You could make the proxy code transparent to both client and server by using an object factory to hide the details of connecting client and server code.

Listing 3–23 Testing a TrappingHandler

//Test.java
import java.util.*;
interface Test {
 Date getGoodDateValue();
 Date getBadDateValue();
}

//TestTrappingHandler.java
import java.lang.reflect.*;
import java.util.*;

public class TestTrappingHandler implements Test {
 public static void main(String [] args) {
  TestTrappingHandler t = new TestTrappingHandler();
  System.out.println("Testing unwrapped object.\n" +
            "This should permit date value " + 
		       TrappingHandler.BAD_DATE);
  executeTests(t);
  Test wrap = (Test)Proxy.newProxyInstance(
	 TestTrappingHandler.class.getClassLoader(), 
	 new Class[]{Test.class}, new TrappingHandler(t));
  System.out.println("Testing wrapped object.\n" +
            "This should reject date value " + 
            TrappingHandler.BAD_DATE);
  executeTests(wrap);
 }

  public Date getGoodDateValue() {
  return new Date();
 }
 public Date getBadDateValue() {
  return TrappingHandler.BAD_DATE;
 }
 public static void executeTests(Test t) {
  System.out.println(t.getGoodDateValue());
  System.out.println(t.getBadDateValue());
 }
}

3.4.8 Advantages of Dynamic Proxies

Dynamic proxies do not provide any service that you could not provide yourself by hand-coding a custom delegator class for every different interface. The advantage of dynamic proxies over hand-rolled delegators is twofold. First, you do not have to write dynamic proxies. Second, they can be generated on-the-fly at runtime to handle new interfaces as they appear. Because dynamic proxies are generic, they tend to be used for services that do not rely on any specific knowledge of the interface or method being forwarded:

  • Parameter validation or modification, where a parameter value is of interest regardless of where it appears, as in the example above

  • Security checks, some of which can be made based on the identity of the user or the source of the code, not the particular method being called

  • Propagation of "implicit" or "context" parameters, such as the transaction ID, which is automatically handled by an EJB container and does not appear in any interface declaration

  • Auditing, tracing, or debugging of method calls

  • Marshalling a Java method call to some other process, machine, or language

Like any generic tool, dynamic proxies may be inefficient compared to a solution hand-tuned to a particular problem. Situations in which performance considerations may rule out the use of dynamic proxies are discussed in §3.5.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020