View Javadoc

1   package net.sourceforge.jparam.conversion.converters;
2   
3   import net.sourceforge.jparam.JParamException;
4   import net.sourceforge.jparam.conversion.weights.ScalarConversionWeight;
5   import net.sourceforge.jparam.typename.TypeNameRegistry;
6   
7   /***
8    * @author Ron_Sidi
9    *
10   * The base class for all converters, it implements all the basic funcionality
11   * of a converter.
12   * 
13   */
14  public abstract class AbstractConverter implements IConverter {
15  
16      /***
17       * the source and target classes, and conversion weight, subclasses
18       * must initialize these in order to index the converter correctly
19       */
20      Class sourceClass;
21  
22      Class targetClass;
23  
24      ScalarConversionWeight conversionWeight;
25  
26      /* (non-Javadoc)
27       * @see net.sourceforge.jparam.conversion.converters.IConverter#getTargetClass()
28       */
29      public Class getTargetClass() {
30          return targetClass;
31      }
32  
33      /* (non-Javadoc)
34       * @see net.sourceforge.jparam.conversion.converters.IConverter#getWeight()
35       */
36      public ScalarConversionWeight getWeight() {
37          return conversionWeight;
38      }
39  
40      /* (non-Javadoc)
41       * @see net.sourceforge.jparam.conversion.converters.IConverter#getSourceClass()
42       */
43      public Class getSourceClass() {
44          return sourceClass;
45      }
46  
47      /* (non-Javadoc)
48       * @see net.sourceforge.jparam.conversion.converters.IConverter#convert(java.lang.Object)
49       */
50      public Object convert(Object o) throws JParamException {
51          // Verify the given <code>Object</code> is the expected one
52          if (!sourceClass.isInstance(o)) {
53              throw new JParamException("Cannot convert from: " + o.getClass()
54                      + " supported class: " + sourceClass);
55          }
56  
57          try {
58              // Use the overriden internal create method
59              Object ret = internalConvert(o);
60  
61              // Verify the returned object is of the expected instance, if for
62              // some reason there is a bug in the converter, we want to find it
63              // as soon as possible, we use isInstance and not exact class
64              // comparison since we have no static types in Java hence there is
65              // no way of returnig something like the super class
66              if (!targetClass.isInstance(ret)) {
67                  throw new JParamException("Converter returned invalid class: " + ret.getClass()
68                          + " expected class: " + targetClass + "\nReturned value: " + ret);
69              }
70              return ret;
71          } catch (JParamException e) {
72              // If an "expected" exception was thrown, forward it so the original
73              // error is reported
74              throw e;
75          } catch (Exception e) {
76              // Wrap the thrown exception with a supported exception
77              throw new JParamException(
78                      "Unexpected error occured while converting: " + o + " to: "
79                              + targetClass, e);
80          }
81      }
82  
83      /***
84       * Internal conversion method, all subclasses must implement the actual
85       * conversion logic here
86       * <p>
87       * No tests are needed since the given object is of the expected type
88       * 
89       * @param o An object instanceof <code>getSourceClass</code>
90       * @return An object instanceof <code>getTargetClass</code>
91       * @throws Exception If there was an error performing the conversion
92       */
93      protected abstract Object internalConvert(Object o) throws Exception;
94  
95      /* (non-Javadoc)
96       * @see java.lang.Object#toString()
97       */
98      public String toString() {
99          StringBuffer result = new StringBuffer();
100         result.append(toConversionString());
101         result.append("(");
102         result.append(conversionWeight);
103         result.append(")");
104 
105         return result.toString();
106     }
107 
108     public String toConversionString() {
109         StringBuffer result = new StringBuffer();
110         try {
111             // the conversion string should use the JParam type name
112             result.append(TypeNameRegistry.getInstance().getJParamTypeName(
113                     sourceClass));
114         } catch (JParamException e) {
115             // if there is no type then use the Java Class name
116             result.append(sourceClass.getName());
117         }
118 
119         result.append(" -> ");
120 
121         try {
122             result.append(TypeNameRegistry.getInstance().getJParamTypeName(
123                     targetClass));
124         } catch (JParamException e) {
125             result.append(targetClass.getName());
126         }
127 
128         return result.toString();
129     }
130 
131     /***
132      * Tests if this converter is equal to the given converter, all validity
133      * checks of source/target/weight and class instance are performed in the
134      * <code>equal</code> method, the derived class can perform all casts with
135      * no verification
136      * 
137      * The check must verify equality, and not similarity meaning to converters
138      * performing the same conversion with the same weight are not necesarily
139      * equal, for instance two conversion paths from the same source to the same
140      * target but not through the same types, will cause ambiguity if not equal
141      * 
142      * @param o A converter to check for equality
143      * @return true if the converters are equal
144      */
145     protected abstract boolean converterEquals(IConverter o);
146 
147     /* (non-Javadoc)
148      * @see java.lang.Object#hashCode()
149      */
150     public int hashCode() {
151         return sourceClass.hashCode() * 37 + targetClass.hashCode() * 37
152                 + conversionWeight.hashCode();
153     }
154 
155     /***
156      * Verify all trivial tests, and let subclass to specific verification
157      * only
158      * 
159      * @see java.lang.Object#equals(java.lang.Object)
160      */
161     public boolean equals(Object obj) {
162         if (!obj.getClass().equals(this.getClass())) {
163             return false;
164         }
165 
166         AbstractConverter other = (AbstractConverter) obj;
167 
168         if (!sourceClass.equals(other.sourceClass)) {
169             return false;
170         }
171         if (!targetClass.equals(other.targetClass)) {
172             return false;
173         }
174         if (!conversionWeight.equals(other.conversionWeight)) {
175             return false;
176         }
177 
178         return converterEquals(other);
179     }
180 }