您的位置:首页 > 编程语言 > Java开发

java分布式环境下,反序列化遇到类型擦除问题,解决思路

2017-04-27 20:41 567 查看

前言

公司使用springcloud搭建了一个分布式框架。但是在框架之间调用的时候,如果返回结果的真实类型涉及到泛型,就会遇到类型擦除的问题。这个问题的解决方案是,框架中数据传输时候序列化和反序列化的时候,需要获取数据的真实类型,来进行反序列化。

序列化的方案

1. 使用java的IO进行序列化和反序列化
2.使用json来进行序列化和反序列化
3.使用hessian来进行序列化和反序列化
4.使用dubbo协议来进行序列化和反序列化
虽然有很多序列化和反序列化方案,但是想要写出能够解决泛型擦除问题的代码还是非常困难的。

代码

翻阅大量资料之后,终于在dubbo框架的dubbo-common源码中找到了具体实现。
代码可以参考dubbo-common包,该jar包是阿里的dubbo框架的common,里面有上述所有方案的具体实现。
这里仅仅展示FastJson的实现
FastJsonSerialization.java

/*
* Copyright 1999-2011 Alibaba Group.
*
* 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.
*/
package com.alibaba.dubbo.common.serialize.support.json;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.serialize.ObjectInput;
import com.alibaba.dubbo.common.serialize.ObjectOutput;
import com.alibaba.dubbo.common.serialize.Serialization;

/**
* FastJsonSerialization
*
* @author william.liangf
*/
public class FastJsonSerialization implements Serialization {

public byte getContentTypeId() {
return 6;
}

public String getContentType() {
return "text/json";
}

public ObjectOutput serialize(URL url, OutputStream output) throws IOException {
return new FastJsonObjectOutput(output);
}

public ObjectInput deserialize(URL url, InputStream input) throws IOException {
return new FastJsonObjectInput(input);
}

}


FastJsonObjectOutput.java
/*
* Copyright 1999-2011 Alibaba Group.
*
* 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.
*/
package com.alibaba.dubbo.common.serialize.support.json;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;

import com.alibaba.dubbo.common.serialize.ObjectOutput;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.SerializeWriter;
import com.alibaba.fastjson.serializer.SerializerFeature;

/**
* JsonObjectOutput
*
* @author william.liangf
*/
public class FastJsonObjectOutput implements ObjectOutput {

private final PrintWriter writer;

public FastJsonObjectOutput(OutputStream out) {
this(new OutputStreamWriter(out));
}

public FastJsonObjectOutput(Writer writer) {
this.writer = new PrintWriter(writer);
}

public void writeBool(boolean v) throws IOException {
writeObject(v);
}

public void writeByte(byte v) throws IOException {
writeObject(v);
}

public void writeShort(short v) throws IOException {
writeObject(v);
}

public void writeInt(int v) throws IOException {
writeObject(v);
}

public void writeLong(long v) throws IOExc
19cad
eption {
writeObject(v);
}

public void writeFloat(float v) throws IOException {
writeObject(v);
}

public void writeDouble(double v) throws IOException {
writeObject(v);
}

public void writeUTF(String v) throws IOException {
writeObject(v);
}

public void writeBytes(byte[] b) throws IOException {
writer.println(new String(b));
}

public void writeBytes(byte[] b, int off, int len) throws IOException {
writer.println(new String(b, off, len));
}

public void writeObject(Object obj) throws IOException {
SerializeWriter out = new SerializeWriter();
JSONSerializer serializer = new JSONSerializer(out);
serializer.config(SerializerFeature.WriteEnumUsingToString, true);
serializer.write(obj);
out.writeTo(writer);
writer.println();
writer.flush();
}

public void flushBuffer() throws IOException {
writer.flush();
}

}
FastJsonObjectInput.java
/*
* Copyright 1999-2011 Alibaba Group.
*
* 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.
*/
package com.alibaba.dubbo.common.serialize.support.json;

import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;

import com.alibaba.dubbo.common.serialize.ObjectInput;
import com.alibaba.dubbo.common.utils.PojoUtils;
import com.alibaba.fastjson.JSON;

/**
* JsonObjectInput
*
* @author william.liangf
*/
public class FastJsonObjectInput implements ObjectInput {

private final BufferedReader reader;

public FastJsonObjectInput(InputStream in){
this(new InputStreamReader(in));
}

public FastJsonObjectInput(Reader reader){
this.reader = new BufferedReader(reader);
}

public boolean readBool() throws IOException {
try {
return readObject(boolean.class);
} catch (ClassNotFoundException e) {
throw new IOException(e.getMessage());
}
}

public byte readByte() throws IOException {
try {
return readObject( byte.class);
} catch (ClassNotFoundException e) {
throw new IOException(e.getMessage());
}
}

public short readShort() throws IOException {
try {
return readObject(short.class);
} catch (ClassNotFoundException e) {
throw new IOException(e.getMessage());
}
}

public int readInt() throws IOException {
try {
return readObject(int.class);
} catch (ClassNotFoundException e) {
throw new IOException(e.getMessage());
}
}

public long readLong() throws IOException {
try {
return readObject(long.class);
} catch (ClassNotFoundException e) {
throw new IOException(e.getMessage());
}
}

public float readFloat() throws IOException {
try {
return readObject(float.class);
} catch (ClassNotFoundException e) {
throw new IOException(e.getMessage());
}
}

public double readDouble() throws IOException {
try {
return readObject(double.class);
} catch (ClassNotFoundException e) {
throw new IOException(e.getMessage());
}
}

public String readUTF() throws IOException {
try {
return readObject(String.class);
} catch (ClassNotFoundException e) {
throw new IOException(e.getMessage());
}
}

public byte[] readBytes() throws IOException {
return readLine().getBytes();
}

public Object readObject() throws IOException, ClassNotFoundException {
String json = readLine();
return JSON.parse(json);
}

public <T> T readObject(Class<T> cls) throws IOException, ClassNotFoundException {
String json = readLine();
return JSON.parseObject(json, cls);
}

@SuppressWarnings("unchecked")
public <T> T readObject(Class<T> cls, Type type) throws IOException,ClassNotFoundException
{
Object value = readObject(cls);
return (T) PojoUtils.realize(value, cls, type);
}

private String readLine() throws IOException, EOFException {
String line = reader.readLine();
if(line == null || line.trim().length() == 0) throw new EOFException();
return line;
}

}
PojoUtils.java

/*
* Copyright 1999-2011 Alibaba Group.
*
* 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.
*/
package com.alibaba.dubbo.common.utils;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;

