View Javadoc

1   /*
2    * Copyright 2004 Ronald Blaschke.
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  package org.rblasch.convert.converters.lang;
17  
18  import org.rblasch.convert.converters.AbstractConverterFactory;
19  import org.rblasch.convert.converters.OnceConverterFactory;
20  import org.rblasch.convert.converters.primitives.ByteToShortConverter;
21  import org.rblasch.convert.converters.primitives.FloatToDoubleConverter;
22  import org.rblasch.convert.converters.primitives.IntegerToLongConverter;
23  import org.rblasch.convert.converters.primitives.ShortToIntegerConverter;
24  import org.rblasch.convert.type.ClassType;
25  import org.rblasch.convert.type.ParameterizableType;
26  import org.rblasch.convert.type.Type;
27  import org.rblasch.convert.type.Types;
28  
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.HashSet;
32  import java.util.Iterator;
33  import java.util.LinkedList;
34  import java.util.List;
35  import java.util.Set;
36  
37  /***
38   * @author Ronald Blaschke
39   */
40  public class JlConverterFactory extends AbstractConverterFactory implements OnceConverterFactory {
41      public Set/*<MetaConverter>*/ createOnce() {
42          final Set/*<MetaConverter>*/ converters = new HashSet();
43  
44          // autoboxing
45          converters.add(new CastConverter(Types.findTypeByName("byte"),
46                  Types.findTypeByClass(Byte.class)));
47          converters.add(new CastConverter(Types.findTypeByClass(Byte.class),
48                  Types.findTypeByName("byte")));
49          converters.add(new CastConverter(Types.findTypeByName("short"),
50                  Types.findTypeByClass(Short.class)));
51          converters.add(new CastConverter(Types.findTypeByClass(Short.class),
52                  Types.findTypeByName("short")));
53          converters.add(new CastConverter(Types.findTypeByName("int"),
54                  Types.findTypeByClass(Integer.class)));
55          converters.add(new CastConverter(Types.findTypeByClass(Integer.class),
56                  Types.findTypeByName("int")));
57          converters.add(new CastConverter(Types.findTypeByName("long"),
58                  Types.findTypeByClass(Long.class)));
59          converters.add(new CastConverter(Types.findTypeByClass(Long.class),
60                  Types.findTypeByName("long")));
61  
62          // "default" number widening
63          converters.add(new ByteToShortConverter());
64          converters.add(new ShortToIntegerConverter());
65          converters.add(new IntegerToLongConverter());
66  
67          converters.add(new FloatToDoubleConverter());
68  
69          // "default" .toString() conversion
70          converters.add(new ObjectToStringConverter());
71  
72          return converters;
73      }
74  
75      // cache already resolved types
76      private final Set/*<Type>*/ resolvedTypes = new HashSet();
77  
78      public Set/*<MetaConverter>*/ create(final Type sourceType, final Type destinationType) {
79          final Set/*<MetaConverter>*/ converters = new HashSet();
80          if (!resolvedTypes.contains(sourceType)) {
81              converters.addAll(jlConverters(sourceType));
82              resolvedTypes.add(sourceType);
83          }
84  
85          if (!resolvedTypes.contains(destinationType)) {
86              converters.addAll(jlConverters(destinationType));
87              resolvedTypes.add(destinationType);
88          }
89  
90          return converters;
91      }
92  
93      private Set/*<MetaConverter>*/ jlConverters(final Type t) {
94          final Set/*<MetaConverter>*/ converters = new HashSet();
95  
96          converters.add(new IdentityConverter(t));
97  
98          // class lookup
99          if (t instanceof ClassType) {
100             converters.addAll(castConverters(t));
101         } else if (t instanceof ParameterizableType) {
102             converters.addAll(castConverters(t));
103 
104             // recurse into all parameters
105             final ParameterizableType pt = (ParameterizableType) t;
106             for (final Iterator i = pt.getParameters().iterator(); i.hasNext();) {
107                 converters.addAll(jlConverters((Type) i.next()));
108             }
109         }
110 
111         return converters;
112     }
113 
114     private Set/*<MetaConverter>*/ castConverters(final Type t) {
115         final Set/*<MetaConverter>*/ converters = new HashSet();
116 
117         final LinkedList/*<Type>*/ pending = new LinkedList();
118         pending.add(t);
119 
120         while (!pending.isEmpty()) {
121             final Type current = (Type) pending.removeFirst();
122 
123             final Set/*<Type>*/ superTypes = getSuperTypes(current);
124             pending.addAll(superTypes);
125             for (final Iterator i = superTypes.iterator(); i.hasNext();) {
126                 converters.add(new CastConverter(current, (Type) i.next()));
127             }
128             resolvedTypes.add(current);
129         }
130 
131         return converters;
132     }
133 
134     static Set/*<Type>*/ getSuperTypes(final Type t) {
135         final Set/*<Type>*/ superTypes = new HashSet();
136         if (t instanceof ClassType) {
137             final ClassType ct = (ClassType) t;
138             final Class c = ct.getTheClass();
139             if (c.getSuperclass() != null) {
140                 superTypes.add(Types.findTypeByClass(c.getSuperclass()));
141                 for (final Iterator i = Arrays.asList(c.getInterfaces()).iterator(); i.hasNext();) {
142                     final Class iface = (Class) i.next();
143                     superTypes.add(Types.findTypeByClass(iface));
144                 }
145             }
146             if (c.isInterface()) {
147                 superTypes.add(Types.findTypeByClass(Object.class));
148             }
149         } else if (t instanceof ParameterizableType) {
150             final ParameterizableType pt = (ParameterizableType) t;
151 
152             final List/*<Type>*/ ptl = toList(pt);
153 
154             for (int i = ptl.size()-1; i>=0; --i) {
155                 final List/*<Type>*/ ptli = new ArrayList(ptl);
156                 for (final Iterator j = getSuperTypes((Type) ptl.get(i)).iterator(); j.hasNext();) {
157                     ptli.set(i, j.next());
158                     final ParameterizableType pti = fromList(ptli);
159                     superTypes.add(pti);
160                 }
161             }
162         }
163 
164         return superTypes;
165     }
166 
167     private static List/*<Type>*/ toList(final ParameterizableType t) {
168         final List/*<Type>*/ l = new ArrayList();
169 
170         l.add(t.getType());
171         l.addAll(t.getParameters());
172 
173         return l;
174     }
175 
176     private static ParameterizableType fromList(final List/*<Type>*/ l) {
177         return Types.findPTypeByType((Type) l.get(0), l.subList(1, l.size()));
178     }
179 }