View Javadoc
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