/**
* PojoUtils. Travel object deeply, and convert complex type to simple type.
* <p>
* Simple type below will be remained:
* <ul>
* <li> Primitive Type, also include <b>String</b>, <b>Number</b>(Integer, Long), <b>Date</b>
* <li> Array of Primitive Type
* <li> Collection, eg: List, Map, Set etc.
* </ul>
* <p>
* Other type will be covert to a map which contains the attributes and value pair of object.
*
* @author william.liangf
* @author ding.lid
*/
public class PojoUtils {

private static final ConcurrentMap<String, Method>  NAME_METHODS_CACHE = new ConcurrentHashMap<String, Method>();
private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Field>> CLASS_FIELD_CACHE =
new ConcurrentHashMap<Class<?>, ConcurrentMap<String, Field>>();

public static Object[] generalize(Object[] objs) {
Object[] dests = new Object[objs.length];
for (int i = 0; i < objs.length; i ++) {
dests[i] = generalize(objs[i]);
}
return dests;
}

public static Object[] realize(Object[] objs, Class<?>[] types) {
if (objs.length != types.length)
throw new IllegalArgumentException("args.length != types.length");
Object[] dests = new Object[objs.length];
for (int i = 0; i < objs.length; i ++) {
dests[i] = realize(objs[i], types[i]);
}
return dests;
}

public static Object[] realize(Object[] objs, Class<?>[] types, Type[] gtypes) {
if (objs.length != types.length
|| objs.length != gtypes.length)
throw new IllegalArgumentException("args.length != types.length");
Object[] dests = new Object[objs.length];
for (int i = 0; i < objs.length; i ++) {
dests[i] = realize(objs[i], types[i], gtypes[i]);
}
return dests;
}

public static Object generalize(Object pojo) {
return generalize(pojo, new IdentityHashMap<Object, Object>());
}

@SuppressWarnings("unchecked")
private static Object generalize(Object pojo, Map<Object, Object> history) {
if (pojo == null) {
return null;
}

if (pojo instanceof Enum<?>) {
return ((Enum<?>)pojo).name();
}
if (pojo.getClass().isArray()
&& Enum.class.isAssignableFrom(
pojo.getClass().getComponentType())) {
int len = Array.getLength(pojo);
String[] values = new String[len];
for (int i = 0; i < len; i ++) {
values[i] = ((Enum<?>)Array.get(pojo, i)).name();
}
return values;
}

if (ReflectUtils.isPrimitives(pojo.getClass())) {
return pojo;
}

if (pojo instanceof Class) {
return ((Class)pojo).getName();
}

Object o = history.get(pojo);
if(o != null){
return o;
}
history.put(pojo, pojo);

if (pojo.getClass().isArray()) {
int len = Array.getLength(pojo);
Object[] dest = new Object[len];
history.put(pojo, dest);
for (int i = 0; i < len; i ++) {
Object obj = Array.get(pojo, i);
dest[i] = generalize(obj, history);
}
return dest;
}
if (pojo instanceof Collection<?>) {
Collection<Object> src = (Collection<Object>)pojo;
int len = src.size();
Collection<Object> dest = (pojo instanceof List<?>) ? new ArrayList<Object>(len) : new HashSet<Object>(len);
history.put(pojo, dest);
for (Object obj : src) {
dest.add(generalize(obj, history));
}
return dest;
}
if (pojo instanceof Map<?, ?>) {
Map<Object, Object> src = (Map<Object, Object>)pojo;
Map<Object, Object> dest= createMap(src);
history.put(pojo, dest);
for (Map.Entry<Object, Object> obj : src.entrySet()) {
dest.put(generalize(obj.getKey(), history), generalize(obj.getValue(), history));
}
return dest;
}
Map<String, Object> map = new HashMap<String, Object>();
history.put(pojo, map);
map.put("class", pojo.getClass().getName());
for (Method method : pojo.getClass().getMethods()) {
if (ReflectUtils.isBeanPropertyReadMethod(method)) {
try {
map.put(ReflectUtils.getPropertyNameFromBeanReadMethod(method),
generalize(method.invoke(pojo), history));
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
// public field
for(Field field : pojo.getClass().getFields()) {
if (ReflectUtils.isPublicInstanceField(field)) {
try {
Object fieldValue = field.get(pojo);
// public filed同时也有get/set方法,如果get/set存取的不是前面那个 public field 该如何处理
if (history.containsKey(pojo)) {
Object pojoGenerilizedValue = history.get(pojo);
if (pojoGenerilizedValue instanceof Map
&& ((Map)pojoGenerilizedValue).containsKey(field.getName())) {
continue;
}
}
if (fieldValue != null) {
map.put(field.getName(), generalize(fieldValue, history));
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
return map;
}

public static Object realize(Object pojo, Class<?> type) {
return realize0(pojo, type, null , new IdentityHashMap<Object, Object>());
}

public static Object realize(Object pojo, Class<?> type, Type genericType) {
return realize0(pojo, type, genericType, new IdentityHashMap<Object, Object>());
}

private static class PojoInvocationHandler implements InvocationHandler {

private Map<Object, Object> map;

public PojoInvocationHandler(Map<Object, Object> map) {
this.map = map;
}

@SuppressWarnings("unchecked")
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(map, args);
}
String methodName = method.getName();
Object value = null;
if (methodName.length() > 3 && methodName.startsWith("get")) {
value = map.get(methodName.substring(3, 4).toLowerCase() + methodName.substring(4));
} else if (methodName.length() > 2 && methodName.startsWith("is")) {
value = map.get(methodName.substring(2, 3).toLowerCase() + methodName.substring(3));
} else {
value = map.get(methodName.substring(0, 1).toLowerCase() + methodName.substring(1));
}
if (value instanceof Map<?,?> && ! Map.class.isAssignableFrom(method.getReturnType())) {
value = realize0((Map<String, Object>) value, method.getReturnType(), null, new IdentityHashMap<Object, Object>());
}
return value;
}
}

@SuppressWarnings("unchecked")
private static Collection<Object> createCollection(Class<?> type, int len) {
if (type.isAssignableFrom(ArrayList.class)) {
return  new ArrayList<Object>(len);
}
if (type.isAssignableFrom(HashSet.class)) {
return new HashSet<Object>(len);
}
if (! type.isInterface() && ! Modifier.isAbstract(type.getModifiers())) {
try {
return (Collection<Object>) type.newInstance();
} catch (Exception e) {
// ignore
}
}
return new ArrayList<Object>();
}

private static Map createMap(Map src) {
Class<? extends Map> cl = src.getClass();
Map result = null;
if (HashMap.class == cl) {
result = new HashMap();
} else if (Hashtable.class == cl) {
result = new Hashtable();
} else if (IdentityHashMap.class == cl) {
result = new IdentityHashMap();
} else if (LinkedHashMap.class == cl) {
result = new LinkedHashMap();
} else if (Properties.class == cl) {
result = new Properties();
} else if (TreeMap.class == cl) {
result = new TreeMap();
} else if (WeakHashMap.class == cl) {
return new WeakHashMap();
} else if (ConcurrentHashMap.class == cl) {
result = new ConcurrentHashMap();
} else if (ConcurrentSkipListMap.class == cl) {
result = new ConcurrentSkipListMap();
} else {
try {
result = cl.newInstance();
} catch (Exception e) { /* ignore */ }

if (result == null) {
try {
Constructor<?> constructor = cl.getConstructor(Map.class);
result = (Map)constructor.newInstance(Collections.EMPTY_MAP);
} catch (Exception e) { /* ignore */ }
}
}

if (result == null) {
result = new HashMap<Object, Object>();
}

return result;
}

@SuppressWarnings({ "unchecked", "rawtypes" })
private static Object realize0(Object pojo, Class<?> type, Type genericType, final Map<Object, Object> history) {
if (pojo == null) {
return null;
}

if (type != null && type.isEnum()
&& pojo.getClass() == String.class) {
return Enum.valueOf((Class<Enum>)type, (String)pojo);
}

if (ReflectUtils.isPrimitives(pojo.getClass())
&& ! (type != null && type.isArray()
&& type.getComponentType().isEnum()
&& pojo.getClass() == String[].class)) {
return CompatibleTypeUtils.compatibleTypeConvert(pojo, type);
}

Object o = history.get(pojo);

if(o != null){
return o;
}

history.put(pojo, pojo);

if (pojo.getClass().isArray()) {
if (Collection.class.isAssignableFrom(type)) {
Class<?> ctype = pojo.getClass().getComponentType();
int len = Array.getLength(pojo);
Collection dest = createCollection(type, len);
history.put(pojo, dest);
for (int i = 0; i < len; i ++) {
Object obj = Array.get(pojo, i);
Object value = realize0(obj, ctype, null, history);
dest.add(value);
}
return dest;
} else {
Class<?> ctype = (type != null && type.isArray() ? type.getComponentType() : pojo.getClass().getComponentType());
int len = Array.getLength(pojo);
Object dest = Array.newInstance(ctype, len);
history.put(pojo, dest);
for (int i = 0; i < len; i ++) {
Object obj = Array.get(pojo, i);
Object value = realize0(obj, ctype, null, history);
Array.set(dest, i, value);
}
return dest;
}
}

if (pojo instanceof Collection<?>) {
if (type.isArray()) {
Class<?> ctype = type.getComponentType();
Collection<Object> src = (Collection<Object>)pojo;
int len = src.size();
Object dest = Array.newInstance(ctype, len);
history.put(pojo, dest);
int i = 0;
for (Object obj : src) {
Object value = realize0(obj, ctype, null, history);
Array.set(dest, i, value);
i ++;
}
return dest;
} else {
Collection<Object> src = (Collection<Object>)pojo;
int len = src.size();
Collection<Object> dest = createCollection(type, len);
history.put(pojo, dest);
for (Object obj : src) {
Type keyType = getGenericClassByIndex(genericType, 0);
Class<?> keyClazz = obj.getClass() ;
if ( keyType instanceof Class){
keyClazz = (Class<?>)keyType;
}
Object value = realize0(obj, keyClazz, keyType, history);
dest.add(value);
}
return dest;
}
}

if (pojo instanceof Map<?, ?> && type != null) {
Object className = ((Map<Object, Object>)pojo).get("class");
if (className instanceof String) {
try {
type = ClassHelper.forName((String)className);
} catch (ClassNotFoundException e) {
// ignore
}
}
Map<Object, Object> map ;
// 返回值类型不是方法签名类型的子集 并且 不是接口类型
if (! type.isInterface()
&& ! type.isAssignableFrom(pojo.getClass())){
try {
map = (Map<Object,Object>)type.newInstance();
} catch (Exception e) {
//ignore error
map = (Map<Object, Object>)pojo;
}
}else {
map = (Map<Object, Object>)pojo;
}

if (Map.class.isAssignableFrom(type) || type == Object.class) {
final Map<Object, Object> result = createMap(map);
history.put(pojo, result);
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Type keyType = getGenericClassByIndex(genericType, 0);
Type valueType = getGenericClassByIndex(genericType, 1);
Class<?> keyClazz;
if ( keyType instanceof Class){
keyClazz = (Class<?>)keyType;
} else {
keyClazz = entry.getKey() == null ? null : entry.getKey().getClass();
}
Class<?> valueClazz;
if ( valueType instanceof Class){
valueClazz = (Class<?>)valueType;
} else {
valueClazz = entry.getValue() == null ? null : entry.getValue().getClass() ;
}

Object key = keyClazz == null ? entry.getKey() : realize0(entry.getKey(), keyClazz, keyType, history);
Object value = valueClazz == null ? entry.getValue() : realize0(entry.getValue(), valueClazz, valueType, history);
result.put(key, value);
}
return result;
} else if (type.isInterface()) {
Object dest = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{type}, new PojoInvocationHandler(map));
history.put(pojo, dest);
return dest;
} else {
Object dest = newInstance(type);
history.put(pojo, dest);
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Object key = entry.getKey();
if (key instanceof String) {
String name = (String) key;
Object value = entry.getValue();
if (value != null) {
Method method = getSetterMethod(dest.getClass(), name, value.getClass());
Field field = getField(dest.getClass(), name);
if (method != null) {
if (! method.isAccessible())
method.setAccessible(true);
Type ptype = method.getGenericParameterTypes()[0];
value = realize0(value, method.getParameterTypes()[0], ptype, history);
try {
method.invoke(dest, value);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to set pojo " + dest.getClass().getSimpleName() + " property " + name
+ " value " + value + "(" + value.getClass() + "), cause: " + e.getMessage(), e);
}
} else if (field != null) {
value = realize0(value, field.getType(), field.getGenericType(), history);
try {
field.set(dest, value);
} catch (IllegalAccessException e) {
throw new RuntimeException(
new StringBuilder(32)
.append("Failed to set filed ")
.append(name)
.append(" of pojo ")
.append(dest.getClass().getName())
.append( " : " )
.append(e.getMessage()).toString(),
e);
}
}
}
}
}
if (dest instanceof Throwable) {
Object message = map.get("message");
if (message instanceof String) {
try {
Field filed = Throwable.class.getDeclaredField("detailMessage");
if(! filed.isAccessible()) {
filed.setAccessible(true);
}
filed.set(dest, (String) message);
} catch (Exception e) {
}
}
}
return dest;
}
}
return pojo;
}

/**
* 获取范型的类型
* @param genericType
* @param index
* @return List<Person>  返回Person.class ,Map<String,Person> index=0 返回String.class index=1 返回Person.class
*/
private static Type getGenericClassByIndex(Type genericType, int index){
Type clazz = null ;
//范型参数转换
if (genericType instanceof ParameterizedType){
ParameterizedType t = (ParameterizedType)genericType;
Type[] types = t.getActualTypeArguments();
clazz = types[index];
}
return clazz;
}

private static Object newInstance(Class<?> cls) {
try {
return cls.newInstance();
} catch (Throwable t) {
try {
Constructor<?>[] constructors = cls.getConstructors();
if (constructors != null && constructors.length == 0) {
throw new RuntimeException("Illegal constructor: " + cls.getName());
}
Constructor<?> constructor = constructors[0];
if (constructor.getParameterTypes().length > 0) {
for (Constructor<?> c : constructors) {
if (c.getParameterTypes().length <
constructor.getParameterTypes().length) {
constructor = c;
if (constructor.getParameterTypes().length == 0) {
break;
}
}
}
}
return constructor.newInstance(new Object[constructor.getParameterTypes().length]);
} catch (InstantiationException e) {
throw new RuntimeException(e.getMessage(), e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}

private static Method getSetterMethod(Class<?> cls, String property, Class<?> valueCls) {
String name = "set" + property.substring(0, 1).toUpperCase() + property.substring(1);
Method method = NAME_METHODS_CACHE.get(cls.getName() + "." + name + "(" +valueCls.getName() + ")");
if(method == null){
try {
method = cls.getMethod(name, valueCls);
} catch (NoSuchMethodException e) {
for (Method m : cls.getMethods()) {
if (ReflectUtils.isBeanPropertyWriteMethod(m)
&& m.getName().equals(name)) {
method = m;
}
}
}
if(method != null){
NAME_METHODS_CACHE.put(cls.getName() + "." + name + "(" +valueCls.getName() + ")", method);
}
}
return method;
}

private static Field getField(Class<?> cls, String fieldName) {
Field result = null;
if (CLASS_FIELD_CACHE.containsKey(cls)
&& CLASS_FIELD_CACHE.get(cls).containsKey(fieldName)) {
return CLASS_FIELD_CACHE.get(cls).get(fieldName);
}
try {
result = cls.getField(fieldName);
} catch (NoSuchFieldException e) {
for(Field field : cls.getFields()) {
if (fieldName.equals(field.getName())
&& ReflectUtils.isPublicInstanceField(field)) {
result = field;
break;
}
}
}
if (result != null) {
ConcurrentMap<String, Field> fields = CLASS_FIELD_CACHE.get(cls);
if (fields == null) {
fields = new ConcurrentHashMap<String, Field>();
CLASS_FIELD_CACHE.putIfAbsent(cls, fields);
}
fields = CLASS_FIELD_CACHE.get(cls);
fields.putIfAbsent(fieldName, result);
}
return result;
}

public static boolean isPojo(Class<?> cls) {
return ! ReflectUtils.isPrimitives(cls)
&& ! Collection.class.isAssignableFrom(cls)
&& ! Map.class.isAssignableFrom(cls);
}

}


CompatibleTypeUtils.java

/*
* Copyright 1999-2011 Alibaba Group.
*
* 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.
*/
package com.alibaba.dubbo.common.utils;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* @author ding.lid
*/
public class CompatibleTypeUtils {

private CompatibleTypeUtils() {
}

private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

/**
* 兼容类型转换。null值是OK的。如果不需要转换,则返回原来的值。
* 进行的兼容类型转换如下:(基本类对应的Wrapper类型不再列出。)
* <ul>
* <li> String -> char, enum, Date
* <li> byte, short, int, long -> byte, short, int, long
* <li> float, double -> float, double
* </ul>
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Object compatibleTypeConvert(Object value, Class<?> type) {
if(value == null || type == null || type.isAssignableFrom(value.getClass())) {
return value;
}
if(value instanceof String) {
String string = (String) value;
if (char.class.equals(type) || Character.class.equals(type)) {
if(string.length() != 1) {
throw new IllegalArgumentException(String.format("CAN NOT convert String(%s) to char!" +
" when convert String to char, the String MUST only 1 char.", string));
}
return string.charAt(0);
} else if(type.isEnum()) {
return Enum.valueOf((Class<Enum>)type, string);
} else if(type == BigInteger.class) {
return new BigInteger(string);
} else if(type == BigDecimal.class) {
return new BigDecimal(string);
} else if(type == Short.class || type == short.class) {
return new Short(string);
} else if(type == Integer.class || type == int.class) {
return new Integer(string);
} else if(type == Long.class || type == long.class) {
return new Long(string);
} else if(type == Double.class || type == double.class) {
return new Double(string);
} else if(type == Float.class || type == float.class) {
return new Float(string);
}  else if(type == Byte.class || type == byte.class) {
return new Byte(string);
} else if(type == Boolean.class || type == boolean.class) {
return new Boolean(string);
} else if(type == Date.class) {
try {
return new SimpleDateFormat(DATE_FORMAT).parse((String) value);
} catch (ParseException e) {
throw new IllegalStateException("Failed to parse date " + value + " by format " + DATE_FORMAT + ", cause: " + e.getMessage(), e);
}
} else if (type == Class.class) {
try {
return ReflectUtils.name2class((String)value);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
} else if(value instanceof Number) {
Number number = (Number) value;
if (type == byte.class || type == Byte.class) {
return number.byteValue();
} else if (type == short.class || type == Short.class) {
return number.shortValue();
} else if (type == int.class || type == Integer.class) {
return number.intValue();
} else if (type == long.class || type == Long.class) {
return number.longValue();
} else if (type == float.class || type == Float.class) {
return number.floatValue();
} else if (type == double.class || type == Double.class) {
return number.doubleValue();
} else if (type == BigInteger.class) {
return BigInteger.valueOf(number.longValue());
} else if (type == BigDecimal.class) {
return BigDecimal.valueOf(number.doubleValue());
} else if (type == Date.class) {
return new Date(number.longValue());
}
} else if(value instanceof Collection) {
Collection collection = (Collection) value;
if (type.isArray()) {
int length = collection.size();
Object array = Array.newInstance(type.getComponentType(), length);
int i = 0;
for (Object item : collection) {
Array.set(array, i ++, item);
}
return array;
} else if (! type.isInterface()) {
try {
Collection result = (Collection) type.newInstance();
result.addAll(collection);
return result;
} catch (Throwable e) {
}
} else if (type == List.class) {
return new ArrayList<Object>(collection);
} else if (type == Set.class) {
return new HashSet<Object>(collection);
}
} else if(value.getClass().isArray() && Collection.class.isAssignableFrom(type)) {
Collection collection;
if (! type.isInterface()) {
try {
collection = (Collection) type.newInstance();
} catch (Throwable e) {
collection = new ArrayList<Object>();
}
} else if (type == Set.class) {
collection = new HashSet<Object>();
} else {
collection = new ArrayList<Object>();
}
int length = Array.getLength(value);
for (int i = 0; i < length; i ++) {
collection.add(Array.get(value, i));
}
return collection;
}
return value;
}
}
ReflectUtils.java
/*
* Copyright 1999-2011 Alibaba Group.
*
* 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.
*/
package com.alibaba.dubbo.common.utils;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import javassist.NotFoundException;

/**
* ReflectUtils
*
* @author qian.lei
*/
public final class ReflectUtils {

/**
* void(V).
*/
public static final char JVM_VOID = 'V';

/**
* boolean(Z).
*/
public static final char JVM_BOOLEAN = 'Z';

/**
* byte(B).
*/
public static final char JVM_BYTE = 'B';

/**
* char(C).
*/
public static final char JVM_CHAR = 'C';

/**
* double(D).
*/
public static final char JVM_DOUBLE = 'D';

/**
* float(F).
*/
public static final char JVM_FLOAT = 'F';

/**
* int(I).
*/
public static final char JVM_INT = 'I';

/**
* long(J).
*/
public static final char JVM_LONG = 'J';

/**
* short(S).
*/
public static final char JVM_SHORT = 'S';

public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];

public static final String JAVA_IDENT_REGEX = "(?:[_$a-zA-Z][_$a-zA-Z0-9]*)";

public static final String JAVA_NAME_REGEX = "(?:" + JAVA_IDENT_REGEX + "(?:\\." + JAVA_IDENT_REGEX + ")*)";

public static final String CLASS_DESC = "(?:L" + JAVA_IDENT_REGEX   + "(?:\\/" + JAVA_IDENT_REGEX + ")*;)";

public static final String ARRAY_DESC  = "(?:\\[+(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "))";

public static final String DESC_REGEX = "(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "|" + ARRAY_DESC + ")";

public static final Pattern DESC_PATTERN = Pattern.compile(DESC_REGEX);

public static final String METHOD_DESC_REGEX = "(?:("+JAVA_IDENT_REGEX+")?\\(("+DESC_REGEX+"*)\\)("+DESC_REGEX+")?)";

public static final Pattern METHOD_DESC_PATTERN = Pattern.compile(METHOD_DESC_REGEX);

public static final Pattern GETTER_METHOD_DESC_PATTERN = Pattern.compile("get([A-Z][_a-zA-Z0-9]*)\\(\\)(" + DESC_REGEX + ")");

public static final Pattern SETTER_METHOD_DESC_PATTERN = Pattern.compile("set([A-Z][_a-zA-Z0-9]*)\\((" + DESC_REGEX + ")\\)V");

public static final Pattern IS_HAS_CAN_METHOD_DESC_PATTERN = Pattern.compile("(?:is|has|can)([A-Z][_a-zA-Z0-9]*)\\(\\)Z");

private static final ConcurrentMap<String, Class<?>>  DESC_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();

private static final ConcurrentMap<String, Class<?>>  NAME_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();

private static final ConcurrentMap<String, Method>  Signature_METHODS_CACHE = new ConcurrentHashMap<String, Method>();

public static boolean isPrimitives(Class<?> cls) {
if (cls.isArray()) {
return isPrimitive(cls.getComponentType());
}
return isPrimitive(cls);
}

public static boolean isPrimitive(Class<?> cls) {
return cls.isPrimitive() || cls == String.class || cls == Boolean.class || cls == Character.class
|| Number.class.isAssignableFrom(cls) || Date.class.isAssignableFrom(cls);
}

public static Class<?> getBoxedClass(Class<?> c) {
if( c == int.class )
c = Integer.class;
else if( c == boolean.class )
c = Boolean.class;
else  if( c == long.class )
c = Long.class;
else if( c == float.class )
c = Float.class;
else if( c == double.class )
c = Double.class;
else if( c == char.class )
c = Character.class;
else if( c == byte.class )
c = Byte.class;
else if( c == short.class )
c = Short.class;
return c;
}

/**
* is compatible.
*
* @param c class.
* @param o instance.
* @return compatible or not.
*/
public static boolean isCompatible(Class<?> c, Object o)
{
boolean pt = c.isPrimitive();
if( o == null )
return !pt;

if( pt )
{
if( c == int.class )
c = Integer.class;
else if( c == boolean.class )
c = Boolean.class;
else  if( c == long.class )
c = Long.class;
else if( c == float.class )
c = Float.class;
else if( c == double.class )
c = Double.class;
else if( c == char.class )
c = Character.class;
else if( c == byte.class )
c = Byte.class;
else if( c == short.class )
c = Short.class;
}
if( c == o.getClass() )
return true;
return c.isInstance(o);
}

/**
* is compatible.
*
* @param cs class array.
* @param os object array.
* @return compatible or not.
*/
public static boolean isCompatible(Class<?>[] cs, Object[] os)
{
int len = cs.length;
if( len != os.length ) return false;
if( len == 0 ) return true;
for(int i=0;i<len;i++)
if( !isCompatible(cs[i], os[i]) ) return false;
return true;
}

public static String getCodeBase(Class<?> cls) {
if (cls == null)
return null;
ProtectionDomain domain = cls.getProtectionDomain();
if (domain == null)
return null;
CodeSource source = domain.getCodeSource();
if (source == null)
return null;
URL location = source.getLocation();
if (location == null)
return null;
return location.getFile();
}

/**
* get name.
* java.lang.Object[][].class => "java.lang.Object[][]"
*
* @param c class.
* @return name.
*/
public static String getName(Class<?> c)
{
if( c.isArray() )
{
StringBuilder sb = new StringBuilder();
do
{
sb.append("[]");
c = c.getComponentType();
}
while( c.isArray() );

return c.getName() + sb.toString();
}
return c.getName();
}

public static Class<?> getGenericClass(Class<?> cls) {
return getGenericClass(cls, 0);
}

public static Class<?> getGenericClass(Class<?> cls, int i) {
try {
ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);
Object genericClass = parameterizedType.getActualTypeArguments()[i];
if (genericClass instanceof ParameterizedType) { // 处理多级泛型
return (Class<?>) ((ParameterizedType) genericClass).getRawType();
} else if (genericClass instanceof GenericArrayType) { // 处理数组泛型
return (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType();
} else if (((Class)genericClass).isArray()) {
// 在 JDK 7 以上的版本, Foo<int[]> 不再是 GenericArrayType
return ((Class)genericClass).getComponentType();
} else {
return (Class<?>) genericClass;
}
} catch (Throwable e) {
throw new IllegalArgumentException(cls.getName()
+ " generic type undefined!", e);
}
}

/**
* get method name.
* "void do(int)", "void do()", "int do(java.lang.String,boolean)"
*
* @param m method.
* @return name.
*/
public static String getName(final Method m)
{
StringBuilder ret = new StringBuilder();
ret.append(getName(m.getReturnType())).append(' ');
ret.append(m.getName()).append('(');
Class<?>[] parameterTypes = m.getParameterTypes();
for(int i=0;i<parameterTypes.length;i++)
{
if( i > 0 )
ret.append(',');
ret.append(getName(parameterTypes[i]));
}
ret.append(')');
return ret.toString();
}

public static String getSignature(String methodName, Class<?>[] parameterTypes) {
StringBuilder sb = new StringBuilder(methodName);
sb.append("(");
if (parameterTypes != null && parameterTypes.length > 0) {
boolean first = true;
for (Class<?> type : parameterTypes) {
if (first) {
first = false;
} else {
sb.append(",");
}
sb.append(type.getName());
}
}
sb.append(")");
return sb.toString();
}

/**
* get constructor name.
* "()", "(java.lang.String,int)"
*
* @param c constructor.
* @return name.
*/
public static String getName(final Constructor<?> c)
{
StringBuilder ret = new StringBuilder("(");
Class<?>[] parameterTypes = c.getParameterTypes();
for(int i=0;i<parameterTypes.length;i++)
{
if( i > 0 )
ret.append(',');
ret.append(getName(parameterTypes[i]));
}
ret.append(')');
return ret.toString();
}

/**
* get class desc.
* boolean[].class => "[Z"
* Object.class => "Ljava/lang/Object;"
*
* @param c class.
* @return desc.
* @throws NotFoundException
*/
public static String getDesc(Class<?> c)
{
StringBuilder ret = new StringBuilder();

while( c.isArray() )
{
ret.append('[');
c = c.getComponentType();
}

if( c.isPrimitive() )
{
String t = c.getName();
if( "void".equals(t) ) ret.append(JVM_VOID);
else if( "boolean".equals(t) ) ret.append(JVM_BOOLEAN);
else if( "byte".equals(t) ) ret.append(JVM_BYTE);
else if( "char".equals(t) ) ret.append(JVM_CHAR);
else if( "double".equals(t) ) ret.append(JVM_DOUBLE);
else if( "float".equals(t) ) ret.append(JVM_FLOAT);
else if( "int".equals(t) ) ret.append(JVM_INT);
else if( "long".equals(t) ) ret.append(JVM_LONG);
else if( "short".equals(t) ) ret.append(JVM_SHORT);
}
else
{
ret.append('L');
ret.append(c.getName().replace('.', '/'));
ret.append(';');
}
return ret.toString();
}

/**
* get class array desc.
* [int.class, boolean[].class, Object.class] => "I[ZLjava/lang/Object;"
*
* @param cs class array.
* @return desc.
* @throws NotFoundException
*/
public static String getDesc(final Class<?>[] cs)
{
if( cs.length == 0 )
return "";

StringBuilder sb = new StringBuilder(64);
for( Class<?> c : cs )
sb.append(getDesc(c));
return sb.toString();
}

/**
* get method desc.
* int do(int arg1) => "do(I)I"
* void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
*
* @param m method.
* @return desc.
*/
public static String getDesc(final Method m)
{
StringBuilder ret = new StringBuilder(m.getName()).append('(');
Class<?>[] parameterTypes = m.getParameterTypes();
for(int i=0;i<parameterTypes.length;i++)
ret.append(getDesc(parameterTypes[i]));
ret.append(')').append(getDesc(m.getReturnType()));
return ret.toString();
}

/**
* get constructor desc.
* "()V", "(Ljava/lang/String;I)V"
*
* @param c constructor.
* @return desc
*/
public static String getDesc(final Constructor<?> c)
{
StringBuilder ret = new StringBuilder("(");
Class<?>[] parameterTypes = c.getParameterTypes();
for(int i=0;i<parameterTypes.length;i++)
ret.append(getDesc(parameterTypes[i]));
ret.append(')').append('V');
return ret.toString();
}

/**
* get method desc.
* "(I)I", "()V", "(Ljava/lang/String;Z)V"
*
* @param m method.
* @return desc.
*/
public static String getDescWithoutMethodName(Method m)
{
StringBuilder ret = new StringBuilder();
ret.append('(');
Class<?>[] parameterTypes = m.getParameterTypes();
for(int i=0;i<parameterTypes.length;i++)
ret.append(getDesc(parameterTypes[i]));
ret.append(')').append(getDesc(m.getReturnType()));
return ret.toString();
}

/**
* get class desc.
* Object.class => "Ljava/lang/Object;"
* boolean[].class => "[Z"
*
* @param c class.
* @return desc.
* @throws NotFoundException
*/
public static String getDesc(final CtClass c) throws NotFoundException
{
StringBuilder ret = new StringBuilder();
if( c.isArray() )
{
ret.append('[');
ret.append(getDesc(c.getComponentType()));
}
else if( c.isPrimitive() )
{
String t = c.getName();
if( "void".equals(t) ) ret.append(JVM_VOID);
else if( "boolean".equals(t) ) ret.append(JVM_BOOLEAN);
else if( "byte".equals(t) ) ret.append(JVM_BYTE);
else if( "char".equals(t) ) ret.append(JVM_CHAR);
else if( "double".equals(t) ) ret.append(JVM_DOUBLE);
else if( "float".equals(t) ) ret.append(JVM_FLOAT);
else if( "int".equals(t) ) ret.append(JVM_INT);
else if( "long".equals(t) ) ret.append(JVM_LONG);
else if( "short".equals(t) ) ret.append(JVM_SHORT);
}
else
{
ret.append('L');
ret.append(c.getName().replace('.','/'));
ret.append(';');
}
return ret.toString();
}

/**
* get method desc.
* "do(I)I", "do()V", "do(Ljava/lang/String;Z)V"
*
* @param m method.
* @return desc.
*/
public static String getDesc(final CtMethod m) throws NotFoundException
{
StringBuilder ret = new StringBuilder(m.getName()).append('(');
CtClass[] parameterTypes = m.getParameterTypes();
for(int i=0;i<parameterTypes.length;i++)
ret.append(getDesc(parameterTypes[i]));
ret.append(')').append(getDesc(m.getReturnType()));
return ret.toString();
}

/**
* get constructor desc.
* "()V", "(Ljava/lang/String;I)V"
*
* @param c constructor.
* @return desc
*/
public static String getDesc(final CtConstructor c) throws NotFoundException
{
StringBuilder ret = new StringBuilder("(");
CtClass[] parameterTypes = c.getParameterTypes();
for(int i=0;i<parameterTypes.length;i++)
ret.append(getDesc(parameterTypes[i]));
ret.append(')').append('V');
return ret.toString();
}

/**
* get method desc.
* "(I)I", "()V", "(Ljava/lang/String;Z)V".
*
* @param m method.
* @return desc.
*/
public static String getDescWithoutMethodName(final CtMethod m) throws NotFoundException
{
StringBuilder ret = new StringBuilder();
ret.append('(');
CtClass[] parameterTypes = m.getParameterTypes();
for(int i=0;i<parameterTypes.length;i++)
ret.append(getDesc(parameterTypes[i]));
ret.append(')').append(getDesc(m.getReturnType()));
return ret.toString();
}

/**
* name to desc.
* java.util.Map[][] => "[[Ljava/util/Map;"
*
* @param name name.
* @return desc.
*/
public static String name2desc(String name)
{
StringBuilder sb = new StringBuilder();
int c = 0,index = name.indexOf('[');
if( index > 0 )
{
c = ( name.length() - index ) / 2;
name = name.substring(0,index);
}
while( c-- > 0 ) sb.append("[");
if( "void".equals(name) ) sb.append(JVM_VOID);
else if( "boolean".equals(name) ) sb.append(JVM_BOOLEAN);
else if( "byte".equals(name) ) sb.append(JVM_BYTE);
else if( "char".equals(name) ) sb.append(JVM_CHAR);
else if( "double".equals(name) ) sb.append(JVM_DOUBLE);
else if( "float".equals(name) ) sb.append(JVM_FLOAT);
else if( "int".equals(name) ) sb.append(JVM_INT);
else if( "long".equals(name) ) sb.append(JVM_LONG);
else if( "short".equals(name) ) sb.append(JVM_SHORT);
else sb.append('L').append(name.replace('.', '/')).append(';');
return sb.toString();
}

/**
* desc to name.
* "[[I" => "int[][]"
*
* @param desc desc.
* @return name.
*/
public static String desc2name(String desc)
{
StringBuilder sb = new StringBuilder();
int c = desc.lastIndexOf('[') + 1;
if( desc.length() == c+1 )
{
switch( desc.charAt(c) )
{
case JVM_VOID: { sb.append("void"); break; }
case JVM_BOOLEAN: { sb.append("boolean"); break; }
case JVM_BYTE: { sb.append("byte"); break; }
case JVM_CHAR: { sb.append("char"); break; }
case JVM_DOUBLE: { sb.append("double"); break; }
case JVM_FLOAT: { sb.append("float"); break; }
case JVM_INT: { sb.append("int"); break; }
case JVM_LONG: { sb.append("long"); break; }
case JVM_SHORT: { sb.append("short"); break; }
default:
throw new RuntimeException();
}
}
else
{
sb.append(desc.substring(c+1, desc.length()-1).replace('/','.'));
}
while( c-- > 0 ) sb.append("[]");
return sb.toString();
}

public static Class<?> forName(String name) {
try {
return name2class(name);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
}
}

/**
* name to class.
* "boolean" => boolean.class
* "java.util.Map[][]" => java.util.Map[][].class
*
* @param name name.
* @return Class instance.
*/
public static Class<?> name2class(String name) throws ClassNotFoundException
{
return name2class(ClassHelper.getClassLoader(), name);
}

/**
* name to class.
* "boolean" => boolean.class
* "java.util.Map[][]" => java.util.Map[][].class
*
* @param cl ClassLoader instance.
* @param name name.
* @return Class instance.
*/
private static Class<?> name2class(ClassLoader cl, String name) throws ClassNotFoundException
{
int c = 0, index = name.indexOf('[');
if( index > 0 )
{
c = ( name.length() - index ) / 2;
name = name.substring(0, index);
}
if( c > 0 )
{
StringBuilder sb = new StringBuilder();
while( c-- > 0 )
sb.append("[");

if( "void".equals(name) ) sb.append(JVM_VOID);
else if( "boolean".equals(name) ) sb.append(JVM_BOOLEAN);
else if( "byte".equals(name) ) sb.append(JVM_BYTE);
else if( "char".equals(name) ) sb.append(JVM_CHAR);
else if( "double".equals(name) ) sb.append(JVM_DOUBLE);
else if( "float".equals(name) ) sb.append(JVM_FLOAT);
else if( "int".equals(name) ) sb.append(JVM_INT);
else if( "long".equals(name) ) sb.append(JVM_LONG);
else if( "short".equals(name) ) sb.append(JVM_SHORT);
else sb.append('L').append(name).append(';'); // "java.lang.Object" ==> "Ljava.lang.Object;"
name = sb.toString();
}
else
{
if( "void".equals(name) ) return void.class;
else if( "boolean".equals(name) ) return boolean.class;
else if( "byte".equals(name) ) return byte.class;
else if( "char".equals(name) ) return char.class;
else if( "double".equals(name) ) return double.class;
else if( "float".equals(name) ) return float.class;
else if( "int".equals(name) ) return int.class;
else if( "long".equals(name) ) return long.class;
else if( "short".equals(name) ) return short.class;
}

if( cl == null )
cl = ClassHelper.getClassLoader();
Class<?> clazz = NAME_CLASS_CACHE.get(name);
if(clazz == null){
clazz = Class.forName(name, true, cl);
NAME_CLASS_CACHE.put(name, clazz);
}
return clazz;
}

/**
* desc to class.
* "[Z" => boolean[].class
* "[[Ljava/util/Map;" => java.util.Map[][].class
*
* @param desc desc.
* @return Class instance.
* @throws ClassNotFoundException
*/
public static Class<?> desc2class(String desc) throws ClassNotFoundException
{
return desc2class(ClassHelper.getClassLoader(), desc);
}

/**
* desc to class.
* "[Z" => boolean[].class
* "[[Ljava/util/Map;" => java.util.Map[][].class
*
* @param cl ClassLoader instance.
* @param desc desc.
* @return Class instance.
* @throws ClassNotFoundException
*/
private static Class<?> desc2class(ClassLoader cl, String desc) throws ClassNotFoundException
{
switch( desc.charAt(0) )
{
case JVM_VOID: return void.class;
case JVM_BOOLEAN: return boolean.class;
case JVM_BYTE: return byte.class;
case JVM_CHAR: return char.class;
case JVM_DOUBLE: return double.class;
case JVM_FLOAT: return float.class;
case JVM_INT: return int.class;
case JVM_LONG: return long.class;
case JVM_SHORT: return short.class;
case 'L':
desc = desc.substring(1, desc.length()-1).replace('/', '.'); // "Ljava/lang/Object;" ==> "java.lang.Object"
break;
case '[':
desc = desc.replace('/', '.');  // "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;"
break;
default:
throw new ClassNotFoundException("Class not found: " + desc);
}

if( cl == null )
cl = ClassHelper.getClassLoader();
Class<?> clazz = DESC_CLASS_CACHE.get(desc);
if(clazz==null){
clazz = Class.forName(desc, true, cl);
DESC_CLASS_CACHE.put(desc, clazz);
}
return clazz;
}

/**
* get class array instance.
*
* @param desc desc.
* @return Class class array.
* @throws ClassNotFoundException
*/
public static Class<?>[] desc2classArray(String desc) throws ClassNotFoundException
{
Class<?>[] ret = desc2classArray(ClassHelper.getClassLoader(), desc);
return ret;
}

/**
* get class array instance.
*
* @param cl ClassLoader instance.
* @param desc desc.
* @return Class[] class array.
* @throws ClassNotFoundException
*/
private static Class<?>[] desc2classArray(ClassLoader cl, String desc) throws ClassNotFoundException
{
if( desc.length() == 0 )
return EMPTY_CLASS_ARRAY;

List<Class<?>> cs = new ArrayList<Class<?>>();
Matcher m = DESC_PATTERN.matcher(desc);
while(m.find())
cs.add(desc2class(cl, m.group()));
return cs.toArray(EMPTY_CLASS_ARRAY);
}

/**
* 根据方法签名从类中找出方法。
*
* @param clazz 查找的类。
* @param methodName 方法签名,形如method1(int, String)。也允许只给方法名不参数只有方法名,形如method2。
* @return 返回查找到的方法。
* @throws NoSuchMethodException
* @throws ClassNotFoundException
* @throws IllegalStateException 给定的方法签名找到多个方法(方法签名中没有指定参数,又有有重载的方法的情况)
*/
public static Method findMethodByMethodSignature(Class<?> clazz, String methodName, String[] parameterTypes)
throws NoSuchMethodException, ClassNotFoundException {
String signature = clazz.getName() + "." + methodName;
if(parameterTypes != null && parameterTypes.length > 0){
signature += StringUtils.join(parameterTypes);
}
Method method = Signature_METHODS_CACHE.get(signature);
if(method != null){
return method;
}
if (parameterTypes == null) {
List<Method> finded = new ArrayList<Method>();
for (Method m : clazz.getMethods()) {
if (m.getName().equals(methodName)) {
finded.add(m);
}
}
if (finded.isEmpty()) {
throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz);
}
if(finded.size() > 1) {
String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.",
methodName, clazz.getName(), finded.size());
throw new IllegalStateException(msg);
}
method = finded.get(0);
} else {
Class<?>[] types = new Class<?>[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i ++) {
types[i] = ReflectUtils.name2class(parameterTypes[i]);
}
method = clazz.getMethod(methodName, types);

}
Signature_METHODS_CACHE.put(signature, method);
return method;
}

