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 abstract 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 * static methods. *
77 * -------------------------------------------------------------------- */
78
79 /**
80 * Returns whether <code>cls</code> represents a primitive type.
81 * Note that also {@link Void#TYPE} is a primitive type.
82 * An implementation of {@link Class#isPrimitive()}.
83 *
84 * @return
85 * Whether <code>cls</code> represents a primitive type.
86 * @see #wrapsPrimitive(Class)
87 */
88 public static boolean isPrimitive(Class<?> cls) {
89 return MAP_BASIC_TYPE2WRAPPER.keySet().contains(cls);
90 }
91
92 /**
93 * Returns whether <code>cls</code> represents a type
94 * wrapping a primitive type.
95 * As an example {@link Integer} wraps <code>int</code> and
96 * {@link Void#TYPE} wraps itself.
97 *
98 * @return
99 * Whether <code>cls</code> wraps a primitive type.
100 * @see #isPrimitive(Class)
101 */
102 public static boolean wrapsPrimitive(Class<?> cls) {
103 return MAP_WRAPPER2BASIC_TYPE.keySet().contains(cls);
104 }
105
106
107 /**
108 * Decides whether the given class and object are compatible.
109 *
110 * @param cls
111 * a <code>Class</code> (of course not <code>null</code>).
112 * @param obj
113 * an <code>Object</code> including <code>null</code>.
114 * @return
115 * <code>true</code> if and only if either of the following holds:
116 * <ul>
117 * <li> <code>cls</code> does not refer to a primitive type
118 * and <code>obj</code> may be casted to <code>cls</code>, i.e.
119 * if either <code>obj == null</code>
120 * or (sequentially) <code>cls.isInstance(obj)</code>.
121 * <li> <code>cls</code> refers to a primitive type
122 * and (sequentially) <code>obj != null</code>
123 * and <code>obj.getClass()</code>
124 * is the corresponding wrapper type.
125 * </ul>
126 * @see #MAP_WRAPPER2BASIC_TYPE
127 */
128 public static boolean areCompatible(Class<?> cls, Object obj) {
129
130 if (cls.isPrimitive()) {
131 // Here, cls represents a primitive class.
132 if (obj == null) {
133 // objects of a primitive class may not be null.
134 return false;
135 }
136 assert obj != null;
137 return getWrapperCls(cls, false).isInstance(obj);
138 // Class<?> basicType = getWrappedCls(obj.getClass(), true);
139 // // return true includes basicType != null.
140 // return cls.equals(basicType);
141 }
142 // Here, cls represents a non-primitive class.
143
144 // Test whether obj may be casted to cls.
145 return obj == null || cls.isInstance(obj);
146 }
147
148 /**
149 * Maps a wrapper class <code>cls</code> to wrapped primitive class.
150 *
151 * @param cls
152 * some <code>Class</code> object.
153 * @param allowsVoid
154 * whether {@link Void#TYPE} is wrapped by itself.
155 * @return
156 * the primitive type wrapped type <code>cls</code>
157 * if <code>cls</code> is the wrapper of a primitive type.
158 * Note that {@link Void#TYPE} may be wrapped by itself.
159 * @throws IllegalArgumentException
160 * if <code>cls</code> wraps no primitive type
161 * or if <code>cls</code> is {@link Void#TYPE}
162 * but this is not allowed by <code>allowsVoid</code>.
163 */
164 public static Class<?> getWrappedCls(Class<?> cls, boolean allowsVoid) {
165 Class<?> res = MAP_WRAPPER2BASIC_TYPE.get(cls);
166 if (res == null || (!allowsVoid && res == Void.TYPE)) {
167 throw new IllegalArgumentException
168 ("Expected wrapper class of primitive type " +
169 (allowsVoid ? "or" : "but not") +
170 " void; found " + cls + ". ");
171 }
172 assert res != null && (allowsVoid || res != Void.TYPE);
173 return res;
174 }
175
176 /**
177 * Maps a primitive class <code>cls</code>
178 * to the corresponding wrapper class.
179 *
180 * @param cls
181 * some <code>Class</code> object.
182 * @param allowsVoid
183 * whether {@link Void#TYPE} wraps itself.
184 * @return
185 * the wrapper type of type <code>cls</code>
186 * if <code>cls</code> is a primitive type.
187 * Note that {@link Void#TYPE} may wrap itself.
188 * @throws IllegalArgumentException
189 * if <code>cls</code> is no primitive type
190 * or if <code>cls</code> is {@link Void#TYPE}
191 * but this is not allowed by <code>allowsVoid</code>.
192 */
193 public static Class<?> getWrapperCls(Class<?> cls, boolean allowsVoid) {
194 Class<?> res = MAP_BASIC_TYPE2WRAPPER.get(cls);
195 if (res == null || (!allowsVoid && res == Void.TYPE)) {
196 throw new IllegalArgumentException
197 ("Expected primitive type " +
198 (allowsVoid ? "or" : "but not") +
199 " void; found " + cls + ". ");
200 }
201 assert res != null && (allowsVoid || res != Void.TYPE);
202 return res;
203 }
204 }
205