001: /***
002: * Retrotranslator: a Java bytecode transformer that translates Java classes
003: * compiled with JDK 5.0 into classes that can be run on JVM 1.4.
004: *
005: * Copyright (c) 2005 - 2008 Taras Puchko
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * 3. Neither the name of the copyright holders nor the names of its
017: * contributors may be used to endorse or promote products derived from
018: * this software without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
022: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
023: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
024: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
025: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
026: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
027: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
028: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
029: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
030: * THE POSSIBILITY OF SUCH DAMAGE.
031: */package net.sf.retrotranslator.runtime.impl;
032:
033: import java.io.*;
034: import java.lang.reflect.*;
035: import java.security.*;
036: import java.util.MissingResourceException;
037: import net.sf.retrotranslator.runtime.asm.Type;
038:
039: /**
040: * @author Taras Puchko
041: */
042: public class RuntimeTools {
043:
044: public static final String CONSTRUCTOR_NAME = "<init>";
045: public static final String STATIC_NAME = "<clinit>";
046: public static final String CLASS_EXTENSION = ".class";
047:
048: public static Class getBaseClass(char type) {
049: return getBaseClass(Type
050: .getType(new String(new char[] { type })));
051: }
052:
053: public static Class getBaseClass(Type type) {
054: switch (type.getSort()) {
055: case Type.VOID:
056: return void.class;
057: case Type.BOOLEAN:
058: return boolean.class;
059: case Type.CHAR:
060: return char.class;
061: case Type.BYTE:
062: return byte.class;
063: case Type.SHORT:
064: return short.class;
065: case Type.INT:
066: return int.class;
067: case Type.FLOAT:
068: return float.class;
069: case Type.LONG:
070: return long.class;
071: case Type.DOUBLE:
072: return double.class;
073: }
074: return null;
075: }
076:
077: public static String getConstructorDescriptor(final Constructor c) {
078: Class[] parameters = c.getParameterTypes();
079: StringBuffer buf = new StringBuffer("(");
080: for (Class parameter : parameters) {
081: buf.append(Type.getDescriptor(parameter));
082: }
083: return buf.append(")V").toString();
084: }
085:
086: public static Object cloneNonEmptyArray(Object value) {
087: if (!value.getClass().isArray() || Array.getLength(value) == 0)
088: return value;
089: if (value instanceof Object[])
090: return ((Object[]) value).clone();
091: if (value instanceof boolean[])
092: return ((boolean[]) value).clone();
093: if (value instanceof byte[])
094: return ((byte[]) value).clone();
095: if (value instanceof char[])
096: return ((char[]) value).clone();
097: if (value instanceof double[])
098: return ((double[]) value).clone();
099: if (value instanceof float[])
100: return ((float[]) value).clone();
101: if (value instanceof int[])
102: return ((int[]) value).clone();
103: if (value instanceof long[])
104: return ((long[]) value).clone();
105: if (value instanceof short[])
106: return ((short[]) value).clone();
107: throw new IllegalStateException();
108: }
109:
110: public static String getString(java.lang.reflect.Type type) {
111: if (!(type instanceof Class))
112: return type.toString();
113: Class aClass = (Class) type;
114: int dimensionCount = 0;
115: for (; aClass.isArray(); dimensionCount++) {
116: aClass = aClass.getComponentType();
117: }
118: if (dimensionCount == 0)
119: return aClass.getName();
120: StringBuilder builder = new StringBuilder();
121: builder.append(aClass.getName());
122: for (; dimensionCount > 0; dimensionCount--) {
123: builder.append("[]");
124: }
125: return builder.toString();
126: }
127:
128: public static StringBuilder append(StringBuilder builder,
129: java.lang.reflect.Type[] types) {
130: for (int i = 0; i < types.length; i++) {
131: if (i > 0)
132: builder.append(',');
133: builder.append(getString(types[i]));
134: }
135: return builder;
136: }
137:
138: public static byte[] readResourceToByteArray(Class loader,
139: String resourceName) throws MissingResourceException {
140: return readAndClose(loader.getResourceAsStream(resourceName));
141: }
142:
143: public static byte[] readAndClose(InputStream inputStream) {
144: if (inputStream == null)
145: return null;
146: try {
147: try {
148: byte[] buffer = new byte[0x1000];
149: ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
150: int count;
151: while ((count = inputStream.read(buffer)) > 0) {
152: outputStream.write(buffer, 0, count);
153: }
154: return outputStream.toByteArray();
155: } finally {
156: inputStream.close();
157: }
158: } catch (IOException e) {
159: throw new RuntimeException(e);
160: }
161: }
162:
163: public static byte[] getBytecode(Class target) {
164: if (target.isPrimitive() || target.isArray())
165: return null;
166: String targetName = target.getName();
167: int index = targetName.lastIndexOf('.');
168: String simpleName = index < 0 ? targetName : targetName
169: .substring(index + 1);
170: return readResourceToByteArray(target, simpleName
171: + CLASS_EXTENSION);
172: }
173:
174: public static UndeclaredThrowableException unwrap(
175: InvocationTargetException exception) {
176: try {
177: throw exception.getTargetException();
178: } catch (RuntimeException e) {
179: throw e;
180: } catch (Error e) {
181: throw e;
182: } catch (Throwable e) {
183: return new UndeclaredThrowableException(e);
184: }
185: }
186:
187: public static Object invokeMethod(final Object target,
188: final String name, final Class[] parameterTypes,
189: final Object[] args) throws NoSuchMethodException,
190: InvocationTargetException {
191: try {
192: return AccessController
193: .doPrivileged(new PrivilegedExceptionAction<Object>() {
194: public Object run() throws Exception {
195: return invoke(target, name, parameterTypes,
196: args);
197: }
198: });
199: } catch (PrivilegedActionException exception) {
200: try {
201: throw exception.getException();
202: } catch (NoSuchMethodException e) {
203: throw e;
204: } catch (InvocationTargetException e) {
205: throw e;
206: } catch (Exception e) {
207: throw new Error(e);
208: }
209: }
210: }
211:
212: private static Object invoke(Object target, String name,
213: Class[] parameterTypes, Object[] args)
214: throws NoSuchMethodException, InvocationTargetException {
215: Method method;
216: try {
217: method = target.getClass().getMethod(name, parameterTypes);
218: } catch (SecurityException e) {
219: throw new NoSuchMethodException(e.getMessage());
220: }
221: try {
222: method.setAccessible(true);
223: } catch (SecurityException e) {
224: // ignore
225: }
226: try {
227: return method.invoke(target, args);
228: } catch (IllegalAccessException e) {
229: throw new NoSuchMethodException(e.getMessage());
230: }
231: }
232:
233: public static String getDisplayClassName(String internalName) {
234: return internalName.replace('/', '.');
235: }
236:
237: public static String getFieldInfo(String className, String fieldName) {
238: return className + '.' + fieldName;
239: }
240:
241: public static String getMethodInfo(String className,
242: String methodName, String methodDesc) {
243: StringBuilder builder = new StringBuilder(className)
244: .append('.').append(methodName);
245: builder.append('(');
246: for (Type type : Type.getArgumentTypes(methodDesc)) {
247: builder.append(type.getClassName()).append(',');
248: }
249: builder.setCharAt(builder.length() - 1, ')');
250: return builder.toString();
251: }
252:
253: public static java.lang.reflect.Type[] getTypes(Class[] rawTypes,
254: java.lang.reflect.Type[] genericTypes) {
255: if (genericTypes == null
256: || genericTypes.length != rawTypes.length) {
257: return rawTypes;
258: }
259: for (int i = 0; i < rawTypes.length; i++) {
260: if (!isCorrect(rawTypes[i], genericTypes[i]))
261: return rawTypes;
262: }
263: return genericTypes;
264: }
265:
266: public static java.lang.reflect.Type getType(Class rawType,
267: java.lang.reflect.Type genericType) {
268: return isCorrect(rawType, genericType) ? genericType : rawType;
269: }
270:
271: private static boolean isCorrect(Class rawType,
272: java.lang.reflect.Type genericType) {
273: if (genericType instanceof Class) {
274: return rawType == genericType;
275: } else if (genericType instanceof ParameterizedType) {
276: return ((ParameterizedType) genericType).getRawType() == rawType;
277: } else {
278: return genericType != null;
279: }
280: }
281:
282: }
|