View Javadoc
1   
2   package eu.simuline.util;
3   
4   /**
5    * Provides ways to transform instances of various classes into one another. 
6    * The core method is {@link #cast}: it performs the transformation. 
7    * <p>
8    * A simple example would be to transform {@link java.lang.Double}s 
9    * into <code>eu.simuline.arithmetics.left2right.FPNumber</code>s. 
10   * Another example is given by {@link #BASIC_TYPES}. 
11   * It is the foundation to transform arrays of elementary types 
12   * to arrays of their wrappers and the other way round 
13   * such as <code>double[][]</code> and <code>Double[][]</code>. 
14   * <p>
15   * Casters may be used to transform descriptors of objects into these objects. 
16   * A snippet of typical implementation for the {@link #cast}-method 
17   * would be "<code>return new ExaClass(descriptor)</code>" in this case. 
18   *
19   * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
20   * @version 1.0
21   */
22  public abstract class Caster {
23  
24      /* -------------------------------------------------------------------- *
25       * inner classes.                                                       *
26       * -------------------------------------------------------------------- */
27  
28      /**
29       * A trivial caster for which compatibility 
30       * is assignment compatibility. 
31       */
32      public static final Caster ASSIGNEMENT_COMPATIBLE = new Trivial() {
33  	    public boolean areCompatible(final Class<?> cls, final Object obj) {
34  		return cls.isInstance(obj);
35  	    }
36  	}; // ASSIGNEMENT_COMPATIBLE 
37  
38      /**
39       * A trivial caster for which compatibility 
40       * is equality of classes. 
41       */
42      public static final Caster STRICT = new Trivial() {
43  	    public boolean areCompatible(final Class<?> cls, final Object obj) {
44  		return cls == obj.getClass();
45  	    }
46  	}; // STRICT 
47  
48      /**
49       * A trivial caster for which compatibility 
50       * is assignment compatibility 
51       * up to wrapping and unwrapping of primitive types. 
52       * Used to implement 
53       * {@link CollectionsExt#recToArray(Object,Class)} 
54       * as a special case of 
55       * {@link CollectionsExt#recToArray(Object,Class,Caster)}. 
56       */
57      public static final Caster BASIC_TYPES = new Trivial() {
58  
59  	    /**
60  	     * Behaves like 
61  	     * {@link BasicTypesCompatibilityChecker#areCompatible}. 
62  	     *
63  	     * @param cls 
64  	     *    a <code>Class</code>. 
65  	     * @param obj 
66  	     *    an <code>Object</code>. 
67  	     * @return 
68  	     *    see {@link BasicTypesCompatibilityChecker#areCompatible}. 
69  	     */
70  	    public boolean areCompatible(final Class<?> cls, final Object obj) {
71  		return BasicTypesCompatibilityChecker.areCompatible(cls, obj);
72  	    }
73  	}; // BASIC_TYPES 
74  
75      /**
76       * This is a trivial caster. 
77       * Method {@link #areCompatible} is still to be implemented. 
78       */
79      abstract static class Trivial extends Caster { // NOPMD
80  
81  	    /**
82  	     * Returns the input parameter unchanged. 
83  	     *
84  	     * @param obj 
85  	     *    An arbitrary object or <code>null</code>. 
86  	     * @return 
87  	     *    the input parameter without a change. 
88  	     */
89  	    public Object cast(final Object obj) {
90  		return obj;
91  	    }
92  	}; // Trivial  
93  
94      /* -------------------------------------------------------------------- *
95       * methods.                                                             *
96       * -------------------------------------------------------------------- */
97  
98      /**
99       * Decides whether the given class and object 
100      * are compatible with respect to this caster. 
101      *
102      * @param cls 
103      *    a <code>Class</code>. 
104      * @param obj 
105      *    an <code>Object</code>. 
106      * @return 
107      *    <code>true</code> if and only if either of the following holds: 
108      *    <ul>
109      *    <li> <code>cast(obj)</code> may be casted to <code>cls</code>, i.e. 
110      *         if either <code>cast(obj) == null</code> 
111      *         (which is the case for <code>obj == null</code>) 
112      *         or (sequentially) <code>cls.isInstance(cast(obj))</code>. 
113      *    <li> <code>cls</code> is a basic type, 
114      *         <code>cast(obj) != null</code> and (sequentially) 
115      *         <code>cast(obj).getClass()</code> 
116      *         is the corresponding wrapper type. 
117      *    </ul>
118      * @see BasicTypesCompatibilityChecker#areCompatible
119      */
120     public abstract boolean areCompatible(Class<?> cls, Object obj);
121 
122     /*
123      * Provided the return value is not <code>null</code>, 
124      * <code>cast(obj)</code> has to be either <code>null</code> 
125      * or an instance of <code>targetClass(obj.getClass()))</code>. 
126      * <p>
127      * This means that {@link #cast} may be used 
128      *
129      * @param cls 
130      *    a <code>Class</code> object; not <code>null</code>. 
131      * @return 
132      *    <ul>
133      *    <li>
134      *    <code>null</code> if {@link #cast} is not defined, 
135      *    i.e. if it throws an **** exception. 
136      *    <li>
137      *    A class to which the return value of {@link #cast} may be casted 
138      *    for input of the type <code>cls</code>. 
139      *    This return value may well be <code>null</code> 
140      *    or it may be an instance of a subclass. 
141      *    </ul>
142      */
143     //Class targetClass(Class cls);
144 
145     /**
146      * The return value <code>cast(obj)</code> 
147      * (which may well be <code>null</code>), 
148      * may be casted to class <code>cls</code> 
149      * if {@link #areCompatible} returns <code>true</code>. 
150      *
151      * @param obj 
152      *    an arbitrary <code>Object</code> or even <code>null</code>. 
153      * @return 
154      *    <ul>
155      *    <li>
156      *    <code>null</code> for <code>obj == null</code>. 
157      *    <li>
158      *    <code>null</code> if <code>obj != null</code> 
159      *    but <code>targetClass(obj.getClass()) == null</code>. **** 
160      *    <li>
161      *    either <code>null</code> again 
162      *    or an instance of <code>targetClass(obj.getClass())</code>
163      *    </ul>
164      */
165     public abstract Object cast(Object obj);
166 }