public static Method findMethodByMethodName(Class<?> clazz, String methodName)
throws NoSuchMethodException, ClassNotFoundException {
return findMethodByMethodSignature(clazz, methodName, null);
}

public static Constructor<?> findConstructor(Class<?> clazz, Class<?> paramType) throws NoSuchMethodException {
Constructor<?> targetConstructor;
try {
targetConstructor = clazz.getConstructor(new Class<?>[] {paramType});
} catch (NoSuchMethodException e) {
targetConstructor = null;
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
if (Modifier.isPublic(constructor.getModifiers())
&& constructor.getParameterTypes().length == 1
&& constructor.getParameterTypes()[0].isAssignableFrom(paramType)) {
targetConstructor = constructor;
break;
}
}
if (targetConstructor == null) {
throw e;
}
}
return targetConstructor;
}

/**
* 检查对象是否是指定接口的实现。
* <p>
* 不会触发到指定接口的{@link Class},所以如果ClassLoader中没有指定接口类时,也不会出错。
*
* @param obj 要检查的对象
* @param interfaceClazzName 指定的接口名
* @return 返回{@code true},如果对象实现了指定接口;否则返回{@code false}。
*/
public static boolean isInstance(Object obj, String interfaceClazzName) {
for (Class<?> clazz = obj.getClass();
clazz != null && !clazz.equals(Object.class);
clazz = clazz.getSuperclass()) {
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> itf : interfaces) {
if (itf.getName().equals(interfaceClazzName)) {
return true;
}
}
}
return false;
}

