package net.minidev.asm;
/*
* Copyright 2011 JSON-SMART authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import static org.objectweb.asm.
Opcodes.
CHECKCAST;
import static org.objectweb.asm.
Opcodes.
INVOKESTATIC;
import static org.objectweb.asm.
Opcodes.
INVOKEVIRTUAL;
import java.lang.reflect.
Field;
import java.util.
HashMap;
import org.objectweb.asm.
Label;
import org.objectweb.asm.
MethodVisitor;
import org.objectweb.asm.
Type;
/**
* ASM Utils used to simplify class generation
*
* @author uriel Chemouni
*/
public class
ASMUtil {
/**
* Append the call of proper autoboxing method for the given primitif type.
*/
public static void
autoBoxing(
MethodVisitor mv,
Class<?>
clz) {
autoBoxing(
mv,
Type.
getType(
clz));
}
/**
* Extract all Accessor for the field of the given class.
*
* @param type
* @return all Accessor available
*/
static public
Accessor[]
getAccessors(
Class<?>
type,
FieldFilter filter) {
Class<?>
nextClass =
type;
HashMap<
String,
Accessor>
map = new
HashMap<
String,
Accessor>();
if (
filter == null)
filter =
BasicFiledFilter.
SINGLETON;
while (
nextClass !=
Object.class) {
Field[]
declaredFields =
nextClass.
getDeclaredFields();
for (
Field field :
declaredFields) {
String fn =
field.
getName();
if (
map.
containsKey(
fn))
continue;
Accessor acc = new
Accessor(
nextClass,
field,
filter);
if (!
acc.
isUsable())
continue;
map.
put(
fn,
acc);
}
nextClass =
nextClass.
getSuperclass();
}
return
map.
values().
toArray(new
Accessor[
map.
size()]);
}
/**
* Append the call of proper autoboxing method for the given primitif type.
*/
protected static void
autoBoxing(
MethodVisitor mv,
Type fieldType) {
switch (
fieldType.
getSort()) {
case
Type.
BOOLEAN:
mv.
visitMethodInsn(
INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
break;
case
Type.
BYTE:
mv.
visitMethodInsn(
INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
break;
case
Type.
CHAR:
mv.
visitMethodInsn(
INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
break;
case
Type.
SHORT:
mv.
visitMethodInsn(
INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
break;
case
Type.
INT:
mv.
visitMethodInsn(
INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
break;
case
Type.
FLOAT:
mv.
visitMethodInsn(
INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
break;
case
Type.
LONG:
mv.
visitMethodInsn(
INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
break;
case
Type.
DOUBLE:
mv.
visitMethodInsn(
INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
break;
}
}
/**
* Append the call of proper extract primitive type of an boxed object.
*/
protected static void
autoUnBoxing1(
MethodVisitor mv,
Type fieldType) {
switch (
fieldType.
getSort()) {
case
Type.
BOOLEAN:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Boolean");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
break;
case
Type.
BYTE:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Byte");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
break;
case
Type.
CHAR:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Character");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
break;
case
Type.
SHORT:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Short");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
break;
case
Type.
INT:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Integer");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
break;
case
Type.
FLOAT:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Float");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
break;
case
Type.
LONG:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Long");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
break;
case
Type.
DOUBLE:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Double");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
break;
case
Type.
ARRAY:
mv.
visitTypeInsn(
CHECKCAST,
fieldType.
getInternalName());
break;
default:
mv.
visitTypeInsn(
CHECKCAST,
fieldType.
getInternalName());
}
}
/**
* Append the call of proper extract primitive type of an boxed object. this
* methode use Number interface to unbox object
*/
protected static void
autoUnBoxing2(
MethodVisitor mv,
Type fieldType) {
switch (
fieldType.
getSort()) {
case
Type.
BOOLEAN:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Boolean");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
break;
case
Type.
BYTE:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Number");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Number", "byteValue", "()B");
break;
case
Type.
CHAR:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Character");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
break;
case
Type.
SHORT:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Number");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Number", "shortValue", "()S");
break;
case
Type.
INT:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Number");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
break;
case
Type.
FLOAT:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Number");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Number", "floatValue", "()F");
break;
case
Type.
LONG:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Number");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J");
break;
case
Type.
DOUBLE:
mv.
visitTypeInsn(
CHECKCAST, "java/lang/Number");
mv.
visitMethodInsn(
INVOKEVIRTUAL, "java/lang/Number", "doubleValue", "()D");
break;
case
Type.
ARRAY:
mv.
visitTypeInsn(
CHECKCAST,
fieldType.
getInternalName());
break;
default:
mv.
visitTypeInsn(
CHECKCAST,
fieldType.
getInternalName());
}
}
/**
* return a array of new Label (used for switch/case generation)
*
* @param cnt
* number of label to return
*/
public static
Label[]
newLabels(int
cnt) {
Label[]
r = new
Label[
cnt];
for (int
i = 0;
i <
cnt;
i++)
r[
i] = new
Label();
return
r;
}
public static
String getSetterName(
String key) {
int
len =
key.
length();
char[]
b = new char[
len + 3];
b[0] = 's';
b[1] = 'e';
b[2] = 't';
char
c =
key.
charAt(0);
if (
c >= 'a' &&
c <= 'z')
c += 'A' - 'a';
b[3] =
c;
for (int
i = 1;
i <
len;
i++) {
b[
i + 3] =
key.
charAt(
i);
}
return new
String(
b);
}
public static
String getGetterName(
String key) {
int
len =
key.
length();
char[]
b = new char[
len + 3];
b[0] = 'g';
b[1] = 'e';
b[2] = 't';
char
c =
key.
charAt(0);
if (
c >= 'a' &&
c <= 'z')
c += 'A' - 'a';
b[3] =
c;
for (int
i = 1;
i <
len;
i++) {
b[
i + 3] =
key.
charAt(
i);
}
return new
String(
b);
}
public static
String getIsName(
String key) {
int
len =
key.
length();
char[]
b = new char[
len + 2];
b[0] = 'i';
b[1] = 's';
char
c =
key.
charAt(0);
if (
c >= 'a' &&
c <= 'z')
c += 'A' - 'a';
b[2] =
c;
for (int
i = 1;
i <
len;
i++) {
b[
i + 2] =
key.
charAt(
i);
}
return new
String(
b);
}
}