A Note on Java Dynamic Proxies

What are dynamic proxies?

Dev Yahya
TheLeanProgrammer
4 min readApr 26, 2020

--

We all would have come across the proxy pattern, at least when we speak of Java RMI. Java 1.3 introduced Dynamic Proxies, a generic way of using the proxy pattern. It gives a simple functionality with reflection. However, the flexibility and usage that it provides are beyond our imagination.

The proxies — An Overview?

The proxies can be explained a pretty straight forward.

The Proxy Pattern provides a surrogate or placeholder for another object to control access to it.

— “Freeman couple” in the book “Head First Design Patterns”

Instead of giving a real object to the implementation, a proxy or a placeholder object is given. The implementation works with the given proxy without caring how the proxy controls access to the real objects. The proxy can do any additional operation before and after the real objects’ work. We will see how this works with an example later.

What Java Dynamic Proxies Provide?

Java Dynamic Proxies provide a generic way of creating proxy objects.

It provides an interface called “InvocationHandler”. Any method that is called over the proxy object will be routed through the “invoke” method of InvocationHandler. This method will be implemented by the developers and they can incorporate any logic there.

Once our InvocationHandler is ready, we can create a proxy object with the static method “newProxyInstance” provided in the “Proxy” class. This method takes a class loader, a list of interfaces to be implemented for the proxy, and the invocation handler which we discussed above. The created proxy can be cast to any of the interfaces provided as the argument to newProxyInstance method. We can give this interface reference to the business logic implementation, and the business logic can work with it without any concerns.

Let’s see how we can implement an authorization functionality with these proxies. Consider a set of operation which can only be done by users who has admin privilege in the application. We can see a simple class diagram of the app below.

Simple object structure in the app

The conventional way of achieving this functionality is that we add the checks in all those methods individually. We will be adding this check to addEntity, updateEntity, and getEntity methods of EntityPersistanceImpl which incorporated the core functionality of the app. These are boilerplate code that is needed for those methods, but that makes the core logic clumsy. Also, the future generation of developers needs to be reminded that they should append proper authorization when adding new functionality to EntityPersistanceImpl. Red flags!!!!!! Can we make this better? Yes… At least, we can try.

Instead of giving a concrete EntityPersistanceImpl, we are giving a proxy of EntetityPersistanceImpl to the Driver program. Let us design the proxy. First, we are gonna create an invocation handler “AdminPermissionHandler” by implementing InvocationHandler interface.

As you can see, the invoke method gets the user param from the param list and validates that the user is an admin, i.e., the same logic that we implemented in all the methods of EntetityPersistanceImpl. We also need an interface for EntetityPersistanceImpl to be handed over to the driver. It will look as follows.

EntetityPersistanceImpl will implement this interface and it will have only the core business logic. Finally, the driver program which tries these operations.

As you see, the driver program does not need any kind of knowing what EntityPersistanceAPI holds.

The final result will be as follows:

Result

Now, we have separated the concerns in a better way. We don’t need to bother about adding new functionality.

For example, we later introduce a delete functionality i.e., deleteEntity(Entity entity, User user) method is introduced. The authorization will be handled without a single line of extra code. Also, we want to change authorization logic, it has to be done at a single place.

If there are some specific cases where we need to skip this authorization, we can handle the actual object to those implementations, i.e., without proxying.

This is just a simple example of using proxies. We can extend it to entity-based authorization and method based authorization using annotations. Other areas in which proxies can be useful are

  1. Transaction management
  2. Mocking while testing (If the resource is over remote or need some intensive operations, the invocation handler can skip the transfer of control to the real object itself. Instead, it can just return a mock result)
  3. Instrumentation (We can do any type of instrumentation over all the methods based on some pre-configured settings)

As said earlier, a proxy is simple but powerful. It’s is up to our imagination to employ it.

Hope you enjoyed the article!

Don’t forget to follow The Lean Programmer Publication for more such articles, and subscribe to our newsletter tinyletter.com/TheLeanProgrammer

--

--