001: package prefuse.util;
002:
003: /**
004: * Library routines dealing with Java Class types.
005: *
006: * @author <a href="http://jheer.org">jeffrey heer</a>
007: */
008: public class TypeLib {
009:
010: private TypeLib() {
011: // prevent instantiation
012: }
013:
014: // ------------------------------------------------------------------------
015:
016: /**
017: * Check if an object is an instance of a given class, or, if the class
018: * is a primitive type, if the Object is an instance of the wrapper class
019: * for that primitive (e.g., as Integer is a wrapper for int).
020: * @param type the Class type
021: * @param instance the Object instance
022: * @return true if the object is an instance of the given class, or if
023: * of the appropriate primitive wrapper type.
024: */
025: public static boolean typeCheck(Class type, Object instance) {
026: return type.isAssignableFrom(instance.getClass())
027: || isWrapperInstance(type, instance);
028: }
029:
030: /**
031: * Get the nearest shared ancestor class of two objects. Note: this
032: * currently does not compute the actual least common ancestor, but
033: * only looks up one level in the inheritance tree and quits if
034: * it does not find a match.
035: * @param o1 the first object
036: * @param o2 the second object
037: * @return the nearest class instance of which both objects
038: * are instances
039: */
040: public static Class getSharedType(Object o1, Object o2) {
041: return getSharedType(o1.getClass(), o2.getClass());
042: }
043:
044: /**
045: * Get the nearest shared ancestor class of two classes. Note: this
046: * currently does not compute the actual least common ancestor, but
047: * only looks up one level in the inheritance tree and quits if
048: * it does not find a match.
049: * @param type1 the first type
050: * @param type2 the second type
051: * @return the nearest class instance which is equal to or a
052: * superclass of the two class instances
053: */
054: public static Class getSharedType(Class type1, Class type2) {
055: if (type1 == type2) {
056: return type1;
057: } else if (type1.isAssignableFrom(type2)) {
058: return type1;
059: } else if (type2.isAssignableFrom(type1)) {
060: return type2;
061: } else {
062: return null;
063: }
064: }
065:
066: /**
067: * Indicates if an object is an instance of a wrapper class for a given
068: * primitive type.
069: * @param type the primitive Class type
070: * @param instance the object to test as wrapper (e.g., as Integer is a
071: * wrapper type for int)
072: * @return true if the object is a wrapper instance of the given
073: * primitive type
074: */
075: public static boolean isWrapperInstance(Class type, Object instance) {
076: if (!type.isPrimitive())
077: throw new IllegalArgumentException(
078: "Input type must be a primitive");
079:
080: if (int.class == type && instance instanceof Integer) {
081: return true;
082: } else if (long.class == type && instance instanceof Long) {
083: return true;
084: } else if (float.class == type && instance instanceof Float) {
085: return true;
086: } else if (double.class == type && instance instanceof Double) {
087: return true;
088: } else if (boolean.class == type && instance instanceof Boolean) {
089: return true;
090: } else if (short.class == type && instance instanceof Short) {
091: return true;
092: } else if (byte.class == type && instance instanceof Byte) {
093: return true;
094: } else if (char.class == type && instance instanceof Character) {
095: return true;
096: } else {
097: return false;
098: }
099: }
100:
101: /**
102: * Given a numeric (byte, short, int, long, float, or double) class type or
103: * associated wrapper class type, return the primitive class type
104: * @param type the type to look up, must be a numerical type, but can be
105: * either primitive or a wrapper.
106: * @return the primitive class type
107: */
108: public static Class getPrimitiveType(Class type) {
109: if (Integer.class.equals(type) || type == int.class) {
110: return int.class;
111: } else if (Long.class.equals(type) || type == long.class) {
112: return long.class;
113: } else if (Float.class.equals(type) || type == float.class) {
114: return float.class;
115: } else if (Double.class.equals(type) || type == double.class) {
116: return double.class;
117: } else if (Byte.class.equals(type) || type == byte.class) {
118: return byte.class;
119: } else if (Short.class.equals(type) || type == short.class) {
120: return short.class;
121: } else {
122: throw new IllegalArgumentException(
123: "Input class must be a numeric type");
124: }
125: }
126:
127: /**
128: * Get the wrapper class type for a primitive class type.
129: * @param type a class type
130: * @return the wrapper class for the input type if it is a
131: * primitive class type, otherwise returns the input type
132: */
133: public static Class getWrapperType(Class type) {
134: if (!type.isPrimitive()) {
135: return type;
136: } else if (int.class == type) {
137: return Integer.class;
138: } else if (long.class == type) {
139: return Long.class;
140: } else if (float.class == type) {
141: return Float.class;
142: } else if (double.class == type) {
143: return Double.class;
144: } else if (boolean.class == type) {
145: return Boolean.class;
146: } else if (short.class == type) {
147: return Short.class;
148: } else if (char.class == type) {
149: return Character.class;
150: } else if (byte.class == type) {
151: return Byte.class;
152: } else if (short.class == type) {
153: return Short.class;
154: } else {
155: throw new IllegalArgumentException();
156: }
157: }
158:
159: /**
160: * Indicates if a given class type is a primitive integer type
161: * (one of byte, short, int, or long).
162: * @param type the type to check
163: * @return true if it is a primitive numeric type, false otherwise
164: */
165: public static boolean isIntegerType(Class type) {
166: return (type == byte.class || type == short.class
167: || type == int.class || type == long.class);
168: }
169:
170: /**
171: * Indicates if a given class type is a primitive numeric one type
172: * (one of byte, short, int, long, float, or double).
173: * @param type the type to check
174: * @return true if it is a primitive numeric type, false otherwise
175: */
176: public static boolean isNumericType(Class type) {
177: return (type == byte.class || type == short.class
178: || type == int.class || type == long.class
179: || type == double.class || type == float.class);
180: }
181:
182: /**
183: * Get a compatible numeric type for two primitive numeric
184: * class types. Any of (byte, short, int) will resolve to int.
185: * @param c1 a numeric primitive class type (int, long, float, or double)
186: * @param c2 a numeric primitive class type (int, long, float, or double)
187: * @return the compatible numeric type for binary operations involving
188: * both types.
189: */
190: public static Class getNumericType(Class c1, Class c2) {
191: if (!isNumericType(c1) || !isNumericType(c2)) {
192: throw new IllegalArgumentException(
193: "Input types must be primitive number types");
194: }
195: if (c1 == double.class || c2 == double.class) {
196: return double.class;
197: } else if (c1 == float.class || c1 == float.class) {
198: return float.class;
199: } else if (c1 == long.class || c2 == long.class) {
200: return long.class;
201: } else {
202: return int.class;
203: }
204: }
205:
206: } // end of class TypeLib
|