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 }