View Javadoc

1   /*
2    * Copyright 2006-2007 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package net.sf.ezmorph;
18  
19  import java.io.Serializable;
20  import java.lang.reflect.Method;
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  
27  import net.sf.ezmorph.object.IdentityObjectMorpher;
28  
29  /**
30   * Convenient class that manages Morphers.<br>
31   * A MorpherRehistry manages a group of Morphers. A Morpher will always be
32   * associated with a target class, it is possible to have several Morphers
33   * registered for a target class, if this is the case, the first Morpher will be
34   * used when performing a conversion and no specific Morpher is selected in
35   * advance.<br>
36   * {@link MorphUtils} may be used to register standard Morphers for primitive
37   * types and primitive wrappers, as well as arrays of those types.
38   *
39   * @author Andres Almiray <aalmiray@users.sourceforge.net>
40   */
41  public class MorpherRegistry implements Serializable
42  {
43     private static final long serialVersionUID = -3894767123320768419L;
44     private Map morphers = new HashMap();
45  
46     public MorpherRegistry()
47     {
48  
49     }
50  
51     /**
52      * Deregisters all morphers.
53      */
54     public synchronized void clear()
55     {
56        morphers.clear();
57     }
58  
59     /**
60      * Deregister all Morphers of a type.<br>
61      *
62      * @param class the target type the Morphers morph to
63      */
64     public synchronized void clear( Class type )
65     {
66        List registered = (List) morphers.get( type );
67        if( registered != null ){
68           morphers.remove( type );
69        }
70     }
71  
72     /**
73      * Deregister the specified Morpher.<br>
74      * The registry will remove the target <code>Class</code> from the morphers
75      * Map if it has no other registered morphers.
76      *
77      * @param morpher the target Morpher to remove
78      */
79     public synchronized void deregisterMorpher( Morpher morpher )
80     {
81        List registered = (List) morphers.get( morpher.morphsTo() );
82        if( registered != null && !registered.isEmpty() ){
83           registered.remove( morpher );
84           if( registered.isEmpty() ){
85              morphers.remove( morpher.morphsTo() );
86           }
87        }
88     }
89  
90     /**
91      * Returns a morpher for <code>clazz</code>.<br>
92      * If several morphers are found for that class, it returns the first. If no
93      * Morpher is found it will return the IdentityObjectMorpher.
94      *
95      * @param clazz the target class for which a Morpher may be associated
96      */
97     public synchronized Morpher getMorpherFor( Class clazz )
98     {
99        List registered = (List) morphers.get( clazz );
100       if( registered == null || registered.isEmpty() ){
101          // no morpher registered for clazz
102          return IdentityObjectMorpher.getInstance();
103       }else{
104          return (Morpher) registered.get( 0 );
105       }
106    }
107 
108    /**
109     * Returns all morphers for <code>clazz</code>.<br>
110     * If no Morphers are found it will return an array containing the
111     * IdentityObjectMorpher.
112     *
113     * @param clazz the target class for which a Morpher or Morphers may be
114     *        associated
115     */
116    public synchronized Morpher[] getMorphersFor( Class clazz )
117    {
118       List registered = (List) morphers.get( clazz );
119       if( registered == null || registered.isEmpty() ){
120          // no morphers registered for clazz
121          return new Morpher[] { IdentityObjectMorpher.getInstance() };
122       }else{
123          Morpher[] morphs = new Morpher[registered.size()];
124          int k = 0;
125          for( Iterator i = registered.iterator(); i.hasNext(); ){
126             morphs[k++] = (Morpher) i.next();
127          }
128          return morphs;
129       }
130    }
131 
132    /**
133     * Morphs and object to the specified target class.<br>
134     * This method uses reflection to invoke primitive Morphers and Morphers that
135     * do not implement ObjectMorpher.
136     *
137     * @param target the target class to morph to
138     * @param value the value to morph
139     * @return an instance of the target class if a suitable Morpher was found
140     * @throws MorphException if an error occurs during the conversion
141     */
142    public Object morph( Class target, Object value )
143    {
144       if( value == null ){
145          // give the first morpher in the list a shot to convert
146          // the value as we can't access type information on it
147          Morpher morpher = getMorpherFor( target );
148          if( morpher instanceof ObjectMorpher ){
149             return ((ObjectMorpher) morpher).morph( value );
150          }else{
151             try{
152                Method morphMethod = morpher.getClass()
153                      .getDeclaredMethod( "morph", new Class[] { Object.class } );
154                return morphMethod.invoke( morpher, new Object[] { value } );
155             }
156             catch( Exception e ){
157                throw new MorphException( e );
158             }
159          }
160       }
161 
162       Morpher[] morphers = getMorphersFor( target );
163       for( int i = 0; i < morphers.length; i++ ){
164          Morpher morpher = morphers[i];
165          if( morpher.supports( value.getClass() ) ){
166             if( morpher instanceof ObjectMorpher ){
167                return ((ObjectMorpher) morpher).morph( value );
168             }else{
169                try{
170                   Method morphMethod = morpher.getClass()
171                         .getDeclaredMethod( "morph", new Class[] { Object.class } );
172                   return morphMethod.invoke( morpher, new Object[] { value } );
173                }
174                catch( Exception e ){
175                   throw new MorphException( e );
176                }
177             }
178          }
179       }
180       return value;
181    }
182 
183    /**
184     * Register a Morpher for a target <code>Class</code>.<br>
185     * The target class is the class this Morpher morphs to. If there are another
186     * morphers registered to that class, it will be appended to a List.
187     *
188     * @param morpher a Morpher to register. The method <code>morphsTo()</code>
189     *        is used to associate the Morpher to a target Class
190     */
191    public void registerMorpher( Morpher morpher )
192    {
193       registerMorpher( morpher, false );
194    }
195 
196    /**
197     * Register a Morpher for a target <code>Class</code>.<br>
198     * The target class is the class this Morpher morphs to. If there are another
199     * morphers registered to that class, it will be appended to a List.
200     *
201     * @param morpher a Morpher to register. The method <code>morphsTo()</code>
202     *        is used to associate the Morpher to a target Class
203     * @param override if registering teh Morpher should override all previously
204     *        registered morphers for the target type
205     */
206    public synchronized void registerMorpher( Morpher morpher, boolean override )
207    {
208       List registered = (List) morphers.get( morpher.morphsTo() );
209       if( override || registered == null ){
210          registered = new ArrayList();
211          morphers.put( morpher.morphsTo(), registered );
212       }
213       if( !registered.contains( morpher ) ){
214          registered.add( morpher );
215       }
216    }
217 }