Lima-Loa is an automated implementation of the Gang of Four Adapter Design Pattern, for Java. It aims to greatly reduce or get rid of the need to write dull boiler plate code when creating an adapter.
Lima-Loa is Open Source software, published under the Apache License, version 2.0.
The Gang of Four Design Patterns book describes the intent of the Adapter pattern as follows:
Convert the interface of a class into another interface interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
One implementation of the adapter pattern (class adapters) involves multiple inheritance, so is not possible using the Java programming language. Another implementation (object adapters) involves object composition, and is the typical solution when using Java. The following UML diagram shows the participants in the object adapter implementation.
The participants are as follows:
Client - calls methods on the source interface. Is unaware that an adapter is even in use.
Source - the interface the client calls, that most likely uses concepts familiar to the client (i.e. the client's domain).
Adapter - adapts method calls from the source interface to the target object.
Target - the object being adapted, i.e. the adaptee.
In the above diagram, the client calls
methodA(int} on the adapter, which then triggers the adapter to call
methodB(long) on the target object. The adapter then passes the result of the target method call back to the
client. In order to do this, the adapter must convert the
int parameter to a
long, then the
boolean result to a
Typically an object adapter would need to be manually written by a developer. In the above simple example that would not be particularly difficult, but in a more complex example where the parameters and results are large graphs of Java objects (e.g. custom JavaBeans) and where exceptions must also be mapped, a reasonably large amount of dull yet brittle code would need to be manually written.
Lima-loa is an automated implementation of an object adapter, and intends to replace large amounts of such dull yet brittle code with a relatively small amount of configuration.
Lima-Loa is a pure Java library, and requires JDK 1.4 or above.
Lima-Loa requires the below list of libraries. For ease these are included in the "libs" folder of the distribution. Other versions of these libraries may well work, they simply haven't been tested.
There are two ways to use Lima-Loa, both have exactly the same functionality:
Direct API - slightly more effort and creates a compile-time dependency but is great if you want a pure Java solution.
Spring Integration - very simple, keeps your application loosely coupled, and is great if you are using the Spring Framework.
Firstly, create an instance of AdapterFactory by calling one of the following methods on the org.limaloa.AdapterFactory class:
public static AdapterFactory getInstance() public static AdapterFactory getInstance(List mappingFiles)
The list of mapping files are for Dozer, more on this later.
These factory instances are relatively expensive objects and are intended to be re-used, for example if you need to create more than one adapter object.
Next, create an adapter object by calling the following method on the factory instance:
public Object createAdapter(Class sourceInterface, Object target, Map methodMappings) throws AdapterCreationException
This returns an object that implements sourceInterface. The target is the object you'd like any adapter method calls to be redirected to, i.e. the object being adapted. The methodMappings is a map of target object method names, keyed by source interface method names. At runtime, all calls to the adapter are seamlessly redirected to the nominated method in the target object.
An exception is thrown if there is anything wrong with the specified configuration. As much as possible is checked at creation time, rather than at runtime.
See the "direct-api/simple" example in the "samples" folder of the distribution for a fully working example. See the ReadMe.txt file in that folder for details of the example.
Lima-Loa is a Spring extension, so you simply add it to the classpath and you can use a new schema in your Spring Application Context xml files. Under the covers, the Spring Integration simply calls the Direct API, so the functionality is identical.
Firstly, add the Lima-Loa schema to your Application Context xml file:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:ll="http://www.limaloa.org/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.limaloa.org/schema http://www.limaloa.org/schema/limaloa.xsd">
Then create an Adapter Configuration (this corresponds to an AdapterFactory) as follows:
Note that unless you need to define some Dozer mapping files then this step is actually optional - if no adapterConfiguration is defined then a default one will be created on demand. Note also that only one adapterConfiguration is allowed per Application Context (this includes any parent xml files in a hierarchical Application Context), if more than one is found then an exception is thrown.
If you would like to specify Dozer mapping files, the syntax is as follows:
<ll:adapterConfiguration> <ll:configFiles> <ll:file>custom-bean-mapping1.xml</ll:file> <ll:file>custom-bean-mapping2.xml</ll:file> </ll:configFiles> </ll:adapterConfiguration>
Next, create an adapter as follows:
<ll:adapter id="source" interface="..source interface.." targetObject="target"> <ll:methodMapping source="sourceMethod1" target="targetMethod1"/> <ll:methodMapping source="sourceMethod2" target="targetMethod2"/> </ll:adapter>
This creates an object that implements interface. The targetObject is a reference to a Spring bean you'd like any adapter method calls to be redirected to, i.e. the object being adapted. The methodMappings map source interface method names to target object method names. At runtime, all calls to the adapter are seamlessly redirected to the nominated method in the target object.
The adapter is a bean instance that can be used just as any other Spring bean, for example it can be injected as a property into another object. That other object need not know that Lima-Loa is even being used, as its only dependency is on the source interface.
As with the Direct API, an exception is thrown if there is anything wrong with the specified configuration. As much as possible is checked at creation time, rather than at runtime.
See the "spring/simple" example in the "samples" folder of the distribution for a fully working example. See the ReadMe.txt file in that folder for details of the example.
Method mappings are pretty simple in this release, expect this to become more comprehensive in future releases. Only instance methods are supported. Due to referring to methods by names right now, overloaded methods are not supported - if more than one method is found matching a configured source interface or target object method name, then an exception is thrown.
Mapping of "basic" types is handled directly by a built-in mapper, and anything else is delegated to Dozer - which is an Open Source library intended for mapping custom JavaBeans.
The built-in mappings handle the following situations:
Any use of unsupported combinations (marked as "No" in the table above) results in a
*1 - Treats "true" (case-insensitive) as true, anything else (including null) as "false",
*2 - Uses the appropriate
Wrapper.valueOf(String) method, which throws
java.lang.NumberFormatException if invalid, null or empty.
*3 - Converts the raw 16-bit character value to a number, for example 'A' becomes 65.
*4 - Expects single character length Strings,
at runtime if the String is empty or length is more than 1.
*5 - Checks the numeric value is not too large or too negative to fit into the destination
at runtime if the value cannot fit into the destination type. For example, if converting from
byte, the source value must be from -128 to +127.
is an object mapper for custom JavaBeans. It expects objects to follow the JavaBean
conventions (have a no arguments constructor, and have getter and setter methods
for each attribute), and can handle "graphs" of nested and dependent objects of any
depth. By default it will map attributes in any source type to attributes
in any destination type by attribute name, with any attributes that don't have a matching
name in the destination object being left at
null. To define attribute
mappings when the attribute name differs, or the object graph itself differs, you
simply define a Dozer XML mapping file.
When using Dozer within Lima-Loa, XML mapping files are defined in the parameter
to the org.limaloa.AdapterFactory
method (if using the Direct API), or are defined by
<configFiles> XML elements
<adapterConfiguration> XML element (if using the Spring Integration).
See the "direct-api/custom-bean" example in the "samples" folder of the distribution for a fully working example of using Dozer with Lima-Loa via the Direct API. See the ReadMe.txt file in that folder for details of the example.
See the "spring/custom-bean" example in the "samples" folder of the distribution for a fully working example of using Dozer with Lima-Loa via Spring Integration. See the ReadMe.txt file in that folder for details of the example.
Mapping of exceptions is not supported in this release. Expect comprehensive
exception mapping to be added in future releases. Any checked or unchecked exceptions
thrown by a target method call are rethrown by Lima-Loa as
java.lang.reflect.InvocationTargetException, with the original
exception in the cause.
Copyright 2009 Chris Nappin
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.