/**
* Copyright (C) 2001-2005 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.objectweb.speedo.generation.enhancer.common;
import org.objectweb.asm.CodeVisitor;
import org.objectweb.asm.Constants;
import org.objectweb.asm.Type;
import org.objectweb.speedo.generation.lib.NamingRules;
import org.objectweb.speedo.metadata.SpeedoClass;
import org.objectweb.speedo.metadata.SpeedoPackage;
import org.objectweb.speedo.metadata.SpeedoXMLDescriptor;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Utility class.
*
* Adapted from isPersistentType and isPersitentCapable in EnhancerTool.
*/
public class Util {
private static Set PERSISTENT_CLASSES;
private static Set AUTO_PERSISTENT_CLASSES;
static {
PERSISTENT_CLASSES = new HashSet();
AUTO_PERSISTENT_CLASSES = new HashSet();
AUTO_PERSISTENT_CLASSES.add("java.lang.String");
AUTO_PERSISTENT_CLASSES.add("java.lang.Character");
AUTO_PERSISTENT_CLASSES.add("java.lang.Boolean");
AUTO_PERSISTENT_CLASSES.add("java.lang.Number");
AUTO_PERSISTENT_CLASSES.add("java.lang.Byte");
AUTO_PERSISTENT_CLASSES.add("java.lang.Integer");
AUTO_PERSISTENT_CLASSES.add("java.lang.Long");
AUTO_PERSISTENT_CLASSES.add("java.lang.Double");
AUTO_PERSISTENT_CLASSES.add("java.lang.Float");
AUTO_PERSISTENT_CLASSES.add("java.lang.Short");
AUTO_PERSISTENT_CLASSES.add("java.math.BigInteger");
AUTO_PERSISTENT_CLASSES.add("java.math.BigDecimal");
PERSISTENT_CLASSES.add("java.util.Collection");
PERSISTENT_CLASSES.add("java.util.Map");
PERSISTENT_CLASSES.add("java.util.Set");
PERSISTENT_CLASSES.add("java.util.List");
PERSISTENT_CLASSES.add("java.util.LinkedList");
PERSISTENT_CLASSES.add("java.util.ArrayList");
PERSISTENT_CLASSES.add("java.util.HashMap");
PERSISTENT_CLASSES.add("java.util.TreeMap");
PERSISTENT_CLASSES.add("java.util.WeakHashMap");
PERSISTENT_CLASSES.add("java.util.Properties");
PERSISTENT_CLASSES.add("java.util.Vector");
PERSISTENT_CLASSES.add("java.util.HashTable");
PERSISTENT_CLASSES.add("java.util.Stack");
PERSISTENT_CLASSES.add("java.util.Date");
PERSISTENT_CLASSES.add("java.util.Locale");
AUTO_PERSISTENT_CLASSES.add("java.sql.Date");
AUTO_PERSISTENT_CLASSES.add("java.sql.Time");
AUTO_PERSISTENT_CLASSES.add("java.sql.Timestamp");
PERSISTENT_CLASSES.addAll(AUTO_PERSISTENT_CLASSES);
}
/**
* Tests whether a specific Type can be defined persistent.
*
* @see #isPersistentCapable
* @param desc the descriptor of the type that is tested
* @param xml a collection of SpeedoXMLDescriptor
* @return true is the type can be defaulted as persistent, false either
*/
public static boolean isPersistentType(final String desc,
final Collection xml) {
Type type = Type.getType(desc);
if (type.getSort() == Type.ARRAY) {
// an array can be defaulted as persistent if its elements can
return isPersistentType(type.getElementType().getDescriptor(), xml);
} else if (type.getSort() == Type.OBJECT) {
// for the class types it depends on the package and the class
String className = type.getClassName();
return PERSISTENT_CLASSES.contains(className)
|| isPersistentCapable(className, xml) != null;
} else {
// a basic type can always be defaulted as persistent
return true;
}
}
public static boolean isAutomaticPersistentType(final String desc,
final Collection xml) {
Type type = Type.getType(desc);
if (type.getSort() == Type.ARRAY) {
return false;
} else if (type.getSort() == Type.OBJECT) {
// for the class types it depends on the package and the class
String className = type.getClassName();
return AUTO_PERSISTENT_CLASSES.contains(className)
|| isPersistentCapable(className, xml) != null;
} else {
// a basic type can always be defaulted as persistent
return true;
}
}
/**
* Tests whether a class exists in the object model.
*
* @param className the complete name of the class
* @param xml a collection of SpeedoXMLDescriptor
* @return null if the class is not known as a persistent capable class
*/
public static SpeedoClass isPersistentCapable(final String className,
final Collection xml) {
Iterator i = xml.iterator();
while (i.hasNext()) {
SpeedoXMLDescriptor xmlDesc = (SpeedoXMLDescriptor) i.next();
String fieldPackage = NamingRules.packageName(className);
String fieldClass = NamingRules.className(className);
SpeedoPackage pkg = (SpeedoPackage) xmlDesc.packages.get(fieldPackage);
if (pkg != null) {
SpeedoClass c = (SpeedoClass) pkg.classes.get(fieldClass);
if (c != null) {
return c;
}
}
}
return null;
}
// ASM TOOLS //
//-----------//
public static void visitIntConstant(CodeVisitor cv, int value) {
if (value == 0) {
cv.visitInsn(Constants.ICONST_0);
} else if (value == 1) {
cv.visitInsn(Constants.ICONST_1);
} else if (value == 2) {
cv.visitInsn(Constants.ICONST_2);
} else if (value == 3) {
cv.visitInsn(Constants.ICONST_3);
} else if (value == 4) {
cv.visitInsn(Constants.ICONST_4);
} else if (value == 5) {
cv.visitInsn(Constants.ICONST_5);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
cv.visitIntInsn(Constants.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
cv.visitIntInsn(Constants.SIPUSH, value);
} else {
cv.visitLdcInsn(new Integer(value));
}
}
public static void visitLongConstant(CodeVisitor cv, long value) {
if (value == 0) {
cv.visitInsn(Constants.LCONST_0);
} else if (value == 1) {
cv.visitInsn(Constants.LCONST_1);
} else {
cv.visitLdcInsn(new Long(value));
}
}
// CONVERSIONS FROM ASM TO JAVA SOURCE CODE //
//------------------------------------------//
public static String modifier(int access) {
StringBuffer buf = new StringBuffer();
if ((access & Constants.ACC_PUBLIC) != 0) {
buf.append("public ");
}
if ((access & Constants.ACC_PRIVATE) != 0) {
buf.append("private ");
}
if ((access & Constants.ACC_PROTECTED) != 0) {
buf.append("protected ");
}
if ((access & Constants.ACC_FINAL) != 0) {
buf.append("final ");
}
if ((access & Constants.ACC_STATIC) != 0) {
buf.append("static ");
}
if ((access & Constants.ACC_SYNCHRONIZED) != 0) {
buf.append("synchronized ");
}
if ((access & Constants.ACC_VOLATILE) != 0) {
buf.append("volatile ");
}
if ((access & Constants.ACC_TRANSIENT) != 0) {
buf.append("transient ");
}
if ((access & Constants.ACC_NATIVE) != 0) {
buf.append("native ");
}
if ((access & Constants.ACC_ABSTRACT) != 0) {
buf.append("abstract ");
}
if ((access & Constants.ACC_STRICT) != 0) {
buf.append("strictfp ");
}
return buf.toString();
}
public static String type(Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
return "boolean";
case Type.CHAR:
return "char";
case Type.BYTE:
return "byte";
case Type.SHORT:
return "short";
case Type.INT:
return "int";
case Type.FLOAT:
return "float";
case Type.LONG:
return "long";
case Type.DOUBLE:
return "double";
case Type.ARRAY:
String result = type(type.getElementType());
for (int i = 0; i < type.getDimensions(); ++i) {
result += "[]";
}
return result;
default:
result = type.getClassName();
if (result.startsWith("java.lang.")) {
return result.substring("java.lang.".length());
}
return result;
}
}
public static Class getClass(Type type, ClassLoader cl) throws Exception {
switch (type.getSort()) {
case Type.BOOLEAN:
return Boolean.TYPE;
case Type.CHAR:
return Character.TYPE;
case Type.BYTE:
return Byte.TYPE;
case Type.SHORT:
return Short.TYPE;
case Type.INT:
return Integer.TYPE;
case Type.FLOAT:
return Float.TYPE;
case Type.LONG:
return Long.TYPE;
case Type.DOUBLE:
return Double.TYPE;
default:
return Class.forName(type.getClassName(), false, cl);
}
}
public static String getClassName(Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
return "Boolean.TYPE";
case Type.CHAR:
return "Character.TYPE";
case Type.BYTE:
return "Byte.TYPE";
case Type.SHORT:
return "Short.TYPE";
case Type.INT:
return "Integer.TYPE";
case Type.FLOAT:
return "Float.TYPE";
case Type.LONG:
return "Long.TYPE";
case Type.DOUBLE:
return "Double.TYPE";
case Type.ARRAY:
StringBuffer result = new StringBuffer(type(type.getElementType()));
for (int i = 0; i < type.getDimensions(); ++i) {
result.append("[]");
}
return result.append(".class").toString();
default:
return type.getClassName() + ".class";
}
}
}