public static Object getEmptyObject(Class<?> returnType) {
return getEmptyObject(returnType, new HashMap<Class<?>, Object>(), 0);
}

private static Object getEmptyObject(Class<?> returnType, Map<Class<?>, Object> emptyInstances, int level) {
if (level > 2)
return null;
if (returnType == null) {
return null;
} else if (returnType == boolean.class || returnType == Boolean.class) {
return false;
} else if (returnType == char.class || returnType == Character.class) {
return '\0';
} else if (returnType == byte.class || returnType == Byte.class) {
return (byte)0;
} else if (returnType == short.class || returnType == Short.class) {
return (short)0;
} else if (returnType == int.class || returnType == Integer.class) {
return 0;
} else if (returnType == long.class || returnType == Long.class) {
return 0L;
} else if (returnType == float.class || returnType == Float.class) {
return 0F;
} else if (returnType == double.class || returnType == Double.class) {
return 0D;
} else if (returnType.isArray()) {
return Array.newInstance(returnType.getComponentType(), 0);
} else if (returnType.isAssignableFrom(ArrayList.class)) {
return new ArrayList<Object>(0);
} else if (returnType.isAssignableFrom(HashSet.class)) {
return new HashSet<Object>(0);
} else if (returnType.isAssignableFrom(HashMap.class)) {
return new HashMap<Object, Object>(0);
} else if (String.class.equals(returnType)) {
return "";
} else if (! returnType.isInterface()) {
try {
Object value = emptyInstances.get(returnType);
if (value == null) {
value = returnType.newInstance();
emptyInstances.put(returnType, value);
}
Class<?> cls = value.getClass();
while (cls != null && cls != Object.class) {
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
Object property = getEmptyObject(field.getType(), emptyInstances, level + 1);
if (property != null) {
try {
if (! field.isAccessible()) {
field.setAccessible(true);
}
field.set(value, property);
} catch (Throwable e) {
}
}
}
cls = cls.getSuperclass();
}
return value;
} catch (Throwable e) {
return null;
}
} else {
return null;
}
}

