001/*
002 *  Copyright 2010, 2011 Chris Pheby
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.jadira.bindings.core.binder;
017
018import java.io.File;
019import java.io.IOException;
020import java.lang.annotation.Annotation;
021import java.lang.reflect.Constructor;
022import java.lang.reflect.Method;
023import java.math.BigDecimal;
024import java.math.BigInteger;
025import java.net.InetAddress;
026import java.net.URI;
027import java.net.URL;
028import java.util.ArrayList;
029import java.util.Calendar;
030import java.util.Currency;
031import java.util.Date;
032import java.util.Enumeration;
033import java.util.HashMap;
034import java.util.HashSet;
035import java.util.List;
036import java.util.Locale;
037import java.util.Map;
038import java.util.Set;
039import java.util.TimeZone;
040import java.util.UUID;
041import java.util.concurrent.ConcurrentHashMap;
042import java.util.concurrent.atomic.AtomicBoolean;
043import java.util.concurrent.atomic.AtomicInteger;
044import java.util.concurrent.atomic.AtomicLong;
045
046import javax.enterprise.inject.Typed;
047
048import org.jadira.bindings.core.annotation.BindingScope;
049import org.jadira.bindings.core.annotation.DefaultBinding;
050import org.jadira.bindings.core.api.Binding;
051import org.jadira.bindings.core.api.Converter;
052import org.jadira.bindings.core.api.FromUnmarshaller;
053import org.jadira.bindings.core.api.ToMarshaller;
054import org.jadira.bindings.core.general.binding.CompositeBinding;
055import org.jadira.bindings.core.general.binding.InverseCompositeBinding;
056import org.jadira.bindings.core.general.converter.FromUnmarshallerConverter;
057import org.jadira.bindings.core.general.converter.ToMarshallerConverter;
058import org.jadira.bindings.core.general.marshaller.ConverterToMarshaller;
059import org.jadira.bindings.core.general.marshaller.MethodToMarshaller;
060import org.jadira.bindings.core.general.unmarshaller.ConstructorFromUnmarshaller;
061import org.jadira.bindings.core.general.unmarshaller.ConverterFromUnmarshaller;
062import org.jadira.bindings.core.general.unmarshaller.MethodFromUnmarshaller;
063import org.jadira.bindings.core.jdk.AtomicBooleanStringBinding;
064import org.jadira.bindings.core.jdk.AtomicIntegerStringBinding;
065import org.jadira.bindings.core.jdk.AtomicLongStringBinding;
066import org.jadira.bindings.core.jdk.BigDecimalStringBinding;
067import org.jadira.bindings.core.jdk.BigIntegerStringBinding;
068import org.jadira.bindings.core.jdk.BooleanStringBinding;
069import org.jadira.bindings.core.jdk.ByteStringBinding;
070import org.jadira.bindings.core.jdk.CalendarStringBinding;
071import org.jadira.bindings.core.jdk.CharSequenceStringBinding;
072import org.jadira.bindings.core.jdk.CharacterStringBinding;
073import org.jadira.bindings.core.jdk.ClassStringBinding;
074import org.jadira.bindings.core.jdk.CurrencyStringBinding;
075import org.jadira.bindings.core.jdk.DateStringBinding;
076import org.jadira.bindings.core.jdk.DoubleStringBinding;
077import org.jadira.bindings.core.jdk.FileStringBinding;
078import org.jadira.bindings.core.jdk.FloatStringBinding;
079import org.jadira.bindings.core.jdk.InetAddressStringBinding;
080import org.jadira.bindings.core.jdk.IntegerStringBinding;
081import org.jadira.bindings.core.jdk.LocaleStringBinding;
082import org.jadira.bindings.core.jdk.LongStringBinding;
083import org.jadira.bindings.core.jdk.PackageStringBinding;
084import org.jadira.bindings.core.jdk.ShortStringBinding;
085import org.jadira.bindings.core.jdk.StringBufferStringBinding;
086import org.jadira.bindings.core.jdk.StringBuilderStringBinding;
087import org.jadira.bindings.core.jdk.StringStringBinding;
088import org.jadira.bindings.core.jdk.TimeZoneStringBinding;
089import org.jadira.bindings.core.jdk.URIStringBinding;
090import org.jadira.bindings.core.jdk.URLStringBinding;
091import org.jadira.bindings.core.jdk.UUIDStringBinding;
092import org.jadira.bindings.core.loader.BindingConfiguration;
093import org.jadira.bindings.core.loader.BindingConfigurationEntry;
094import org.jadira.bindings.core.loader.BindingXmlLoader;
095import org.jadira.bindings.core.loader.Extension;
096import org.jadira.bindings.core.loader.Provider;
097import org.jadira.bindings.core.spi.ConverterProvider;
098import org.jadira.bindings.core.utils.lang.IterableEnumeration;
099import org.jadira.bindings.core.utils.reflection.ClassLoaderUtils;
100
101/**
102 * Core binding capability.
103 * Typically you would obtain an instance of this class either
104 * by direct construction, or in JDK6 and above by using 
105 * <code>java.util.ServiceLoader</code>.
106 * 
107 * Default construction of this class registers bindings for core
108 * JDK classes, as well as any bindings specified using bindings.xml
109 * 
110 * You can also register additional bindings programmatically.
111 * @see Binding Binding is used to define a binding
112 */
113@Typed({})
114public class BasicBinder implements Binder, RegisterableBinder {
115
116        /**
117         * ConverterProviders are used to resolve converters using annotations on the target class.
118         * Because additional converter providers can be registered they provide a mechanism for extending the framework.
119         */
120        private final List<ConverterProvider> converterProviders = new ArrayList<ConverterProvider>();
121        
122        /**
123         * A map of registered converters
124         */
125        private ConcurrentHashMap<ConverterKey<?,?>, Converter<?,?>> registeredConverters = new ConcurrentHashMap<ConverterKey<?,?>, Converter<?,?>>();
126
127        /**
128         * A map of registered converters
129         */
130        private ConcurrentHashMap<Class<?>, Object> extendedBinders = new ConcurrentHashMap<Class<?>, Object>();
131        
132        /**
133         * A reference of classes which have already been introspected for conversion annotations.
134         */
135    private final Set<Class<?>> inspectedClasses = new HashSet<Class<?>>();
136        
137    /**
138     * Creates a new instance, initialised with standard, and registered bindings
139     */
140    public BasicBinder() {
141        this(true);
142    }
143
144    /**
145     * Creates a new instance
146     * @param includeBuiltInBindings If true, initialise with standard, and registered bindings
147     */
148    public BasicBinder(boolean includeBuiltInBindings) {
149
150        initExtendedBinders();
151        
152        if (includeBuiltInBindings) {
153
154            initJdkBindings();
155
156            // Before we load other configuration, load the binding
157            // configuration from
158            // jadira-bindings' jar to ensure no-one overrides our built-in
159            // mappings.
160            initBuiltInBindings();
161
162            // Init bindings registered from other jars
163            initRegisteredBindings();
164        }
165    }
166        
167    /******************
168     *                *
169     * Bootstrapping  * 
170     *                *
171     ******************/
172
173        /**
174         *  Initialise the instance with built in extended binders
175         */
176        private void initExtendedBinders() {
177                extendedBinders.put(StringBinder.class, this);
178        }
179    
180    /**
181     * Initialises standard bindings for Java built in types
182     */
183    private void initJdkBindings() {
184        
185        registerBinding(AtomicBoolean.class, String.class, new AtomicBooleanStringBinding());
186        registerBinding(AtomicInteger.class, String.class, new AtomicIntegerStringBinding());
187        registerBinding(AtomicLong.class, String.class, new AtomicLongStringBinding());
188        registerBinding(BigDecimal.class, String.class, new BigDecimalStringBinding());
189        registerBinding(BigInteger.class, String.class, new BigIntegerStringBinding());
190        registerBinding(Boolean.class, String.class, new BooleanStringBinding());
191        registerBinding(Byte.class, String.class, new ByteStringBinding());
192        registerBinding(Calendar.class, String.class, new CalendarStringBinding());
193        registerBinding(Character.class, String.class, new CharacterStringBinding());
194        registerBinding(CharSequence.class, String.class, new CharSequenceStringBinding());
195        registerBinding(Class.class, String.class, new ClassStringBinding());
196        registerBinding(Currency.class, String.class, new CurrencyStringBinding());
197        registerBinding(Date.class, String.class, new DateStringBinding());
198        registerBinding(Double.class, String.class, new DoubleStringBinding());
199        registerBinding(File.class, String.class, new FileStringBinding());
200        registerBinding(Float.class, String.class, new FloatStringBinding());
201        registerBinding(InetAddress.class, String.class, new InetAddressStringBinding());
202        registerBinding(Integer.class, String.class, new IntegerStringBinding());
203        registerBinding(Locale.class, String.class, new LocaleStringBinding());
204        registerBinding(Long.class, String.class, new LongStringBinding());
205        registerBinding(Package.class, String.class, new PackageStringBinding());
206        registerBinding(Short.class, String.class, new ShortStringBinding());
207        registerBinding(StringBuffer.class, String.class, new StringBufferStringBinding());
208        registerBinding(StringBuilder.class, String.class, new StringBuilderStringBinding());
209        registerBinding(String.class, String.class, new StringStringBinding());
210        registerBinding(TimeZone.class, String.class, new TimeZoneStringBinding());
211        registerBinding(URI.class, String.class, new URIStringBinding());
212        registerBinding(URL.class, String.class, new URLStringBinding());
213        registerBinding(UUID.class, String.class, new UUIDStringBinding());
214    }
215 
216    /**
217     * Initialises bindings registered with the framework included bindings.xml
218     * This includes the built in support for converters for annotation processing and Joda Convert annotations.
219     */
220    private void initBuiltInBindings() {
221
222        final URL builtInBindingsUrl = getBuiltInBindingsURL();
223        registerConfiguration(builtInBindingsUrl);
224    }
225
226        private URL getBuiltInBindingsURL() {
227
228                String classResource = BasicBinder.class.getCanonicalName().replace('.', '/') + ".class";
229        
230        URL bindingClassUrl = Thread.currentThread().getContextClassLoader().getResource(classResource);
231        
232        String classPrefix = bindingClassUrl.toString().substring(0,
233                bindingClassUrl.toString().indexOf(classResource));
234
235        final URL builtInBindingsUrl;
236        try {
237            builtInBindingsUrl = new URL(classPrefix + "META-INF/bindings.xml");
238        } catch (IOException e) {
239            throw new IllegalStateException("Error registering bindings: " + e.getMessage(), e);
240        }
241                return builtInBindingsUrl;
242        }
243    
244    /**
245     * Initialises any bindings bundled with other (third-party / user) jars
246     */
247    private void initRegisteredBindings() {
248        
249        Enumeration<URL> bindingsConfiguration;
250        try {
251            bindingsConfiguration = ClassLoaderUtils.getClassLoader().getResources("META-INF/bindings.xml");
252        } catch (IOException e) {
253            throw new IllegalStateException("Error registering bindings: " + e.getMessage(), e);
254        }
255
256        registerConfigurations(bindingsConfiguration);
257    }
258
259    /**
260     * Registers a set of configurations for the given list of URLs. 
261     * This is typically used to process all the various bindings.xml files discovered in
262     * jars on the classpath. It is given protected scope to allow subclasses to register
263     * additional configurations
264     * @param bindingsConfiguration An enumeration of the URLs to process
265     * @param <X> Internally used type argument
266     */
267    protected <X> void registerConfigurations(Enumeration<URL> bindingsConfiguration) {
268        List<BindingConfiguration> configs = new ArrayList<BindingConfiguration>();
269        for (URL nextLocation : IterableEnumeration.wrapEnumeration(bindingsConfiguration)) {
270            
271                // Filter built in bindings - these are already registered by calling registerConfiguration directly
272                URL builtIn = getBuiltInBindingsURL();
273                if (!builtIn.toString().equals(nextLocation.toString())) {
274                        configs.add(BindingXmlLoader.load(nextLocation));
275                }
276        }
277        
278        for (BindingConfiguration nextConfig : configs) {
279                for (Provider nextProvider : nextConfig.getProviders()) {
280            
281                        try {
282                            registerConverterProvider(nextProvider.getProviderClass().newInstance());
283                        } catch (InstantiationException e) {
284                            throw new IllegalStateException("Cannot instantiate binding provider class: " + nextProvider.getProviderClass().getName());
285                        } catch (IllegalAccessException e) {
286                            throw new IllegalStateException("Cannot access binding provider class: " + nextProvider.getProviderClass().getName());
287                        }
288                }
289                
290                for (Extension<?> nextExtension : nextConfig.getExtensions()) {
291                        try {
292                                @SuppressWarnings("unchecked") Extension<X> myExtension = (Extension<X>)nextExtension;
293                                @SuppressWarnings("unchecked") X myImplementation = (X) nextExtension.getImplementationClass().newInstance();
294                                registerExtendedBinder(myExtension.getExtensionClass(), myImplementation);
295                        } catch (InstantiationException e) {
296                            throw new IllegalStateException("Cannot instantiate binder extension class: " + nextExtension.getExtensionClass().getName());
297                        } catch (IllegalAccessException e) {
298                            throw new IllegalStateException("Cannot access binder extension class: " + nextExtension.getExtensionClass().getName());
299                        }
300                }
301        
302            registerBindingConfigurationEntries(nextConfig.getBindingEntries());
303        }
304    }
305    
306    /**
307     * Register the configuration file (bindings.xml) at the given URL 
308     */
309    public final void registerConfiguration(URL nextLocation) {
310        
311        BindingConfiguration configuration = BindingXmlLoader.load(nextLocation);
312
313        for (Provider nextProvider : configuration.getProviders()) {
314            
315            try {
316                registerConverterProvider(nextProvider.getProviderClass().newInstance());
317            } catch (InstantiationException e) {
318                throw new IllegalStateException("Cannot instantiate binding provider class: " + nextProvider.getProviderClass().getName());
319            } catch (IllegalAccessException e) {
320                throw new IllegalStateException("Cannot access binding provider class: " + nextProvider.getProviderClass().getName());
321            }
322        }
323        
324        registerBindingConfigurationEntries(configuration.getBindingEntries());
325    }
326    
327    /**
328     * Method used to register one or more converter providers. Converters extend the binding framework to provide 
329     * additional mechanisms for discovering and registering bindings (e.g. using Joda Convert).
330     * This method is protected so that subclasses can register additional providers.
331     * @param providers A collection of providers
332     */
333    public void registerConverterProviders(ConverterProvider... providers) {
334
335        for (ConverterProvider nextProvider : providers) {
336            registerConverterProvider(nextProvider);
337        }
338    }
339    
340    /**
341     * Register a single converter provider
342     * @param provider The provider.
343     */
344    public void registerConverterProvider(ConverterProvider provider) {
345        this.converterProviders.add(provider);
346    }
347    
348    /**
349     * Registers a list of binding configuration entries. A binding configuration entry described in a section of a bindings.xml file 
350     * and describes the use of a particular method for databinding.
351     * @param bindings The entries to register
352     */
353    protected void registerBindingConfigurationEntries(Iterable<BindingConfigurationEntry> bindings) {
354
355        for (BindingConfigurationEntry nextBinding : bindings) {
356                try {
357                        registerBindingConfigurationEntry(nextBinding);
358                } catch (IllegalStateException e) {
359                        // Ignore this - it can happen when introspecting class mappings
360                }
361        }
362    }
363    
364    /**
365     * Register a particular binding configuration entry.
366     * @param theBinding The entry to be registered
367     * @param <S> The Source type for the binding
368     * @param <T> The Target type for the binding
369     */
370        protected <S,T> void registerBindingConfigurationEntry(BindingConfigurationEntry theBinding) {
371                
372        /*
373         * BindingConfigurationEntry has two possible configurations:
374         * 
375         * bindingClass with an optional qualifier (this defaults to DefaultBinding)
376         * 
377         *  OR
378         *  
379         * sourceClass and
380         * targetClass and
381         * optional qualifier (defaults to DefaultBinding)
382         * with at least one of either
383         * toMethod and/or
384         * fromMethod and/or
385         * fromConstructor         
386         * 
387         * Depending on which components are populated the entry is interpreted differently.
388         */
389                
390                if (Binding.class.isAssignableFrom(theBinding.getBindingClass())) {
391                
392                /*
393                 * If the binding class is an instance of the Binding interface then register it.
394                 * When the binding class is an interface, you must define source and target class if they cannot be
395                 * determined from introspecting the interface.
396                 * 
397                 * You can optionally supply a qualifier so that the binding is associated with a qualifier
398                 */
399                try {
400                        @SuppressWarnings("unchecked")
401                                Binding<S,T> binding = (Binding<S,T>)theBinding.getBindingClass().newInstance();
402                registerBinding(binding.getBoundClass(), binding.getTargetClass(), binding, theBinding.getQualifier());
403            } catch (InstantiationException e) {
404                throw new IllegalStateException("Cannot instantiate binding class: " + theBinding.getBindingClass().getName());
405            } catch (IllegalAccessException e) {
406                throw new IllegalStateException("Cannot access binding class: " + theBinding.getBindingClass().getName());
407            }
408        } else if (FromUnmarshaller.class.isAssignableFrom(theBinding.getBindingClass())) {
409                
410                /*
411                 * If the binding class is an instance of the FromUnmarshaller interface then register it.
412                 * When the class is an interface, you must define source and target class if they cannot be
413                 * determined from introspecting the interface.
414                 * 
415                 * You can optionally supply a qualifier so that the binding is associated with a qualifier
416                 */
417                try {
418                        @SuppressWarnings("unchecked")
419                                FromUnmarshaller<S,T> fromUnmarshaller = (FromUnmarshaller<S,T>)theBinding.getBindingClass().newInstance();
420                registerUnmarshaller(fromUnmarshaller.getBoundClass(), fromUnmarshaller.getTargetClass(), fromUnmarshaller, theBinding.getQualifier());
421            } catch (InstantiationException e) {
422                throw new IllegalStateException("Cannot instantiate binding class: " + theBinding.getBindingClass().getName());
423            } catch (IllegalAccessException e) {
424                throw new IllegalStateException("Cannot access binding class: " + theBinding.getBindingClass().getName());
425            }
426                } else if (ToMarshaller.class.isAssignableFrom(theBinding.getBindingClass())) {
427                
428                /*
429                 * If the binding class is an instance of the ToMarshaller interface then register it.
430                 * When the class is an interface, you must define source and target class if they cannot be
431                 * determined from introspecting the interface.
432                 * 
433                 * You can optionally supply a qualifier so that the binding is associated with a qualifier
434                 */
435                try {
436                        @SuppressWarnings("unchecked")
437                                ToMarshaller<S,T> toMarshaller = (ToMarshaller<S,T>)theBinding.getBindingClass().newInstance();
438                registerMarshaller(toMarshaller.getBoundClass(), toMarshaller.getTargetClass(), toMarshaller, theBinding.getQualifier());
439            } catch (InstantiationException e) {
440                throw new IllegalStateException("Cannot instantiate binding class: " + theBinding.getBindingClass().getName());
441            } catch (IllegalAccessException e) {
442                throw new IllegalStateException("Cannot access binding class: " + theBinding.getBindingClass().getName());
443            }
444                } else if (Converter.class.isAssignableFrom(theBinding.getBindingClass())) {
445                
446                /*
447                 * If the binding class is an instance of the Converter interface then register it.
448                 * When the class is an interface, you must define source and target class if they cannot be
449                 * determined from introspecting the interface.
450                 * 
451                 * You can optionally supply a qualifier so that the binding is associated with a qualifier
452                 */
453                try {
454                        @SuppressWarnings("unchecked")
455                                Converter<S,T> converter = (Converter<S,T>)theBinding.getBindingClass().newInstance();
456                registerConverter(converter.getInputClass(), converter.getOutputClass(), converter, theBinding.getQualifier());
457            } catch (InstantiationException e) {
458                throw new IllegalStateException("Cannot instantiate binding class: " + theBinding.getBindingClass().getName());
459            } catch (IllegalAccessException e) {
460                throw new IllegalStateException("Cannot access binding class: " + theBinding.getBindingClass().getName());
461            }
462                } else if (theBinding.getBindingClass() != null) {
463
464                /*
465                 * If only the binding class is supplied, then inspect it for bindings, gathering all bindings identified
466                 */
467                        registerAnnotatedClasses(theBinding.getBindingClass());
468        } else {
469                
470                /*
471                 * Register the binding using the explicit method details provided 
472                 */
473                @SuppressWarnings("unchecked")
474                ConverterKey<S,T> converterKey = new ConverterKey<S,T>((Class<S>)theBinding.getSourceClass(), (Class<T>)theBinding.getTargetClass(), theBinding.getQualifier());
475                @SuppressWarnings("unchecked")
476                Constructor<S> fromConstructor = (Constructor<S>)theBinding.getFromConstructor();
477                
478            registerForMethods(converterKey, theBinding.getToMethod(), theBinding.getFromMethod(), fromConstructor);
479        }
480    }
481    
482        /**
483         * Inspect each of the supplied classes, processing any of the annotated methods found
484         * @param classesToInspect The classes to inspect for annotations
485         */
486        public void registerAnnotatedClasses(Class<?>... classesToInspect) {
487                
488                for (Class<?> nextClass : classesToInspect) {
489                        
490                        Class<?> loopClass = nextClass;
491                        while ((loopClass != Object.class) && (!inspectedClasses.contains(loopClass))) {
492        
493                                attachForAnnotations(loopClass);
494        
495                                loopClass = loopClass.getSuperclass();
496                        }               
497                }
498        }
499
500    /**********************
501     *                    *
502     * Extended Binders   * 
503     *                    *
504     **********************/    
505        
506    /**
507     * Register a custom, typesafe binder implementation which can be retrieved later
508         * @param iface The interface for the provider to be registered.
509     * @param provider The implementation.
510     * @param <I> The class to be registered
511     * @param <T> Implementation of the binder type, I.
512     */
513    protected <I, T extends I> void registerExtendedBinder(Class<I> iface, T provider) {
514        extendedBinders.put(iface, provider);
515    }
516    
517    /**
518     * Retrieves an extended binder
519     * @param cls The implementation.
520     * @param <I> Interface type for the extended binder
521     * @return The found extended binder
522     */
523    @SuppressWarnings("unchecked")
524        protected <I> I getExtendedBinder(Class<I> cls) {
525        return (I) extendedBinders.get(cls);
526    }
527        
528    /******************
529     *                *
530     * Registration   * 
531     *                *
532     ******************/
533    
534        /**
535         * Register a Binding with the given source and target class.
536         * A binding unifies a marshaller and an unmarshaller and both must be available to resolve a binding.
537         * 
538         * The source class is considered the owning class of the binding. The source can be marshalled
539         * into the target class. Similarly, the target can be unmarshalled to produce an instance of the source type.
540         * @param source The source (owning) class
541         * @param target The target (foreign) class
542         * @param converter The binding to be registered
543         */
544        public final <S, T> void registerBinding(Class<S> source, Class<T> target, Binding<S, T> converter) {
545        Class<? extends Annotation> scope = matchImplementationToScope(converter.getClass());
546        registerBinding(new ConverterKey<S,T>(source, target, scope == null ? DefaultBinding.class : scope), converter);        
547        }
548
549        /**
550         * Register an UnMarshaller with the given source and target class.
551         * The unmarshaller is used as follows: Instances of the source can be marshalled into the target class.
552         * @param source The source (input) class
553         * @param target The target (output) class
554         * @param converter The FromUnmarshaller to be registered  
555         */
556        public final <S, T> void registerUnmarshaller(Class<S> source, Class<T> target, FromUnmarshaller<S, T> converter) {
557        Class<? extends Annotation> scope = matchImplementationToScope(converter.getClass());
558        registerUnmarshaller(new ConverterKey<S,T>(source, target, scope == null ? DefaultBinding.class : scope), converter);   
559        }
560
561        /**
562         * Register a Marshaller with the given source and target class.
563         * The marshaller is used as follows: Instances of the source can be marshalled into the target class.
564         * @param source The source (input) class
565         * @param target The target (output) class
566         * @param converter The ToMarshaller to be registered
567         */
568        public final <S, T> void registerMarshaller(Class<S> source, Class<T> target, ToMarshaller<S, T> converter) {
569        Class<? extends Annotation> scope = matchImplementationToScope(converter.getClass());
570        registerMarshaller(new ConverterKey<S,T>(source, target, scope == null ? DefaultBinding.class : scope), converter);     
571        }
572        
573        /**
574         * Register a Converter with the given input and output classes. Instances of the input class can be converted into 
575         * instances of the output class
576         * @param input The input class
577         * @param output The output class
578         * @param converter The Converter to be registered   
579         */
580        public final <S, T> void registerConverter(Class<S> input, Class<T> output, Converter<S, T> converter) {
581        Class<? extends Annotation> scope = matchImplementationToScope(converter.getClass());
582        registerConverter(new ConverterKey<S,T>(input, output, scope == null ? DefaultBinding.class : scope), converter);
583    }
584
585        /**
586         * Register a Binding with the given source and target class.
587         * A binding unifies a marshaller and an unmarshaller and both must be available to resolve a binding.
588         * 
589         * The source class is considered the owning class of the binding. The source can be marshalled
590         * into the target class. Similarly, the target can be unmarshalled to produce an instance of the source type.
591         * @param source The source (owning) class
592         * @param target The target (foreign) class
593         * @param converter The binding to be registered
594         * @param qualifier The qualifier for which the binding must be registered
595         */
596        public final <S, T> void registerBinding(Class<S> source, Class<T> target, Binding<S, T> converter, Class<? extends Annotation> qualifier) {
597                registerBinding(new ConverterKey<S,T>(source, target, qualifier == null ? DefaultBinding.class : qualifier), converter);
598        }
599
600        /**
601         * Register a Binding with the given source and target class.
602         * A binding unifies a marshaller and an unmarshaller and both must be available to resolve a binding.
603         * 
604         * The source class is considered the owning class of the binding. The source can be marshalled
605         * into the target class. Similarly, the target can be unmarshalled to produce an instance of the source type.
606         * @param key Converter Key to use
607         * @param converter The binding to be registered
608         */
609        public final <S, T> void registerBinding(ConverterKey<S,T> key, Binding<S, T> converter) {
610                registerConverter(key.invert(), new FromUnmarshallerConverter<S,T>(converter));
611                registerConverter(key, new ToMarshallerConverter<S,T>(converter));
612        }
613
614        
615        /**
616         * Register an UnMarshaller with the given source and target class.
617         * The unmarshaller is used as follows: Instances of the source can be marshalled into the target class.
618         * @param source The source (input) class
619         * @param target The target (output) class
620         * @param converter The FromUnmarshaller to be registered
621         * @param qualifier The qualifier for which the unmarshaller must be registered  
622         */
623        public final <S, T> void registerUnmarshaller(Class<S> source, Class<T> target, FromUnmarshaller<S, T> converter, Class<? extends Annotation> qualifier) {
624                registerUnmarshaller(new ConverterKey<S,T>(source, target, qualifier == null ? DefaultBinding.class : qualifier), converter);
625        }
626
627        /**
628         * Register an UnMarshaller with the given source and target class.
629         * The unmarshaller is used as follows: Instances of the source can be marshalled into the target class.
630         * @param key Converter Key to use
631         * @param converter The FromUnmarshaller to be registered
632         */
633        public final <S, T> void registerUnmarshaller(ConverterKey<S,T> key, FromUnmarshaller<S, T> converter) {
634                registerConverter(key.invert(), new FromUnmarshallerConverter<S,T>(converter));
635        }
636        
637        /**
638         * Register a Marshaller with the given source and target class.
639         * The marshaller is used as follows: Instances of the source can be marshalled into the target class.
640         * @param source The source (input) class
641         * @param target The target (output) class
642         * @param converter The ToMarshaller to be registered
643         * @param qualifier The qualifier for which the marshaller must be registered 
644         */
645        public final <S, T> void registerMarshaller(Class<S> source, Class<T> target, ToMarshaller<S, T> converter, Class<? extends Annotation> qualifier) {
646                registerMarshaller(new ConverterKey<S,T>(source, target, qualifier == null ? DefaultBinding.class : qualifier), converter);
647        }
648
649        /**
650         * Register a Marshaller with the given source and target class.
651         * The marshaller is used as follows: Instances of the source can be marshalled into the target class.
652         * @param key Converter Key to use
653         * @param converter The ToMarshaller to be registered
654         */
655        public final <S, T> void registerMarshaller(ConverterKey<S,T> key, ToMarshaller<S, T> converter) {
656                registerConverter(key, new ToMarshallerConverter<S,T>(converter));
657        }
658        
659        /**
660         * Register a Converter with the given input and output classes. Instances of the input class can be converted into 
661         * instances of the output class
662         * @param input The input class
663         * @param output The output class
664         * @param converter The Converter to be registered
665         * @param qualifier The qualifier for which the converter must be registered   
666         */
667        public final <S, T> void registerConverter(Class<S> input, Class<T> output, Converter<S, T> converter, Class<? extends Annotation> qualifier) {
668                registerConverter(new ConverterKey<S,T>(input, output, qualifier == null ? DefaultBinding.class : qualifier), converter);
669        }
670                
671        /**
672         * Register a Converter with the given input and output classes. Instances of the input class can be converted into 
673         * instances of the output class
674         * @param key Converter Key to use
675         * @param converter The Converter to be registered
676         */
677        public final <S, T> void registerConverter(ConverterKey<S,T> key, Converter<S, T> converter) {  
678
679        if (key.getInputClass() == null) {
680            throw new IllegalArgumentException("Input Class must not be null");
681        }
682        if (key.getOutputClass() == null) {
683            throw new IllegalArgumentException("Output Class must not be null");
684        }
685        if (converter == null) {
686            throw new IllegalArgumentException("Converter must not be null");
687        }
688
689        if (key.getQualifierAnnotation() == null) {
690            throw new IllegalArgumentException("Qualifier must not be null");
691        }
692
693        Converter<?,?> old = registeredConverters.putIfAbsent(key, converter);
694        if (old != null && (!isSameConverter(old, converter))) {
695                throw new IllegalStateException("Converter already registered for key: " + key);
696        }
697    }
698        
699        @SuppressWarnings("unlikely-arg-type")
700        private boolean isSameConverter(Converter<?,?> old, Converter<?,?> converter) {
701                
702                if (old.getClass().equals(converter.getClass())) {
703                        return true;
704                }
705
706                // Special cases which arises when processing the identity function
707                if (old instanceof FromUnmarshallerConverter && converter instanceof ToMarshallerConverter
708                                && (((FromUnmarshallerConverter<?, ?>)old).getUnmarshaller().equals(((ToMarshallerConverter<?, ?>)converter).getMarshaller()))) {
709                        return true;
710                }
711                if (old instanceof ToMarshallerConverter && converter instanceof FromUnmarshallerConverter
712                                && (((ToMarshallerConverter<?, ?>)old).getMarshaller().equals(((FromUnmarshallerConverter<?, ?>)converter).getUnmarshaller()))) {
713                        return true;
714                }
715                return false;
716        }
717        
718    /******************
719     *                *
720     * Conversion API * 
721     *                *
722     ******************/
723        
724        /**
725         * Convert an object to the given target class
726         * This method infers the source type for the conversion from the runtime type of object.
727         * @param output The target class to convert the object to
728         * @param object The object to be converted
729         */
730        public <S, T> T convertTo(Class<T> output, Object object) {
731                return convertTo(output, object, DefaultBinding.class);
732        }
733        
734        /**
735         * Convert an object to the given target class
736         * This method infers the source type for the conversion from the runtime type of object.
737         * @param output The target class to convert the object to
738         * @param object The object to be converted
739         * @param qualifier The qualifier for which the binding must be registered
740         */
741        public <S, T> T convertTo(Class<T> output, Object object, Class<? extends Annotation> qualifier) {
742
743                if (object == null) {
744                        return null;
745                }
746                
747                @SuppressWarnings("unchecked")
748                Converter<S, T> conv = (Converter<S, T>) determineConverter(object.getClass(), output, qualifier == null ? DefaultBinding.class : qualifier);
749                
750                if (conv == null) {
751                        @SuppressWarnings("unchecked")
752                        Class<S> inputClass = (Class<S>)object.getClass();
753                        throw new NoConverterFoundException(new ConverterKey<S,T>(inputClass, output, qualifier == null ? DefaultBinding.class : qualifier));
754                }
755                
756                @SuppressWarnings("unchecked")
757                S myObject = (S)object;
758                return conv.convert(myObject);
759        }
760                
761        private <S, T> Converter<S, T> determineConverter(Class<S> candidateClass, Class<T> output, Class<? extends Annotation> qualifier) {
762                
763                if (!candidateClass.equals(Object.class)) {
764                        Converter<S, T> match = findConverter(candidateClass, output, qualifier);
765                        if (match != null) {
766                                return match;
767                        }
768
769                        @SuppressWarnings("unchecked")  
770                        Class<S>[] interfaces = (Class<S>[])candidateClass.getInterfaces();
771                        for (Class<S> candidateInterface : interfaces) {
772                                match = determineConverter(candidateInterface, output, qualifier);
773                                if (match != null) {
774                                        return match;
775                                }       
776                        }
777                        
778                        Class<? super S> superClass = (Class<? super S>)candidateClass.getSuperclass();
779                        
780                        @SuppressWarnings("unchecked")
781                        Converter<S,T> superMatch = (Converter<S, T>) determineConverter(superClass, output, qualifier);
782                        return superMatch;
783                } else {
784                        return null;
785                }
786        }
787        
788        /**
789         * Convert an object which is an instance of source class to the given target class
790         * @param input The class of the object to be converted
791         * @param output The target class to convert the object to
792         * @param object The object to be converted
793         */
794        public <S, T> T convertTo(Class<S> input, Class<T> output, Object object) {
795                return convertTo(new ConverterKey<S,T>(input, output, DefaultBinding.class), object);
796        }
797
798        /**
799         * Convert an object which is an instance of source class to the given target class
800         * @param input The class of the object to be converted
801         * @param output The target class to convert the object to
802         * @param object The object to be converted
803         * @param qualifier Match the converter with the given qualifier
804         */
805        public <S, T> T convertTo(Class<S> input, Class<T> output, Object object, Class<? extends Annotation> qualifier) {
806
807                return convertTo(new ConverterKey<S,T>(input, output, qualifier), object);
808        }
809
810        /**
811         * Convert an object which is an instance of source class to the given target class
812         * @param key The converter key to use
813         * @param object The object to be converted
814         */
815        public <S, T> T convertTo(ConverterKey<S,T> key, Object object) {
816
817                if (object == null) {
818                        return null;
819                }
820                
821                Converter<S, T> conv = findConverter(key.getInputClass(), key.getOutputClass(), key.getQualifierAnnotation() == null ? DefaultBinding.class : key.getQualifierAnnotation());
822                
823                if (conv == null) {
824                        throw new NoConverterFoundException(key);
825                }
826                
827                @SuppressWarnings("unchecked")
828                S myObject = (S)object;
829                return conv.convert(myObject);
830        }
831        
832    /*************************
833     *                       *
834     * Conversion Resolution * 
835     *                       *
836     *************************/
837        
838        /**
839         * Resolve a Binding with the given source and target class.
840         * A binding unifies a marshaller and an unmarshaller and both must be available to resolve a binding.
841         * 
842         * The source class is considered the owning class of the binding. The source can be marshalled
843         * into the target class. Similarly, the target can be unmarshalled to produce an instance of the source type.
844         * @param source The source (owning) class
845         * @param target The target (foreign) class
846         */
847        public <S, T> Binding<S, T> findBinding(Class<S> source, Class<T> target) {
848                return findBinding(new ConverterKey<S,T>(source, target, DefaultBinding.class));
849        }
850
851        /**
852         * Resolve a Marshaller with the given source and target class.
853         * The marshaller is used as follows: Instances of the source can be marshalled into the target class.
854         * @param source The source (input) class
855         * @param target The target (output) class 
856         */
857        public <S, T> ToMarshaller<S, T> findMarshaller(Class<S> source, Class<T> target) {
858                return findMarshaller(new ConverterKey<S,T>(source, target, DefaultBinding.class));
859        }
860
861        /**
862         * Resolve a Converter with the given input and output classes. Instances of the input class can be converted into 
863         * instances of the output class
864         * @param input The input class
865         * @param output The output class  
866         */
867        public <S, T> Converter<S, T> findConverter(Class<S> input, Class<T> output) {
868                return findConverter(new ConverterKey<S,T>(input, output, DefaultBinding.class));
869        }
870
871        /**
872         * Resolve an UnMarshaller with the given source and target class.
873         * The unmarshaller is used as follows: Instances of the source can be marshalled into the target class.
874         * @param source The source (input) class
875         * @param target The target (output) class 
876         */
877        public <S, T> FromUnmarshaller<S, T> findUnmarshaller(Class<S> source, Class<T> target) {
878                return findUnmarshaller(new ConverterKey<S,T>(source, target, DefaultBinding.class));
879        }
880
881        /**
882         * Resolve a Binding with the given source and target class.
883         * A binding unifies a marshaller and an unmarshaller and both must be available to resolve a binding.
884         * 
885         * The source class is considered the owning class of the binding. The source can be marshalled
886         * into the target class. Similarly, the target can be unmarshalled to produce an instance of the source type.
887         * @param source The source (owning) class
888         * @param target The target (foreign) class
889         * @param qualifier The qualifier for which the binding must be registered
890         */
891        public <S, T> Binding<S, T> findBinding(Class<S> source, Class<T> target, Class<? extends Annotation> qualifier) {
892                return findBinding(new ConverterKey<S,T>(source, target, qualifier == null ? DefaultBinding.class : qualifier));
893        }
894        
895        /**
896         * Resolve a Binding with the given source and target class.
897         * A binding unifies a marshaller and an unmarshaller and both must be available to resolve a binding.
898         * 
899         * The source class is considered the owning class of the binding. The source can be marshalled
900         * into the target class. Similarly, the target can be unmarshalled to produce an instance of the source type.
901         * @param key The key to look up
902         */
903        @SuppressWarnings("unlikely-arg-type")
904        public <S, T> Binding<S, T> findBinding(ConverterKey<S,T> key) {
905
906                FromUnmarshaller<?,?> fromUnmarshaller = null;
907                ToMarshaller<?,?> toMarshaller = null;
908                
909                Converter<S, T> toTarget = findConverter(key);
910                if (toTarget instanceof FromUnmarshallerConverter<?, ?>) {
911                        fromUnmarshaller = ((FromUnmarshallerConverter<?, ?>) toTarget).getUnmarshaller();
912                } else if (toTarget instanceof ToMarshallerConverter<?, ?>) {
913                        toMarshaller = ((ToMarshallerConverter<?, ?>) toTarget).getMarshaller();
914                }
915                Converter<T, S> toSource = findConverter(key.invert());
916                if (toSource instanceof FromUnmarshallerConverter<?, ?>) {
917                        fromUnmarshaller = ((FromUnmarshallerConverter<?, ?>) toSource).getUnmarshaller();
918                } else if (toSource instanceof ToMarshallerConverter<?, ?>) {
919                        toMarshaller = ((ToMarshallerConverter<?, ?>) toSource).getMarshaller();
920                }
921                
922                if (fromUnmarshaller != null && toMarshaller != null) {
923                        
924                        if (fromUnmarshaller.equals(toMarshaller) && Binding.class.isAssignableFrom(fromUnmarshaller.getClass())) {
925                                Binding<?,?> theBinding = (Binding<?,?>)fromUnmarshaller;
926                                if (theBinding.getBoundClass().equals(key.getInputClass())) {
927                                        @SuppressWarnings("unchecked")
928                                        final Binding<S, T>myBinding = (Binding<S, T>)theBinding;
929                                        return myBinding;
930                                }
931                        }
932                        
933                        if (fromUnmarshaller.getBoundClass().equals(key.getInputClass())) {
934                                @SuppressWarnings("unchecked")
935                                final Binding<S, T>myBinding = new CompositeBinding<S,T>((ToMarshaller<S,T>)toMarshaller, (FromUnmarshaller<S,T>)fromUnmarshaller);
936                                return myBinding;
937                        } else {
938                                @SuppressWarnings("unchecked")
939                                final Binding<S, T> myBinding = new InverseCompositeBinding<S,T>((ToMarshaller<T,S>)toMarshaller, (FromUnmarshaller<T,S>)fromUnmarshaller);
940                                return myBinding;
941                        }
942                }
943                return null;
944        }
945
946        /**
947         * Resolve a Marshaller with the given source and target class.
948         * The marshaller is used as follows: Instances of the source can be marshalled into the target class.
949         * @param source The source (input) class
950         * @param target The target (output) class
951         * @param qualifier The qualifier for which the marshaller must be registered 
952         */
953        public <S, T> ToMarshaller<S, T> findMarshaller(Class<S> source, Class<T> target, Class<? extends Annotation> qualifier) {
954                return findMarshaller(new ConverterKey<S,T>(source, target, qualifier == null ? DefaultBinding.class : qualifier));
955        }
956        
957        /**
958         * Resolve a Marshaller with the given source and target class.
959         * The marshaller is used as follows: Instances of the source can be marshalled into the target class.
960         * @param key The key to look up
961         */
962        public <S, T> ToMarshaller<S, T> findMarshaller(ConverterKey<S,T> key) {
963
964                Converter<S,T> converter = findConverter(key);
965                
966                if (converter == null) {
967                        return null;
968                }
969                
970                if (ToMarshallerConverter.class.isAssignableFrom(converter.getClass())) {
971                        return ((ToMarshallerConverter<S, T>)converter).getMarshaller();
972                } else {
973                        return new ConverterToMarshaller<S, T>(converter);
974                }
975        }
976
977        /**
978         * Resolve a Converter with the given input and output classes. Instances of the input class can be converted into 
979         * instances of the output class
980         * @param source The source class
981         * @param target The target class
982         * @param qualifier The qualifier for which the marshaller must be registered   
983         */
984        public <S, T> Converter<S, T> findConverter(Class<S> source, Class<T> target, Class<? extends Annotation> qualifier) {
985                return findConverter(new ConverterKey<S,T>(source, target, qualifier == null ? DefaultBinding.class : qualifier));
986        }
987        
988        /**
989         * Resolve a Converter with the given input and output classes. Instances of the input class can be converted into 
990         * instances of the output class
991         * @param key The key to look up
992         */
993        public <S, T> Converter<S, T> findConverter(ConverterKey<S,T> key) {
994                
995                 // We check once before attempting introspection so we avoid that if possible
996                @SuppressWarnings("unchecked")
997                Converter<S,T> converter = (Converter<S, T>) registeredConverters.get(key);
998                if (converter != null) {
999                        return converter;
1000                }
1001                
1002                // Now try introspecting the relevant class
1003                registerAnnotatedClasses(key.getInputClass(), key.getOutputClass());
1004
1005                @SuppressWarnings("unchecked")
1006                Converter<S,T> myConverter = (Converter<S, T>) registeredConverters.get(key);
1007                return myConverter;
1008        }
1009
1010        /**
1011         * Resolve an UnMarshaller with the given source and target class.
1012         * The unmarshaller is used as follows: Instances of the source can be marshalled into the target class.
1013         * @param source The source (input) class
1014         * @param target The target (output) class 
1015         * @param qualifier The qualifier for which the unmarshaller must be registered 
1016         */
1017        public <S, T> FromUnmarshaller<S, T> findUnmarshaller(Class<S> source, Class<T> target, Class<? extends Annotation> qualifier) {
1018                return findUnmarshaller(new ConverterKey<S,T>(source, target, qualifier == null ? DefaultBinding.class : qualifier));
1019        }
1020        
1021        /**
1022         * Resolve an UnMarshaller with the given source and target class.
1023         * The unmarshaller is used as follows: Instances of the source can be marshalled into the target class.
1024         * @param key The key to look up 
1025         */
1026        public <S, T> FromUnmarshaller<S, T> findUnmarshaller(ConverterKey<S,T> key) {
1027
1028                Converter<T,S> converter = findConverter(key.invert());
1029                
1030                if (converter == null) {
1031                        return null;
1032                }
1033                
1034                if (FromUnmarshallerConverter.class.isAssignableFrom(converter.getClass())) {
1035                        return ((FromUnmarshallerConverter<S, T>)converter).getUnmarshaller();
1036                } else {
1037                        return new ConverterFromUnmarshaller<S, T>(converter);
1038                }
1039        }
1040        
1041        /**
1042         * Return an iterable collection of ConverterKeys, one for each currently registered conversion
1043         */
1044        public Iterable<ConverterKey<?,?>> getConverterEntries() {
1045                return registeredConverters.keySet();
1046        }
1047
1048    /******************
1049     *                *
1050     * Helper Methods * 
1051     *                *
1052     ******************/
1053
1054        /**
1055         * This method assists in matching a given implementation class to its (programmer) defined scope.
1056         * The method searches for an annotation on the class defined as a binding scope. If one is found 
1057         * the implementation is matched to the scope. Note that the implementation scope can be overridden 
1058         * using bindings.xml configuration
1059         * @param implementation The class to examine
1060         * @return The found scope annotation
1061         */
1062    private <T> Class<? extends Annotation> matchImplementationToScope(Class<?> implementation) {
1063
1064        for (Annotation next : implementation.getAnnotations()) {
1065            Class<? extends Annotation> nextType = next.annotationType();
1066            if (nextType.getAnnotation(BindingScope.class) != null) {
1067                return nextType;
1068            }
1069        }
1070        return null;
1071    }
1072        
1073        private <S, T> void attachForAnnotations(final Class<?> target) {
1074
1075                // Only apply an annotation once
1076                synchronized(inspectedClasses) {
1077                        if (inspectedClasses.contains(target)) {
1078                                return;
1079                        }
1080                        inspectedClasses.add(target);
1081                }
1082
1083                // NB Don't worry about superclasses - that happens elsewhere
1084                Set<ConverterKey<?,?>> previouslySeenKeys = new HashSet<ConverterKey<?,?>>();
1085                
1086                Map<ConverterKey<?,?>, Method> toMethods = new HashMap<ConverterKey<?,?>, Method>();
1087                Map<ConverterKey<?,?>, Method> fromMethods = new HashMap<ConverterKey<?,?>, Method>();
1088                Map<ConverterKey<?,?>, Constructor<?>> fromConstructors = new HashMap<ConverterKey<?,?>, Constructor<?>>();
1089                
1090                matchTo(target, previouslySeenKeys, toMethods);
1091                
1092                matchFrom(target, previouslySeenKeys, fromMethods, fromConstructors);
1093                
1094                // 2 Pass all the results into registerForMethods
1095                for (ConverterKey<?,?> next : previouslySeenKeys) {
1096                        
1097                        @SuppressWarnings("unchecked")
1098                        ConverterKey<S,T> nextKey = (ConverterKey<S,T>)next;
1099                        
1100                        ConverterKey<?,?> inverse = next.invert();
1101                        @SuppressWarnings("unchecked") Constructor<S> fromConstructor = (Constructor<S>) fromConstructors.get(inverse);
1102                        
1103                        registerForMethods(nextKey, toMethods.get(next), fromMethods.get(inverse), fromConstructor);
1104                }
1105        }
1106
1107        private void matchTo(Class<?> target, Set<ConverterKey<?,?>> previouslySeenKeys, Map<ConverterKey<?,?>, Method> toMethods) {
1108
1109                for (ConverterProvider nextConverter : converterProviders) {
1110                        Map<ConverterKey<?,?>, Method> nextMethods = nextConverter.matchToMethods(target);
1111                        for(ConverterKey<?,?> currentKey : nextMethods.keySet()) {
1112                                if (previouslySeenKeys.contains(currentKey)) {
1113                                        throw new IllegalStateException("Method is resolved by two converters: " + currentKey.toString());
1114                                }
1115                                previouslySeenKeys.add(currentKey);
1116                        }
1117                        toMethods.putAll(nextMethods);
1118                }
1119        }
1120        
1121        private <T> void matchFrom(Class<T> target, Set<ConverterKey<?,?>> previouslySeenKeys, Map<ConverterKey<?,?>, Method> fromMethods, Map<ConverterKey<?,?>, Constructor<?>> fromConstructors) {
1122
1123                for (ConverterProvider nextConverter : converterProviders) {
1124                        Map<ConverterKey<?,?>, Method> nextMethods = nextConverter.matchFromMethods(target);
1125                        for (ConverterKey<?,?> currentKey : nextMethods.keySet()) {
1126                                if (previouslySeenKeys.contains(currentKey)) {
1127                                        throw new IllegalStateException("Method is resolved by two converters: " + currentKey.toString());
1128                                }
1129                                previouslySeenKeys.add(currentKey);
1130                        }
1131                        fromMethods.putAll(nextMethods);
1132                        
1133                        Map<ConverterKey<?,?>, Constructor<T>> nextConstructors = nextConverter.matchFromConstructors(target);
1134                        for (ConverterKey<?,?> currentKey : nextConstructors.keySet()) {
1135                                if (previouslySeenKeys.contains(currentKey)) {
1136                                        throw new IllegalStateException("ConverterKey is resolved by two converters: " + currentKey.toString());
1137                                }
1138                                previouslySeenKeys.add(currentKey);
1139                        }
1140                        fromConstructors.putAll(nextConstructors);
1141                }
1142        }
1143    
1144    private <I,O> void registerForMethods(ConverterKey<I,O> key, Method toMethod, Method fromMethod, Constructor<I> con) {
1145    
1146        if (toMethod != null) {
1147            
1148            MethodToMarshaller<I,O> toMarshaller = new MethodToMarshaller<I,O>(key.getInputClass(), key.getOutputClass(), toMethod);
1149            if (con != null) {
1150    
1151                ConstructorFromUnmarshaller<I,O> fromUnmarshaller = new ConstructorFromUnmarshaller<I,O>(con); 
1152                registerBinding(key.getInputClass(), key.getOutputClass(), new CompositeBinding<I,O>(toMarshaller, fromUnmarshaller), key.getQualifierAnnotation());               
1153            } else if (fromMethod != null) {
1154                
1155                MethodFromUnmarshaller<I,O> fromUnmarshaller = new MethodFromUnmarshaller<I,O>(key.getInputClass(), fromMethod);
1156                registerBinding(key.getInputClass(), key.getOutputClass(), new CompositeBinding<I,O>(toMarshaller, fromUnmarshaller), key.getQualifierAnnotation());
1157            } else {
1158                
1159                registerMarshaller(key.getInputClass(), key.getOutputClass(), toMarshaller, key.getQualifierAnnotation());
1160            }
1161        } else {
1162            if (con != null) {
1163                
1164                registerUnmarshaller(key.getInputClass(), key.getOutputClass(), new ConstructorFromUnmarshaller<I,O>(con), key.getQualifierAnnotation());
1165            } else if (fromMethod != null) {
1166                
1167                registerUnmarshaller(key.getInputClass(), key.getOutputClass(), new MethodFromUnmarshaller<I,O>(key.getInputClass(), fromMethod), key.getQualifierAnnotation());
1168            }
1169        }
1170    }
1171
1172    /******************
1173     *                *
1174     * String Binder  * 
1175     *                *
1176     ******************/
1177    
1178        public <T> T convertFromString(Class<T> output, String object) {
1179                return convertTo(String.class, output, object);
1180        }
1181
1182        public <T> T convertFromString(Class<T> output, String object,
1183                        Class<? extends Annotation> qualifier) {
1184                return convertTo(String.class, output, object, qualifier);
1185        }
1186
1187        public String convertToString(Object object) {
1188                return convertTo(String.class, object);
1189        }
1190
1191        public String convertToString(Object object,
1192                        Class<? extends Annotation> qualifier) {
1193                return convertTo(String.class, object, qualifier);
1194        }
1195
1196        public <S> String convertToString(Class<S> input, Object object) {
1197                return convertTo(input, String.class, object);
1198        }
1199
1200        public <S> String convertToString(Class<S> input, Object object,
1201                        Class<? extends Annotation> qualifier) {
1202                return convertTo(input, String.class, object, qualifier);
1203        }
1204}