Transformation Proxies

Maarten Winkels

One of the most important language features of java is the dynamic proxy. At some point, the ability to create dynamic proxies must have saved Java from disappearing in the dull world of strict object oriented languages. Nowadays dynamic proxies are mainly used by frameworks like Spring AOP and Hibernate, but once in a while an opportunity arises to use a dynamic proxy in application code.

Dynamic Proxies

The dynamic proxy mechanism allows the developer to create an implementation of an interface without directly writing the implementing class. Instead the developer writes a java.lang.reflect.InvocationHandler and attaches it to a java.lang.reflect.Proxy instance. The proxy instance will be given the interface as well and the Java Platform will ensure that the resulting instance will implement the interface. All method invocations on the instance will go through the invoke method of the InvocationHandler.

So what good is that? We still have to write a class! Instead of simply writing an implementation of the interface, we have to write a class with a single method that will contain all business logic.

The mechanism is especially useful with cross-cutting concerns, such as security, transparent persistency or transaction support. These are features that you would want to apply to a lot of methods in a similar manner. The dynamic proxy allows for one implementation of this feature to apply to all methods in an interface.

This is what the frameworks use it for. Generally a delegate will be used. In the invocation handler the cross-cutting concern is applied to the invocation and then the same method is invoked on the delegate. The delegate will thus implement the same interface as the proxy.

Transformation

In one of my last projects I encountered a different situation in which a dynamic proxy was useful. The project was a very simple web application that would provide a user interface on top of a number of web services. The web services were already implemented and a WSDL file was provided. I used Apache Axis to generate the Java code necessary to communicate with the web services. Now this generated code was very complex. It used a single “In” and a single “Out” parameter for each webservice. These classes were not suitable for the web application I was building. So they would have to be transformed to the simple objects used in the rest of the application.

There were a number of web methods that the application would use and therefore this transformation process was a cross-cutting concern. Now the interface to the web services that the application would use would be much simpler than the interface that the AXIS generated classes provided. More specifically, it would have multiple simple argument types to each method instead of one complex one and a simple return type. Delegation would therefore not be possible.

So what would the design of the InvocationHandler be like? It should know which transformer to invoke for which method invocation. The transformer should know how to transform the simple input types of the application interface to the single complex input type of the webservice and how to convert the complex output type of the webservice to the simple output type of the application interface. Furthermore these transformers could not share an interface, since the signature of the transformation methods would be different for each method. The transform method for the input would have the same parameter types as the method on the application interface and the input type of the web service as result type. The transform method for the output would have the output type of the web service as single parameter type and the result type of the application interface as result type. The transformation would therefore use reflection and a naming convention to find the correct transformation methods. The invocation on the delegate (in this case the AXIS generated classes that will execute the web service invocation) will also use reflection. The method that should be invoked is different on at least two accounts from the method on the interface that was invoked; the input parameter types and the return type. For simplicity, the method name is assumed to be the same.

The core of the implementation is pretty simple:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	String methodName = method.getName();
	
	Object transformer = transformers.get(methodName);
	
	if (transformer == null) {
		throw new ConfigurationException("Found no transformer for: '"+methodName+"'.");
	}
	
	Object actualArgument = transformInput(method, args, transformer);
	Object soapAnswer = callDelegate(methodName, actualArgument);
	return transformOutput(transformer, soapAnswer);
}

The complexity is mainly in the error handling of the reflection. This is now hidden in the methods that are used in the code fragment above (see attachment for complete source code). If an error occurs, either during the transformation or during the delegation, the error will be wrapped in a java.lang.reflect.UndeclaredThrowableException and thrown from the generated Proxy code. This is important if you want to show comprehensive error messages to the user, for example in case of a communication error.

The image above shows the interaction between the proxy instance, the transformer and the delegate. It also tries to explain the “interface” that the transformers should implement. A transformer should thus have a

ComplexTypeIn transformIn (SimpleTypeIn1, SimpleTypeIn2, …)

method and a

SimpleTypeOut transformOut(ComplexTypeOut)

method.

Spring configuration

The web application I was building used Spring for configuration, so I had to wire the proxy in a spring context. To create the correct proxy as a spring bean, a bean factory could be used, just like the org.springframework.aop.framework.ProxyFactoryBean that is used to create Spring AOP proxies, but I choose to configure it using the concrete classes directly.

<bean id="…" class="java.lang.reflect.Proxy" factory-method="newProxyInstance">
	<constructor-arg index="0">
		<bean class="org.springframework.util.ClassUtils" factory-method="getDefaultClassLoader"/>
	</constructor-arg>
	<constructor-arg index="1" value="MyInterface"/>
	<constructor-arg index="2">
		<bean class="com.xebia.proxy. Transformer">
			<constructor-arg index="0">
				<ref bean=”delegate”/>
			</constructor-arg>
			<constructor-arg index="1">
				<map>
					<entry key="methodname1">
						<ref bean=”transformer1”/>
					</entry>
					<entry key="methodname2">
						<ref bean=”transformer2”/>
					</entry>
					…
				</map>
			</constructor-arg>
		</bean>
	</constructor-arg>
</bean>

The default classloader that is used will return the thread context class loader if available. This will allow this context to be included in a spring context that is loaded from another deployment package (.JAR, .WAR or .EAR). This allows the transformation proxy, both code and configuration, to be shared between multiple (web) applications.

See attachment for complete source code.

Comments (0)

    Add a Comment