public static boolean isBeanPropertyReadMethod(Method method) {
return method != null
&& Modifier.isPublic(method.getModifiers())
&& ! Modifier.isStatic(method.getModifiers())
&& method.getReturnType() != void.class
&& method.getDeclaringClass() != Object.class
&& method.getParameterTypes().length == 0
&& ((method.getName().startsWith("get") && method.getName().length() > 3)
|| (method.getName().startsWith("is") && method.getName().length() > 2));
}

public static String getPropertyNameFromBeanReadMethod(Method method) {
if (isBeanPropertyReadMethod(method)) {
if (method.getName().startsWith("get")) {
return method.getName().substring(3, 4).toLowerCase()
+ method.getName().substring(4);
}
if (method.getName().startsWith("is")) {
return method.getName().substring(2, 3).toLowerCase()
+ method.getName().substring(3);
}
}
return null;
}

public static boolean isBeanPropertyWriteMethod(Method method) {
return method != null
&& Modifier.isPublic(method.getModifiers())
&& ! Modifier.isStatic(method.getModifiers())
&& method.getDeclaringClass() != Object.class
&& method.getParameterTypes().length == 1
&& method.getName().startsWith("set")
&& method.getName().length() > 3;
}

public static String getPropertyNameFromBeanWriteMethod(Method method) {
if (isBeanPropertyWriteMethod(method)) {
return method.getName().substring(3, 4).toLowerCase()
+ method.getName().substring(4);
}
return null;
}

public static boolean isPublicInstanceField(Field field) {
return Modifier.isPublic(field.getModifiers())
&& !Modifier.isStatic(field.getModifiers())
&& !Modifier.isFinal(field.getModifiers())
&& !field.isSynthetic();
}

public static Map<String, Field> getBeanPropertyFields(Class cl) {
Map<String, Field> properties = new HashMap<String, Field>();
for(; cl != null; cl = cl.getSuperclass()) {
Field[] fields = cl.getDeclaredFields();
for(Field field : fields) {
if (Modifier.isTransient(field.getModifiers())
|| Modifier.isStatic(field.getModifiers())) {
continue;
}

field.setAccessible(true);

properties.put(field.getName(), field);
}
}

return properties;
}

public static Map<String, Method> getBeanPropertyReadMethods(Class cl) {
Map<String, Method> properties = new HashMap<String, Method>();
for(; cl != null; cl = cl.getSuperclass()) {
Method[] methods = cl.getDeclaredMethods();
for(Method method : methods) {
if (isBeanPropertyReadMethod(method)) {
method.setAccessible(true);
String property = getPropertyNameFromBeanReadMethod(method);
properties.put(property, method);
}
}
}

return properties;
}

private ReflectUtils(){}
}


OK,大功告成。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: