1
2 package eu.simuline.util;
3
4 import java.util.Map;
5 import java.util.HashMap;
6
7 /**
8 * Provides methods to map basic types to their wrappers,
9 * to map wrapper types to the corresponding basic types
10 * and for compatibility checks.
11 *
12 * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
13 * @version 1.0
14 */
15 public final class BasicTypesCompatibilityChecker {
16
17 /* -------------------------------------------------------------------- *
18 * class constants. *
19 * -------------------------------------------------------------------- */
20
21 /**
22 * Maps wrapper classes to the corresponding basic classes.
23 * E.g. Boolean is mapped to boolean.
24 * Note that {@link Void#TYPE} is mapped to itself.
25 *
26 * @see #areCompatible(Class, Object)
27 */
28 private static final Map<Class<?>, Class<?>> MAP_WRAPPER2BASIC_TYPE =
29 new HashMap<Class<?>, Class<?>>();
30
31 /**
32 * Maps basic classes to the corresponding wrapper classes.
33 * E.g. boolean is mapped to Boolean.
34 * Note that {@link Void#TYPE} is mapped to itself.
35 *
36 * @see #areCompatible (Class, Object)
37 */
38 private static final Map<Class<?>, Class<?>> MAP_BASIC_TYPE2WRAPPER =
39 new HashMap<Class<?>, Class<?>>();
40
41
42 /* -------------------------------------------------------------------- *
43 * static initializer. *
44 * -------------------------------------------------------------------- */
45
46 /**
47 * Initializes {@link #MAP_WRAPPER2BASIC_TYPE} and
48 * {@link #MAP_BASIC_TYPE2WRAPPER}.
49 */
50 static {
51 // initialize MAP_WRAPPER2BASIC_TYPE
52 MAP_WRAPPER2BASIC_TYPE.put(Boolean .class, Boolean .TYPE);
53 MAP_WRAPPER2BASIC_TYPE.put(Character.class, Character.TYPE);
54 MAP_WRAPPER2BASIC_TYPE.put(Byte .class, Byte .TYPE);
55 MAP_WRAPPER2BASIC_TYPE.put(Short .class, Short .TYPE);
56 MAP_WRAPPER2BASIC_TYPE.put(Integer .class, Integer .TYPE);
57 MAP_WRAPPER2BASIC_TYPE.put(Long .class, Long .TYPE);
58 MAP_WRAPPER2BASIC_TYPE.put(Float .class, Float .TYPE);
59 MAP_WRAPPER2BASIC_TYPE.put(Double .class, Double .TYPE);
60 MAP_WRAPPER2BASIC_TYPE.put(Void .TYPE, Void .TYPE);
61
62 // initialize MAP_BASIC_TYPE2WRAPPER
63 MAP_BASIC_TYPE2WRAPPER.put(Boolean .TYPE, Boolean .class);
64 MAP_BASIC_TYPE2WRAPPER.put(Character.TYPE, Character.class);
65 MAP_BASIC_TYPE2WRAPPER.put(Byte .TYPE, Byte .class);
66 MAP_BASIC_TYPE2WRAPPER.put(Short .TYPE, Short .class);
67 MAP_BASIC_TYPE2WRAPPER.put(Integer .TYPE, Integer .class);
68 MAP_BASIC_TYPE2WRAPPER.put(Long .TYPE, Long .class);
69 MAP_BASIC_TYPE2WRAPPER.put(Float .TYPE, Float .class);
70 MAP_BASIC_TYPE2WRAPPER.put(Double .TYPE, Double .class);
71 MAP_BASIC_TYPE2WRAPPER.put(Void .TYPE, Void .TYPE);
72 } // static
73
74
75 /**
76 * Prevents <code>BasicTypesCompatibilityChecker</code>
77 * from being instantiated.
78 */
79 private BasicTypesCompatibilityChecker() {}
80
81 /* -------------------------------------------------------------------- *
82 * static methods. *
83 * -------------------------------------------------------------------- */
84
85 /**
86 * Returns whether <code>cls</code> represents a primitive type.
87 * Note that also {@link Void#TYPE} is a primitive type.
88 * An implementation of {@link Class#isPrimitive()}.
89 *
90 * @return
91 * Whether <code>cls</code> represents a primitive type.
92 * @see #wrapsPrimitive(Class)
93 */
94 public static boolean isPrimitive(Class<?> cls) {
95 return MAP_BASIC_TYPE2WRAPPER.keySet().contains(cls);
96 }
97
98 /**
99 * Returns whether <code>cls</code> represents a type
100 * wrapping a primitive type.
101 * As an example {@link Integer} wraps <code>int</code> and
102 * {@link Void#TYPE} wraps itself.
103 *
104 * @return
105 * Whether <code>cls</code> wraps a primitive type.
106 * @see #isPrimitive(Class)
107 */
108 public static boolean wrapsPrimitive(Class<?> cls) {
109 return MAP_WRAPPER2BASIC_TYPE.keySet().contains(cls);
110 }
111
112
113 /**
114 * Decides whether the given class and object are compatible.
115 *
116 * @param cls
117 * a <code>Class</code> (of course not <code>null</code>).
118 * @param obj
119 * an <code>Object</code> including <code>null</code>.
120 * @return
121 * <code>true</code> if and only if either of the following holds:
122 * <ul>
123 * <li> <code>cls</code> does not refer to a primitive type
124 * and <code>obj</code> may be casted to <code>cls</code>, i.e.
125 * if either <code>obj == null</code>
126 * or (sequentially) <code>cls.isInstance(obj)</code>.
127 * <li> <code>cls</code> refers to a primitive type
128 * and (sequentially) <code>obj != null</code>
129 * and <code>obj.getClass()</code>
130 * is the corresponding wrapper type.
131 * </ul>
132 * @see #MAP_WRAPPER2BASIC_TYPE
133 */
134 public static boolean areCompatible(Class<?> cls, Object obj) {
135
136 if (cls.isPrimitive()) {
137 // Here, cls represents a primitive class.
138 if (obj == null) {
139 // objects of a primitive class may not be null.
140 return false;
141 }
142 assert obj != null;
143 return getWrapperCls(cls, false).isInstance(obj);
144 // Class<?> basicType = getWrappedCls(obj.getClass(), true);
145 // // return true includes basicType != null.
146 // return cls.equals(basicType);
147 }
148 // Here, cls represents a non-primitive class.
149
150 // Test whether obj may be casted to cls.
151 return obj == null || cls.isInstance(obj);
152 }
153
154 /**
155 * Maps a wrapper class <code>cls</code> to wrapped primitive class.
156 *
157 * @param cls
158 * some <code>Class</code> object.
159 * @param allowsVoid
160 * whether {@link Void#TYPE} is wrapped by itself.
161 * @return
162 * the primitive type wrapped type <code>cls</code>
163 * if <code>cls</code> is the wrapper of a primitive type.
164 * Note that {@link Void#TYPE} may be wrapped by itself.
165 * @throws IllegalArgumentException
166 * if <code>cls</code> wraps no primitive type
167 * or if <code>cls</code> is {@link Void#TYPE}
168 * but this is not allowed by <code>allowsVoid</code>.
169 */
170 public static Class<?> getWrappedCls(Class<?> cls, boolean allowsVoid) {
171 Class<?> res = MAP_WRAPPER2BASIC_TYPE.get(cls);
172 if (res == null || (!allowsVoid && res == Void.TYPE)) {
173 throw new IllegalArgumentException
174 ("Expected wrapper class of primitive type " +
175 (allowsVoid ? "or" : "but not") +
176 " void; found " + cls + ". ");
177 }
178 assert res != null && (allowsVoid || res != Void.TYPE);
179 return res;
180 }
181
182 /**
183 * Maps a primitive class <code>cls</code>
184 * to the corresponding wrapper class.
185 *
186 * @param cls
187 * some <code>Class</code> object.
188 * @param allowsVoid
189 * whether {@link Void#TYPE} wraps itself.
190 * @return
191 * the wrapper type of type <code>cls</code>
192 * if <code>cls</code> is a primitive type.
193 * Note that {@link Void#TYPE} may wrap itself.
194 * @throws IllegalArgumentException
195 * if <code>cls</code> is no primitive type
196 * or if <code>cls</code> is {@link Void#TYPE}
197 * but this is not allowed by <code>allowsVoid</code>.
198 */
199 public static Class<?> getWrapperCls(Class<?> cls, boolean allowsVoid) {
200 Class<?> res = MAP_BASIC_TYPE2WRAPPER.get(cls);
201 if (res == null || (!allowsVoid && res == Void.TYPE)) {
202 throw new IllegalArgumentException
203 ("Expected primitive type " +
204 (allowsVoid ? "or" : "but not") +
205 " void; found " + cls + ". ");
206 }
207 assert res != null && (allowsVoid || res != Void.TYPE);
208 return res;
209 }
210 }
211