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